Secciones de la página

Benford. Test


Árbol de ficheros


Declaraciones


Inclusiones


Constantes


Funciones de nombre corto


Funciones: Comunes a todos los experimentos


Funciones: Para cada experimento


Pruebas


Finalización


Time oriented language

Funciones

Text F()

Real BenFstDig()

Set BenEval()

Set BenView()

Real BenOpeSecRnd()

Real BenOpeTreRnd()

Tol

Artículos del sitio

Presentación de Tol

Todos los programas

Simuladores visuales

Sitios que me gustan

Por categorías

Algoritmia

Búsqueda y ordenación

Computación fisiológica

Editorial y edición

Gráficos de datos

Herramientas y utilidades

Hipertexto

Informática forense

Lectura óptica de datos

Metaprogramación

No determinista

Ofimática

Recursión e iteración

Reglas y restricciones

Series y estadística









make.tol de Benford.Test

Este programa realiza diversos experimentos sobre el cumplimiento de la Ley de Benford en direrentes areas. Benford.Test consiste en una serie de pruebas que se realizan una tras otra, dependiento de su primera funcion If() de control y contiene algoritmos recursivos para la creacion de secuencias de operaciones basicas y aleatorias. La ley de Benford, tambien conocida como ley del primer digito, enuncia que, en los numeros de la vida real, el primer digito mas frecuente es el 1, luego el 2, luego el 3, ..., luego el 8 y finalmente el menos frecuente es el 9. Esta Ley de Benford parece comprobarse tanto en hechos relacionados con el mundo natural o con el social, por ejemplo, la longitud de rios, los totales de facturas, los precios de acciones, el numero de habitantes de las poblaciones, las distancias estelares, en las cifras resultantes de la realizacion de calculos con otras cifras, etc.

Antes que Frank Benford, Simon Newcomb, astronomo y matematico, en 1881 observo que las primeras paginas de las tablas de logaritmos estaban mas usadas que las finales, de lo que dedujo que los digitos iniciales de los numeros no son equiprobables sino que el 1 era el digito inicial mas frecuente, luego 2 y asi hasta el 9 que es el menos frecuente y establecio una primera aproximacion a la funcion de distribucion de esta probabilidad. Frank Benford, fisico, en 1938 establecio esta funcion de distribucion con mas precision y la comprobo en diferentes dominios. La ley de Benford establece que la primera cifra no nula n (n = 1, 2, 3, 4, ..., 9) ocurre con una probabilidad igual a (Log10(n + 1) - Log10(n)).

Ademas de otros experimentos, se dispone de un banco de 2000 datos que corresponden al acumulado del trafico de subida mas el trafico de bajada en bytes para un periodo de dias para un conjunto de 2000 direcciones MAC, Media Access Control address. La hipotesis es que este banco de 2000 datos esta manipulado y no corresponde a la realidad del trafico. Puede plantearse el siguiente experimento, seleccionar varios bancos de 2000 datos reales de trafico por MAC y para un periodo, registrados en una condiciones muy similares a las del banco de datos del que se sospecha y aplicar a estos bancos de prueba y al banco sospechoso la Ley de Benford. Se pueden establecer los 3 posibles resultados siguientes: a) Si ninguno de los bancos sigue la Ley de Benford, entonces podria concluirse que el trafico por MAC no sigue esta ley y no podria concluirse nada sobre el banco sospechoso con este experimento. b) Si todos los bancos siguen la Ley de Benford, entonces podria concluirse que el trafico por MAC si sigue esta ley y tampoco podria concluirse nada sobre el banco sospechoso con este experimento, pudiera ser autentico o falseado de tal forma que cumpliera la Ley de Benford. c) Si todos los bancos de prueba siguen la Ley de Benford pero el sospecho no la sigue entonces se podria concluir que el banco de datos de trafico por MAC efectivamente ha sido manipulado o generado de alguna forma para ser aportado como una prueba digital falsa y que no corresponde a la realidad. Cientificamente el experimento hay que hacerlo con varios bancos de trafico real. En este caso, por simplicidad, se ha seleccionado solo 1 banco de 2000 datos de trafico por MAC captados de la realidad, trafico de subida mas trafico de bajada. La conclusion puede deducirse claramente al final de este programa y existiran otras formas de analisis, pero el objetivo de este programa es realizarlo con la Ley de Benford.

Árbol de ficheros

Benford.Test pruebas de la Ley de Bendford con diferentes casos y uno forense

  • make.tol proceso de prueba de la Ley de Bendford con un caso forense
  • make.bat mandato de ejecucion del programa de test de la Ley Benford
  • trafico directorio con datos de trafico como pruebas digitales forenses
    • bytespermac.tol 2 muestras de trafico de telecomunicacion acumulado en bytes
  • startlog.txt fichero de log de un proceso completo de prueba de Bendord
  • casoforense_html resultado analizar con la Ley de Benford del trafico en bytes
  • benford_test.pdf documento de funciones del test de la Ley de Benford

Declaraciones

Inclusiones

  • Set datInc
    Inclusion de 2 muestras de trafico en bytes.

Constantes

  • Text makSep
    Separador de trazas de ejecucion.
  • Set OpeBas
    Conjunto con las 4 operaciones basicas +, -, * y /.
  • Set BenDig
    Digitos del 1 al 9.
  • Set BenLaw
    Probabilidad del 1,2,...9 segun la Ley de Benford.
  • Text BenFmt
    Formato general para sacar los resultados.

Funciones de nombre corto

  • Text F(Real numDat)
    Retorna un numero como texto con 4 decimales, si es entero sin decimales. Es una version reducida para este programa de la funcion F() mas usual.

Funciones: Comunes a todos los experimentos

  • Real BenFstDig(Real numDat)
    Retorna el primer digito, de 1 a 9, de un numero.
  • Set BenEval(Real numCic, Code funCod)
    Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado de haber evaluado la funcion funCod numCic veces.
  • Set BenView(Text expTit, Real numCic, Code funCod)
    Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado de haber evaluado la funcion funCod numCic veces y, como efecto lateral, a) visualiza por pantalla la comparativa del resultado con la Ley de Benford y b) el error.

Funciones: Para cada experimento

  • Real BenOpeSecRnd(Real numUno, Real numDos, Real numOpe)
    Retorna el resultado de realizar a partir de 2 numeros de entrada, numUno y numDos, una secuencia de numOpe operaciones de suma, resta, multiplicacion y division aleatorias y equiprobables. La secuencia se realiza como una recursion lineal.
  • Real BenOpeTreRnd(Real ranMin, Real ranMax, Real numOpe)
    Retorna el resultado de realizar a partir de 1 rango de entrada, determinado por ranMin y ranMax, una secuencia de numOpe operaciones de suma, resta, multiplicacion y division aleatorias y equiprobables. La construccion se realiza por la expansion de un arbol binario con tantos nodos de operacion como determine numOpe.

Pruebas

  • Set tst001
    Numeros aleatorios frente a operaciones aleatorias.
  • Set tst002
    Comparar nº de ciclos contra nº de operaciones.
  • Set tst003
    Compararcion de la generacion en secuencia de operaciones, en arbol binario de operaciones y la exponencial de numeros aleatorios.
  • Set tstFor
    Analiza el caso de informatica forense.

Inclusiones

Set datInc

//////////////////////////////////////////////////////////////////////////////
Set  datInc = Include("trafico/bytespermac.tol");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Inclusion de 2 muestras de trafico en bytes.", datInc);
//////////////////////////////////////////////////////////////////////////////

Constantes

Text makSep

//////////////////////////////////////////////////////////////////////////////
Text makSep = "\n"+Repeat("_", 72)+"\n";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Separador de trazas de ejecucion.", makSep);
//////////////////////////////////////////////////////////////////////////////

Set OpeBas

//////////////////////////////////////////////////////////////////////////////
Set OpeBas = SetOfText("+", "-", "*", "/");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto con las 4 operaciones basicas +, -, * y /.", OpeBas);
//////////////////////////////////////////////////////////////////////////////

Set BenDig

//////////////////////////////////////////////////////////////////////////////
Set BenDig = SetOfReal(1, 2, 3, 4, 5, 6, 7, 8, 9);
//////////////////////////////////////////////////////////////////////////////
PutDescription("Digitos del 1 al 9.", BenDig);
//////////////////////////////////////////////////////////////////////////////

Set BenLaw

//////////////////////////////////////////////////////////////////////////////
Set BenLaw = EvalSet(BenDig, Real (Real fstDig)
                     { Log10(fstDig+1) - Log10(fstDig) });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Probabilidad del 1,2,...9 segun la Ley de Benford.", BenDig);
//////////////////////////////////////////////////////////////////////////////

Text BenFmt

//////////////////////////////////////////////////////////////////////////////
Text BenFmt = "%.5lf";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Formato general para sacar los resultados.", BenFmt);
//////////////////////////////////////////////////////////////////////////////

Funciones de nombre corto

Text F()

//////////////////////////////////////////////////////////////////////////////
Text F(Real numDat) // Numero de entrada
//////////////////////////////////////////////////////////////////////////////
{
  Case(
    numDat <: BenDig,          FormatReal(numDat, "%1.0lf"), // Un solo digito
    EQ(numDat, Round(numDat)), FormatReal(numDat, "%7.0lf"), // Un entero
    TRUE,                      FormatReal(numDat, BenFmt))   // Con decimales
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un numero como texto con 4 decimales, si es entero sin decimales.
Es una version reducida para este programa de la funcion F() mas usual.",
F);
//////////////////////////////////////////////////////////////////////////////

Funciones: Comunes a todos los experimentos

Real BenFstDig()

//////////////////////////////////////////////////////////////////////////////
Real BenFstDig(Real numDat) // Un numero
//////////////////////////////////////////////////////////////////////////////
{
  Real numAbs = Abs(numDat); // Valor Absoluto
  Floor(numAbs / (10^Floor(Log10(numAbs))))
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el primer digito, de 1 a 9, de un numero.",
BenFstDig);
//////////////////////////////////////////////////////////////////////////////

Set BenEval()

//////////////////////////////////////////////////////////////////////////////
Set BenEval(Real numCic, // Numero de veces que se ha de evaluar
            Code funCod) // Funcion que hay que evaluar
//////////////////////////////////////////////////////////////////////////////
{ 
  Set  resSet = For(1, numCic, funCod);  // Evalua funCod numCic veces

  Set  fstSet = EvalSet(resSet, BenFstDig); // Extrae el primer digito

  // Selecciona del 1 al 9, por si la funcion retornara algun error (?).
  Set  fstChk = Select(fstSet, Real(Real fstDig) { fstDig <: BenDig });
  
  // Añadir 1 representante de cada numero para que salgan todos
  Set  fstCat = BenDig << fstChk;
  
  // Clasificar, la de los 1, la de los 2, ..., la de los 9
  Set  fstCla = Classify(fstCat, Real(Real a, Real b) { Compare(a, b) });

  // Ordenar las clases 1º el 1, luego el 2, ..., finalmente el 9
  // con comparar el primer elemento de cada clase basta
  Set  fstSrt = Sort(fstCla, Real(Set a, Set b) { Compare(a[1], b[1]) });

  // Numero de ocurrencias de cada clase, recordar que hay que quitar una
  Set  fstCrd = EvalSet(fstSrt, Real(Set claSet) { Card(claSet)-1 });

  
  Real numTot = SetSum(fstCrd); // Numero total de ejecuciones validas,

  // Si la funcion funCod no ha dado errores tendria que ser igual a numCic
  Real chkTot = If(numTot == numCic, TRUE, // Todo correcto
  {
    Text WriteLn("De "+F(numCic)+" han sido validas "+F(numTot));
    FALSE // Error en alguna
  });

  // Calculo de la frecuencia  
  Set  fstFrq = EvalSet(fstCrd, Real(Real digCrd) { digCrd / numTot })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado
de haber evaluado la funcion funCod numCic veces.",
BenEval);
//////////////////////////////////////////////////////////////////////////////

Set BenView()

//////////////////////////////////////////////////////////////////////////////
Set BenView(Text expTit, // Titulo del experimento
            Real numCic, // Numero de veces que se ha de evaluar
            Code funCod) // Funcion que hay que evaluar
//////////////////////////////////////////////////////////////////////////////
{
  Set  expFrq = BenEval(numCic, funCod); // Evalua funCod numCic veces

  Text tabTit = "D | Benford | "+Compact(F(numCic))+" ciclos de "+expTit;
  Real lenTit = TextLength(tabTit);
  Text linTit = Repeat("_", lenTit);

  Text WriteLn("\n"+linTit+"\n"+tabTit+"\n"+linTit);

  Set  expTab = EvalSet(BenDig, Set(Real fstDig)
  {
    Real benTeo = BenLaw[fstDig]; // Valor teorico
    Real fstFrq = expFrq[fstDig]; // Frecuencia resultante
    Text WriteLn(F(fstDig)+" | "+F(benTeo)+" | "+F(fstFrq));

    Real errQua = ((fstFrq - benTeo) / benTeo) ^ 2; // Calculo del error
    
    [[ fstDig, benTeo, fstFrq, errQua]]
  });
  Text WriteLn(linTit);

  Real benSum = SetSum(BenLaw); // Total de frecuencias de Benford
  Real expSum = SetSum(expFrq); // Total de frecuencias del experimento

  Set  expErr = Traspose(expTab)[4]; // Conjunto de errores
  Real errSum = SetSum(expErr);      // Error del experimento

  Text WriteLn("Sum "+FormatReal(benSum, BenFmt)+" | "+
                      FormatReal(expSum, BenFmt)+" | error "+F(errSum));
//Text WriteLn(linTit);

  Extract(expTab, 1, 2, 3) // Tabla digito, Benford, experimento
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado
de haber evaluado la funcion funCod numCic veces y, como efecto lateral,
a) visualiza por pantalla la comparativa del resultado con la Ley de Benford
y b) el error.",
BenView);
//////////////////////////////////////////////////////////////////////////////

Funciones: Para cada experimento

Real BenOpeSecRnd()

//////////////////////////////////////////////////////////////////////////////
Real BenOpeSecRnd(Real numUno, // Primer numero de entrada
                  Real numDos, // Segundo numero de entrada
                  Real numOpe) // Numero de operaciones a realizar
//////////////////////////////////////////////////////////////////////////////
{
  If(numOpe <= 0, numDos, // No hay ya mas operaciones que hacer
  {
    Real numRnd = Floor(Rand(1, Card(OpeBas)+1)); // Numero aleatorio
    Text opeTxt = OpeBas[numRnd];                 // Operador como texto
    Code opeCod = FindCode("Real", opeTxt);       // Operador Tol de Real
    Real newVal = opeCod(numUno, numDos);         // Realiza la operacion

//  Text WriteLn(F(numUno)+" "+opeTxt+" "+F(numDos)+" = "+F(newVal));

    BenOpeSecRnd(numDos, newVal, numOpe-1)
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el resultado de realizar a partir de 2 numeros de entrada, numUno y
numDos, una secuencia de numOpe operaciones de suma, resta, multiplicacion y
division aleatorias y equiprobables.
La secuencia se realiza como una recursion lineal.",
BenOpeSecRnd);
//////////////////////////////////////////////////////////////////////////////

Real BenOpeTreRnd()

//////////////////////////////////////////////////////////////////////////////
Real BenOpeTreRnd(Real ranMin, // Minimo del rango de aletorios
                  Real ranMax, // Maximo del rango de aletorios
                  Real numOpe) // Numero de operaciones a realizar
//////////////////////////////////////////////////////////////////////////////
{
  Real numRnd = Floor(Rand(1, Card(OpeBas)+1)); // Numero aleatorio
  Text opeTxt = OpeBas[numRnd];                 // Operador como texto
  Code opeCod = FindCode("Real", opeTxt);       // Operador Tol de Real

  If(numOpe <= 1, opeCod(Rand(ranMin, ranMax), 
                         Rand(ranMin, ranMax)), // Operacion final
  {
    Real numLft = Floor(numOpe/2); // La mitad para la izquierda
    Real numRht = numOpe - numLft; // La otra mitad para la derecha

    opeCod(BenOpeTreRnd(ranMin, ranMax, numLft), // Izquierda
           BenOpeTreRnd(ranMin, ranMax, numRht)) // Derecha
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el resultado de realizar a partir de 1 rango de entrada, determinado
por ranMin y ranMax, una secuencia de numOpe operaciones de suma, resta,
multiplicacion y division aleatorias y equiprobables.
La construccion se realiza por la expansion de un arbol binario con tantos
nodos de operacion como determine numOpe.",
BenOpeTreRnd);
//////////////////////////////////////////////////////////////////////////////

Pruebas

Set tst001

//////////////////////////////////////////////////////////////////////////////
Set tst001 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
  Set tstR01 = BenView(
               "numeros aleatorios de distribucion uniforme", 1000,
               Real(Real posCic) { Rand(0,1) });

  Set tstS01 = BenView(
               " 4 operaciones secuenciales basicas + - * /", 1000,
               Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1),  4)})
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Numeros aleatorios frente a operaciones aleatorias.", tst001);
//////////////////////////////////////////////////////////////////////////////

Set tst002

//////////////////////////////////////////////////////////////////////////////
Set tst002 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
  Set tstS02 = BenView(
               "10 operaciones secuenciales basicas + - * /", 2000,
               Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 10)});

  Set tstS04 = BenView(
               " 5 operaciones secuenciales basicas + - * /", 4000,
               Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1),  5)})
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Comparar nº de ciclos contra nº de operaciones.", tst002);
//////////////////////////////////////////////////////////////////////////////

Set tst003

//////////////////////////////////////////////////////////////////////////////
Set tst003 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
  Set tstS03 = BenView(
               " 7 operaciones secuenciales basicas + - * /", 3000,
               Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1),  7)});

  Set tstT03 = BenView(
               " 7 operaciones en arbol basicas + - * /", 3000,
              Real(Real posCic) { BenOpeTreRnd(0, 1, 7)});

  Set tstE03 = BenView(
               "exponencial de numeros aleatorios entre 0 y 1", 3000,
               Real(Real posCic) { Exp(Rand(-10,10)) })
});
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Compararcion de la generacion en secuencia de operaciones, en arbol binario
de operaciones y la exponencial de numeros aleatorios.",
tst003);
//////////////////////////////////////////////////////////////////////////////

Set tstFor

//////////////////////////////////////////////////////////////////////////////
Set tstFor = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
  Set tstD02 = BenView(
               "trafico dudoso, acumulado en bytes", Card(TraDud),
               Real(Real posCic) { TraDud[posCic] });

  Set tstC02 = BenView(
               "trafico controlado, acumulado en bytes", Card(TraChk),
               Real(Real posCic) { TraChk[posCic] })
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Analiza el caso de informatica forense.", tstFor);
//////////////////////////////////////////////////////////////////////////////

Finalización

Text WriteLn("\nBenford.Test make: end");

Time oriented language

//////////////////////////////////////////////////////////////////////////////
// FILE    : make.tol
// AUTHOR  : http://www.asolver.com
// CLASS   : Estadística; Forense; Algoritmia
// VERSION : Tol 1.1.1; Tol 2.0.1 con reservas
// PURPOSE : Este programa realiza diversos experimentos sobre el cumplimiento
// de la Ley de Benford en direrentes areas.
// 
// Benford.Test consiste en una serie de pruebas que se realizan una tras
// otra, dependiento de su primera funcion If() de control y contiene 
// algoritmos recursivos para la creacion de secuencias de operaciones basicas
// y aleatorias.
// 
// La ley de Benford, tambien conocida como ley del primer digito, enuncia
// que, en los numeros de la vida real, el primer digito mas frecuente es
// el 1, luego el 2, luego el 3, ..., luego el 8 y finalmente el menos
// frecuente es el 9.
// 
// Esta Ley de Benford parece comprobarse tanto en hechos relacionados con el
// mundo natural o con el social, por ejemplo, la longitud de rios, los
// totales de facturas, los precios de acciones, el numero de habitantes de
// las poblaciones, las distancias estelares, en las cifras resultantes de la
// realizacion de calculos con otras cifras, etc.
// _
// Antes que Frank Benford, Simon Newcomb, astronomo y matematico, en 1881
// observo que las primeras paginas de las tablas de logaritmos estaban mas
// usadas que las finales, de lo que dedujo que los digitos iniciales de los
// numeros no son equiprobables sino que el 1 era el digito inicial mas
// frecuente, luego 2 y asi hasta el 9 que es el menos frecuente y establecio
// una primera aproximacion a la funcion de distribucion de esta probabilidad.
// 
// Frank Benford, fisico, en 1938 establecio esta funcion de distribucion con
// mas precision y la comprobo en diferentes dominios.
// La ley de Benford establece que la primera cifra no nula n (n = 1, 2, 3, 4,
// ..., 9) ocurre con una probabilidad igual a (Log10(n + 1) - Log10(n)).
// _
// Ademas de otros experimentos, se dispone de un banco de 2000 datos que
// corresponden al acumulado del trafico de subida mas el trafico de bajada en
// bytes para un periodo de dias para un conjunto de 2000 direcciones MAC,
// Media Access Control address.
// 
// La hipotesis es que este banco de 2000 datos esta manipulado y no
// corresponde a la realidad del trafico.
// 
// Puede plantearse el siguiente experimento,
// seleccionar varios bancos de 2000 datos reales de trafico por MAC y para un
// periodo, registrados en una condiciones muy similares a las del banco de
// datos del que se sospecha y aplicar a estos bancos de prueba y al banco
// sospechoso la Ley de Benford.
// 
// Se pueden establecer los 3 posibles resultados siguientes:
// a) Si ninguno de los bancos sigue la Ley de Benford, entonces podria
//    concluirse que el trafico por MAC no sigue esta ley y no podria
//    concluirse nada sobre el banco sospechoso con este experimento.
// b) Si todos los bancos siguen la Ley de Benford, entonces podria concluirse
//    que el trafico por MAC si sigue esta ley y tampoco podria concluirse
//    nada sobre el banco sospechoso con este experimento,
//    pudiera ser autentico o falseado de tal forma que cumpliera la Ley de
//    Benford.
// c) Si todos los bancos de prueba siguen la Ley de Benford pero el sospecho
//    no la sigue entonces se podria concluir que el banco de datos de trafico
//    por MAC efectivamente ha sido manipulado o generado de alguna forma para
//    ser aportado como una prueba digital falsa y que no corresponde a la
//    realidad.
// 
// Cientificamente el experimento hay que hacerlo con varios bancos de trafico
// real.
// En este caso, por simplicidad, se ha seleccionado solo 1 banco de 2000
// datos de trafico por MAC captados de la realidad, trafico de subida mas
// trafico de bajada.
// La conclusion puede deducirse claramente al final de este programa y
// existiran otras formas de analisis, pero el objetivo de este programa es
// realizarlo con la Ley de Benford.
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// INCLUDE
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nBenford.Test make: begin");

//////////////////////////////////////////////////////////////////////////////
Set  datInc = Include("trafico/bytespermac.tol");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Inclusion de 2 muestras de trafico en bytes.", datInc);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// CONSTANTS
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Text makSep = "\n"+Repeat("_", 72)+"\n";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Separador de trazas de ejecucion.", makSep);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set OpeBas = SetOfText("+", "-", "*", "/");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto con las 4 operaciones basicas +, -, * y /.", OpeBas);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set BenDig = SetOfReal(1, 2, 3, 4, 5, 6, 7, 8, 9);
//////////////////////////////////////////////////////////////////////////////
PutDescription("Digitos del 1 al 9.", BenDig);
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set BenLaw = EvalSet(BenDig, Real (Real fstDig)
                     { Log10(fstDig+1) - Log10(fstDig) });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Probabilidad del 1,2,...9 segun la Ley de Benford.", BenDig);
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Text BenFmt = "%.5lf";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Formato general para sacar los resultados.", BenFmt);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// SHORTNAMES
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Text F(Real numDat) // Numero de entrada
//////////////////////////////////////////////////////////////////////////////
{
  Case(
    numDat <: BenDig,          FormatReal(numDat, "%1.0lf"), // Un solo digito
    EQ(numDat, Round(numDat)), FormatReal(numDat, "%7.0lf"), // Un entero
    TRUE,                      FormatReal(numDat, BenFmt))   // Con decimales
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un numero como texto con 4 decimales, si es entero sin decimales.
Es una version reducida para este programa de la funcion F() mas usual.",
F);
//////////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////////
// FUNCTIONS: Comunes a todos los experimentos
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Real BenFstDig(Real numDat) // Un numero
//////////////////////////////////////////////////////////////////////////////
{
  Real numAbs = Abs(numDat); // Valor Absoluto
  Floor(numAbs / (10^Floor(Log10(numAbs))))
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el primer digito, de 1 a 9, de un numero.",
BenFstDig);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set BenEval(Real numCic, // Numero de veces que se ha de evaluar
            Code funCod) // Funcion que hay que evaluar
//////////////////////////////////////////////////////////////////////////////
{ 
  Set  resSet = For(1, numCic, funCod);  // Evalua funCod numCic veces

  Set  fstSet = EvalSet(resSet, BenFstDig); // Extrae el primer digito

  // Selecciona del 1 al 9, por si la funcion retornara algun error (?).
  Set  fstChk = Select(fstSet, Real(Real fstDig) { fstDig <: BenDig });
  
  // Añadir 1 representante de cada numero para que salgan todos
  Set  fstCat = BenDig << fstChk;
  
  // Clasificar, la de los 1, la de los 2, ..., la de los 9
  Set  fstCla = Classify(fstCat, Real(Real a, Real b) { Compare(a, b) });

  // Ordenar las clases 1º el 1, luego el 2, ..., finalmente el 9
  // con comparar el primer elemento de cada clase basta
  Set  fstSrt = Sort(fstCla, Real(Set a, Set b) { Compare(a[1], b[1]) });

  // Numero de ocurrencias de cada clase, recordar que hay que quitar una
  Set  fstCrd = EvalSet(fstSrt, Real(Set claSet) { Card(claSet)-1 });

  
  Real numTot = SetSum(fstCrd); // Numero total de ejecuciones validas,

  // Si la funcion funCod no ha dado errores tendria que ser igual a numCic
  Real chkTot = If(numTot == numCic, TRUE, // Todo correcto
  {
    Text WriteLn("De "+F(numCic)+" han sido validas "+F(numTot));
    FALSE // Error en alguna
  });

  // Calculo de la frecuencia  
  Set  fstFrq = EvalSet(fstCrd, Real(Real digCrd) { digCrd / numTot })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado
de haber evaluado la funcion funCod numCic veces.",
BenEval);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set BenView(Text expTit, // Titulo del experimento
            Real numCic, // Numero de veces que se ha de evaluar
            Code funCod) // Funcion que hay que evaluar
//////////////////////////////////////////////////////////////////////////////
{
  Set  expFrq = BenEval(numCic, funCod); // Evalua funCod numCic veces

  Text tabTit = "D | Benford | "+Compact(F(numCic))+" ciclos de "+expTit;
  Real lenTit = TextLength(tabTit);
  Text linTit = Repeat("_", lenTit);

  Text WriteLn("\n"+linTit+"\n"+tabTit+"\n"+linTit);

  Set  expTab = EvalSet(BenDig, Set(Real fstDig)
  {
    Real benTeo = BenLaw[fstDig]; // Valor teorico
    Real fstFrq = expFrq[fstDig]; // Frecuencia resultante
    Text WriteLn(F(fstDig)+" | "+F(benTeo)+" | "+F(fstFrq));

    Real errQua = ((fstFrq - benTeo) / benTeo) ^ 2; // Calculo del error
    
    [[ fstDig, benTeo, fstFrq, errQua]]
  });
  Text WriteLn(linTit);

  Real benSum = SetSum(BenLaw); // Total de frecuencias de Benford
  Real expSum = SetSum(expFrq); // Total de frecuencias del experimento

  Set  expErr = Traspose(expTab)[4]; // Conjunto de errores
  Real errSum = SetSum(expErr);      // Error del experimento

  Text WriteLn("Sum "+FormatReal(benSum, BenFmt)+" | "+
                      FormatReal(expSum, BenFmt)+" | error "+F(errSum));
//Text WriteLn(linTit);

  Extract(expTab, 1, 2, 3) // Tabla digito, Benford, experimento
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna un conjunto con la frecuencia de los digitos del 1 al 9 resultado
de haber evaluado la funcion funCod numCic veces y, como efecto lateral,
a) visualiza por pantalla la comparativa del resultado con la Ley de Benford
y b) el error.",
BenView);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// FUNCTIONS: Para cada experimento
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Real BenOpeSecRnd(Real numUno, // Primer numero de entrada
                  Real numDos, // Segundo numero de entrada
                  Real numOpe) // Numero de operaciones a realizar
//////////////////////////////////////////////////////////////////////////////
{
  If(numOpe <= 0, numDos, // No hay ya mas operaciones que hacer
  {
    Real numRnd = Floor(Rand(1, Card(OpeBas)+1)); // Numero aleatorio
    Text opeTxt = OpeBas[numRnd];                 // Operador como texto
    Code opeCod = FindCode("Real", opeTxt);       // Operador Tol de Real
    Real newVal = opeCod(numUno, numDos);         // Realiza la operacion

//  Text WriteLn(F(numUno)+" "+opeTxt+" "+F(numDos)+" = "+F(newVal));

    BenOpeSecRnd(numDos, newVal, numOpe-1)
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el resultado de realizar a partir de 2 numeros de entrada, numUno y
numDos, una secuencia de numOpe operaciones de suma, resta, multiplicacion y
division aleatorias y equiprobables.
La secuencia se realiza como una recursion lineal.",
BenOpeSecRnd);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real BenOpeTreRnd(Real ranMin, // Minimo del rango de aletorios
                  Real ranMax, // Maximo del rango de aletorios
                  Real numOpe) // Numero de operaciones a realizar
//////////////////////////////////////////////////////////////////////////////
{
  Real numRnd = Floor(Rand(1, Card(OpeBas)+1)); // Numero aleatorio
  Text opeTxt = OpeBas[numRnd];                 // Operador como texto
  Code opeCod = FindCode("Real", opeTxt);       // Operador Tol de Real

  If(numOpe <= 1, opeCod(Rand(ranMin, ranMax), 
                         Rand(ranMin, ranMax)), // Operacion final
  {
    Real numLft = Floor(numOpe/2); // La mitad para la izquierda
    Real numRht = numOpe - numLft; // La otra mitad para la derecha

    opeCod(BenOpeTreRnd(ranMin, ranMax, numLft), // Izquierda
           BenOpeTreRnd(ranMin, ranMax, numRht)) // Derecha
  })
};
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Retorna el resultado de realizar a partir de 1 rango de entrada, determinado
por ranMin y ranMax, una secuencia de numOpe operaciones de suma, resta,
multiplicacion y division aleatorias y equiprobables.
La construccion se realiza por la expansion de un arbol binario con tantos
nodos de operacion como determine numOpe.",
BenOpeTreRnd);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// TEST
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nBenford.Test make: process");

//////////////////////////////////////////////////////////////////////////////
Set tst001 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
  Set tstR01 = BenView(
               "numeros aleatorios de distribucion uniforme", 1000,
               Real(Real posCic) { Rand(0,1) });

  Set tstS01 = BenView(
               " 4 operaciones secuenciales basicas + - * /", 1000,
               Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1),  4)})
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Numeros aleatorios frente a operaciones aleatorias.", tst001);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set tst002 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
  Set tstS02 = BenView(
               "10 operaciones secuenciales basicas + - * /", 2000,
               Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1), 10)});

  Set tstS04 = BenView(
               " 5 operaciones secuenciales basicas + - * /", 4000,
               Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1),  5)})
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Comparar nº de ciclos contra nº de operaciones.", tst002);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set tst003 = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
  Set tstS03 = BenView(
               " 7 operaciones secuenciales basicas + - * /", 3000,
               Real(Real posCic) { BenOpeSecRnd(Rand(0,1),Rand(0,1),  7)});

  Set tstT03 = BenView(
               " 7 operaciones en arbol basicas + - * /", 3000,
              Real(Real posCic) { BenOpeTreRnd(0, 1, 7)});

  Set tstE03 = BenView(
               "exponencial de numeros aleatorios entre 0 y 1", 3000,
               Real(Real posCic) { Exp(Rand(-10,10)) })
});
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Compararcion de la generacion en secuencia de operaciones, en arbol binario
de operaciones y la exponencial de numeros aleatorios.",
tst003);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set tstFor = If(FALSE, FALSE, // Poner a true/false para ejecutar o no
{
  Set tstD02 = BenView(
               "trafico dudoso, acumulado en bytes", Card(TraDud),
               Real(Real posCic) { TraDud[posCic] });

  Set tstC02 = BenView(
               "trafico controlado, acumulado en bytes", Card(TraChk),
               Real(Real posCic) { TraChk[posCic] })
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Analiza el caso de informatica forense.", tstFor);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// END
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nBenford.Test make: end");

2015 asolver.com | Aviso legal | XHTML | Δ Θ Ξ | Creative Commons | Mapa y funciones del sitio

Tol