Sudoku II

Sudoku II

Hace tiempo escribí un artículo sobre un método de generación de sudokus en wakicode, ahora se me ha ocurrido obtener un método sencillo de resolución de sudoku. En esta primera parte mostraré como intentar resolverlos por pura lógica, con operaciones lógicas en pura esencia, sin necesidad de efectuar simulaciones por fuerza bruta o prueba error. Eso será más adelante cuando la lógica no tenga cabida.

El método que se me ha ocurrido lo hago del siguiente modo.

1.- Definiciones.

  • Ln. Capa de posición de un elemento n, se corresponde con un 1 si existe n (o es visible) y 0 si no es visible. En el ejemplo, podemos visualizar para un n=2, la matriz resultado de L2.
  • Bnc. Byte de columna para n. En el ejemplo B2c=110101111 que corresponde a un 1 si la columna tiene un 1 y 0 si la columna es ausente de 1.
  • Bnr. Byte de fila para n. En el ejemplo B2r=110110111 que corresponde (de arriba hacia abajo) a un 1 si la fila tiene un 1 y 0 si esta es ausente de 1.
  • Bns. Byte de bloque 3×3 para n. En el ejemplo B2s=101011111 que corresponde (de izquierda a derecha y de arriba abajo) a un 1 si el bloque 3×3 tiene un 1 y 0 si el bloque 3×3 es ausente de 1.
  • Mo. Matriz de elementos ocupados. Matriz 9×9 identificada por un 1 si la celda tiene un valor visible y un 0 si no lo tiene.
  • Mnc. Matriz de columnas. Operación OR de cada uno de los elementos de Mo con el bit correspondiente de Bnc. Mo OR Bnc
  • Mnr. Matriz de filas. Operación OR de cada uno de los elementos de Mnc con el bit correspondiente de Bnr. Mnc OR Bnr
  • Mns. Matriz de bloque. Operación OR de cada uno de los elementos de Mnr con Bns. Mnr OR Bns
Mnc. Mo OR Bnc. Los elementos de la derecha corresponden al resultado de la operación OR de los elementos de la izquierda del mismo color.

Una vez que conocemos los elementos participantes en el método pasamos a describir su desarrollo:

  1. Generar Mnc. Buscar en la matriz elementos únicos con valor 0. Esto significa que al realizar la operación OR del byte de columna con los elementos ocupados, queremos discriminar los elementos en los que únicamente pueden estar en esa posición. En el caso del ejemplo para n=2 no existen elementos únicos puesto que las columnas que tienen 0, tienen más de un 0. La columna 3ª tiene tres «0» y 5ª columna tiene dos «0».
  2. Generar Mnr. Buscar en la matriz elementos únicos con valor 0. En el caso del ejemplo para n=2 la matriz resultante si tiene elementos únicos puesto que las columnas que tienen 0, tienen más de un 0. La columna 3ª tiene tres «0» y la 5ª columna tiene dos «0».
    El caso de la figura indica que el lugar ocupado por los ceros únicos, es una celda ocupada en este caso por un 2
  3. Generar Mns. Buscar en la matriz elementos únicos con valor 0. En este caso se buscan elementos únicos en el bloque 3×3 y que para el caso concreto, ha coincidido con los elementos obtenidos de en Mnr.
    La matriz de la derecha corresponde con la operación OR del Byte y la matriz origen
  4. En cada generación de una nueva Matriz se realiza una búsqueda de estos elementos únicos. Solo en el caso de ubicaciones ambiguas en las que es posible ocupar dos celdas o tres o más celdas con 3 o más números posibles, habría que usar otros métodos de fuerza bruta o prueba y error hasta que no se me ocurra otro método lógico para este caso. Esto lo dejaremos para otro post.

Para terminar os dejo el diagrama de clases y cuando se me ocurra un método lógico de resolución del sudoku pondré el código en GitHub.

He aquí una muestra con C# y WPF resolviendo Sudokus generados aleatoriamente con 50 celdas ocultas. El algoritmo en la mayoría de los casos, para unas 50 celdas ocultas, no ha necesitado más de 7 iteraciones para resolver todos los elementos por lógica. Le he indicado que dependiendo del número de iteraciones cambie de color el número encontrado, del azul, verde, amarillo al rojo como el color de mayor iteración.

tailrec

tailrec
Hace tiempo me topé con un modificador llamado tailrec. ¿Que hace? Pues le dice al compilador que es una función recursiva y que la trate como una función iterativa en lugar de recursiva.
Y esto ¿por qué? vamos a poner un ejemplo del cálculo de un elemento de la sucesión de Fibonacci donde existe un crecimiento alto en cada llamada recursiva. Si eliminamos la palabra clave modificador (aunque es una anotación) tailrec para un n = 10000, la función muestra un error StackOverflow. Al añadirla de nuevo, la función se convierte a nivel compilador en una función iterativa y el error no se produce.

tailrec fun fibonacci(n: Int, a: BigInteger= BigInteger.ZERO, b: BigInteger= BigInteger.ONE): BigInteger {
    return if (n == 0) b
    else fibonacci(n - 1, a + b, a)
}

val n = 10000
println("fib($n)=${fibonacci(n)}")
Exception in thread "main" java.lang.StackOverflowError
	at MainKt.fibonacci(Main.kt:52)

val n = 10000
println("fib($n)=${fibonacci(n)}")

fib(10000)= 20793608237133498072112648988642836825087036094015903119682945866528501423455686648927456034305226515591757343297190158010624794267250973176133810179902738038231789748346235556483191431591924532394420028067810320408724414693462849062668387083308048250920654493340878733226377580847446324873797603734794648258113858631550404081017260381202919943892370942852601647398213554479081823593715429566945149312993664846779090437799284773675379284270660175134664833266377698642012106891355791141872776934080803504956794094648292880566056364718187662668970758537383352677420835574155945658542003634765324541006121012446785689171494803262408602693091211601973938229446636049901531963286159699077880427720289235539329671877182915643419079186525118678856821600897520171070499437657067342400871083908811800976259727431820539554256869460815355918458253398234382360435762759823179896116748424269545924633204614137992850814352018738480923581553988990897151469406131695614497783720743461373756218685106856826090696339815490921253714537241866911604250597353747823733268178182198509240226955826416016690084749816072843582488613184829905383150180047844353751554201573833105521980998123833253261228689824051777846588461079790807828367132384798451794011076569057522158680378961532160858387223882974380483931929541222100800313580688585002598879566463221427820448492565073106595808837401648996423563386109782045634122467872921845606409174360635618216883812562321664442822952537577492715365321134204530686742435454505103269768144370118494906390254934942358904031509877369722437053383165360388595116980245927935225901537634925654872380877183008301074569444002426436414756905094535072804764684492105680024739914490555904391369218696387092918189246157103450387050229300603241611410707453960080170928277951834763216705242485820801423866526633816082921442883095463259080471819329201710147828025221385656340207489796317663278872207607791034431700112753558813478888727503825389066823098683355695718137867882982111710796422706778536913192342733364556727928018953989153106047379741280794091639429908796650294603536651238230626

Calculadora CVSS 3.1

Calculadora CVSS 3.1

En Arithmos, publiqué un post acerca de CVSS en su versión 3.1 y para ser sincero, cada vez que escucho la palabra calculadora, se me erizan los pelos y allí que meto la cabeza, así que como no iba a ser menos en esta ocasión, he desarrollado una con Kotlin en una tarde. Así mismo tal y como os puse en arithmos, podeís visitar los enlaces de las calculadoras de First y NVD.

Para empezar, que base de datos usamos, podríamos usar JSON, XML, pero como estos datos solo varían con cada versión de CVSS, he creado unos modelos Group, Metric, MetricValue y MetricType los cuales serán el alimento de una clase con los datos precargados llamada DataDB31, de hecho si queréis almacenarla en JSON por ejemplo, siemplemente debéis serializar la clase y asunto concluido, para ello hay una clase Repository encargada de acceder a cualquiera del tipo de datos elegido. Una vez tenemos los datos, la clase que se encargará de calcular todo será la clase CVSSv31 junto a Risk.

Los modelos (aunque veáis algunas propiedades en inglés, lo hice con vistas a una versión en-es):

data class Metric(
        val name: String,
        val description: String,
        val englishName: String,
        val group: Group,
        val metricValues: MutableList,
        val longDescription: String,
        val ratingText: String,
        val metricType: MetricType = MetricType.NONE,
        var valueSelected : Double = 0.0,
        var otherValueSelected : Double = 0.0,
        var metricValueSelected : String = ""
)

data class MetricValue(
        val value: String,
        val spValue: String,
        val enValue: String,
        val description: String,
        val numericalValue: Double,
        val otherValue: Double = 1.0
) {
    val metricValue: String
        get() = value.split(':')[1]
    val metric: String
        get() = value.split(':')[0]
}

enum class MetricType(val description: String) {
    EXPLOITABILITY("Explotación"),
    IMPACT("Impacto"),
    NONE(""),
    SECURITYREQUIREMENT("Requisitos de seguridad"),
    MODIFIEDBASESCORE("Métricas base modificadas")
}

enum class Group(val description: String, val longDescription: String) {
    BASESCORE(
            "Grupo Métricas Base",
            "Son propiedades intrínsecas de la vulnerabilidad, siendo constantes en el tiempo y entorno utilizado. Permiten la definición del acceso a una vulnerabilidad y si se cumplen las condiciones necesarias para que sea explotada. Determina el grado de pérdida de confidencialidad, disponibilidad o integridad"
    ),
    TEMPORAL(
            "Grupo Métricas Temporal",
            "Son las características de la vulnerabilidad que podrían ser dinámicas con el paso del tiempo. Hay que tener en cuenta que estas métricas no afectan a la evaluación ya que son totalmente opcionales y se pueden omitir"
    ),
    ENVIROMENTAL(
            "Grupo Métricas Entorno",
            "Características que son únicas y tienen relevancia para un entorno en particular. Las métricas consideradas en este caso son las mismas métricas base pero teniendo en cuenta a la hora de valorarlas el impacto de cada una de ellas en el entorno concreto que estemos analizando y su importancia en el mismo"
    )
}

Y como resultado, cvss02

La podéis descargar desde aquí y si aguien quiere el código completo o el archivo JSON, que me lo pida! (o debería saber como obtenerlo)

😉

Saludos

Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-NoComercial-CompartirIgual 4.0 Internacional.

Suffled

Suffled
Kotlin tiene algunas funciones extendidas muy prácticas, entre otras la función shuffled(), pero y C# ¿tiene esta función?. la respuesta es no y ¿como lo haremos? Bien, he aquí una extensión que uso en mi código como extensión de listas.

public static class Extensions
    {
        public static List Shuffled(this List source)
        {
            var rnd = new Random();
            return source
           .Select(x => new { value = x, order = rnd.Next() })
           .OrderBy(x => x.order).Select(x => x.value).ToList();
        }
    }

Lo primero sería crear un objeto anónimo por cada elemento de la lista al cual le asignaremos un índice aleatorio; este índice será ordenado posteriormente, de ese modo obtendremos la lista en un orden distinto.

var list = new List() { "Negro", "Marrón", "Rojo", "Naranja", "Amarillo", "Verde", "Azul", "Violeta", "Gris", "Blanco" };
            Console.WriteLine(string.Join("\n",list.Suffled()));
            Console.ReadKey();

y el resultado


Verde
Azul
Marrón
Amarillo
Gris
Blanco
Negro
Rojo
Violeta
Naranja

Genetic Algorithm & Binding

Genetic Algorithm & Binding
Ya que sabemos como implementar un algoritmo genético básico con la Interface de Waki, vamos a usar el algoritmo genético de ordenamiento del tablero de ajedrez del post Interface. Algoritmo Genético II y crearemos una interfaz gráfica con WPF y como no, aplicaremos lo que sabemos con Binding.
Lo primero que vamos a hacer es que la clase ChessBoard implemente la interfaz INotifyPropertyChanged del namespace System.ComponentModel. Una vez hecho esto, añadimos el evento public event PropertyChangedEventHandler PropertyChanged y creamos un método que realice la llamada. Ahora que ya podemos notificar cambios en las propiedades, le incluimos una llamada a este método desde la propiedad BestParent, es decir, cada vez que se encuentre una solución parcial en el algoritmo queremos que actualice la pantalla, para ello cambiamos también la propiedad Bestparent por su equivalente de propiedad completa.

public event PropertyChangedEventHandler PropertyChanged;

public void OnPropertyChanged(string property)
{
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
private List bestparent;

public List BestParent
{
        get { return bestparent; }
        set
        { 
            bestparent = value;
            OnPropertyChanged(nameof(BestParent));
        }
}

A la clase ChessPiece le he añadido una propiedad nueva llamada Picture para incluirle la forma de la pieza de ajedrez.
Acto seguido, preparamos nuesto código XAMl, donde yo lo que he hecho, como nuestra clase ChessBoard era una lista de objetos ChessPiece, no he cambiado a coordenadas y simplemente he incluido 64 Textblock, uno por casilla y el DataContext de cada Textblock es el que corresponde a cada objeto de la lista de objetos ChessPiece. Posteriormente cada Textblock tendrá un style asociado donde se le crea el Binding con el texto o la figura de ajedrez. (Las piezas de ajedrez son caracteres Unicode. ♜♞♝♛♚♟♖♘♗♕♔♙).
El estilo aplicado a cada Textblock es el siguiente:

<Style x:Key="piece" TargetType="TextBlock">
            <Setter Property="Text" Value="{Binding Picture}"/>

Código XAML

<Window x:Class="ChessBoardProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ChessBoardProject"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="20*"/>
            <ColumnDefinition Width="20"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20*"/>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="board">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="55"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="55"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="55"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="55"/>
            </Grid.RowDefinitions>
            

            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="0" Grid.Column="0"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="0" Grid.Column="1"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="0" Grid.Column="2"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="0" Grid.Column="3"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="0" Grid.Column="4"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="0" Grid.Column="5"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="0" Grid.Column="6"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="0" Grid.Column="7"/>

            <Rectangle Style="{StaticResource blackCell}" Grid.Row="1" Grid.Column="0"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="1" Grid.Column="1"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="1" Grid.Column="2"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="1" Grid.Column="3"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="1" Grid.Column="4"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="1" Grid.Column="5"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="1" Grid.Column="6"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="1" Grid.Column="7"/>

            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="2" Grid.Column="0"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="2" Grid.Column="1"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="2" Grid.Column="2"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="2" Grid.Column="3"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="2" Grid.Column="4"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="2" Grid.Column="5"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="2" Grid.Column="6"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="2" Grid.Column="7"/>

            <Rectangle Style="{StaticResource blackCell}" Grid.Row="3" Grid.Column="0"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="3" Grid.Column="1"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="3" Grid.Column="2"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="3" Grid.Column="3"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="3" Grid.Column="4"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="3" Grid.Column="5"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="3" Grid.Column="6"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="3" Grid.Column="7"/>

            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="4" Grid.Column="0"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="4" Grid.Column="1"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="4" Grid.Column="2"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="4" Grid.Column="3"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="4" Grid.Column="4"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="4" Grid.Column="5"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="4" Grid.Column="6"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="4" Grid.Column="7"/>

            <Rectangle Style="{StaticResource blackCell}" Grid.Row="5" Grid.Column="0"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="5" Grid.Column="1"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="5" Grid.Column="2"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="5" Grid.Column="3"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="5" Grid.Column="4"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="5" Grid.Column="5"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="5" Grid.Column="6"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="5" Grid.Column="7"/>

            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="6" Grid.Column="0"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="6" Grid.Column="1"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="6" Grid.Column="2"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="6" Grid.Column="3"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="6" Grid.Column="4"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="6" Grid.Column="5"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="6" Grid.Column="6"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="6" Grid.Column="7"/>

            <Rectangle Style="{StaticResource blackCell}" Grid.Row="7" Grid.Column="0"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="7" Grid.Column="1"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="7" Grid.Column="2"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="7" Grid.Column="3"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="7" Grid.Column="4"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="7" Grid.Column="5"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="7" Grid.Column="6"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="7" Grid.Column="7"/>

            <Rectangle Fill="Transparent" Stroke="Black" StrokeThickness="3" Grid.RowSpan="8" Grid.ColumnSpan="8"/>

            <TextBlock DataContext="{Binding BestParent[0]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[1]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[2]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[3]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[4]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[5]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[6]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[7]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[8]}" Style="{StaticResource piece}"   Grid.Row="1" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[9]}" Style="{StaticResource piece}"   Grid.Row="1" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[10]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[11]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[12]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[13]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[14]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[15]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[16]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[17]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[18]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[19]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[20]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[21]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[22]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[23]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[24]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[25]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[26]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[27]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[28]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[29]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[30]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[31]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[32]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[33]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[34]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[35]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[36]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[37]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[38]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[39]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[40]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[41]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[42]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[43]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[44]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[45]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[46]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[47]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[48]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[49]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[50]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[51]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[52]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[53]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[54]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[55]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[56]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[57]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[58]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[59]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[60]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[61]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[62]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[63]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="7"/>
        </Grid>
        <Button Content="Start" Grid.Column="1" HorizontalAlignment="Right" Grid.Row="1" VerticalAlignment="Bottom" Width="75" Margin="20" Click="Button_Click"/>
    </Grid>
   
</Window>

Para no bloquear la interfaz, creamos una tarea y ejecutamos. Le he puesto un retardo de unos cuantos milisegundos en cada solución parcial para ver como actua el algoritmo y el resultado.
ScreenCapture_05-09-2020 12.44.10.gif
Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.

Contraseñas y entropía

Contraseñas y entropía

Hoy un amigo nos ha enviado un mensaje al grupo de la Promoción para ver que opinábamos al respecto de la siguiente imagen

IMG-20200902-WA0018.jpg

y yo que la he visto, instantáneamente me he acordado del cálculo necesario para rellenar esta tabla.

Lo primero de todo se debe calcular la entropía. La entropía de una contraseña es calculo matemático que representa un indicador de como se encuentra esta contraseña sobre una población, si incluimos en nuestra contraseña mayúsculas, minúsculas, números y símbolos, la entropía de nuestra contraseña será mayor puesto que la población de caracteres usados es mucho mayor, en este caso, unos 94 (26 minúsculas, 26 mayúsculas, 10 números y 32 símbolos). La fórmula es la siguiente:

entropia.png

o lo que es lo mismo, es el logaritmo en base de 2 de la cantidad de elementos de la población por la longitud de la cadena. Si efectuamos el cálculo inverso, 2 elevado a la entropía debe ser igual a la población elevada al número de caracteres de  nuestra contraseña, que esto serían el número máximo de operaciones necesarias para intentar reventar nuestra password por fuerza bruta.

Si nuestra contraseña usa solo las minúsculas, su «pool» sería de 26 y por tanto la contraseña tendría una entropía baja y fácil de descubrir.

Si hay alguien que quiera comprobar la fuerza de su contraseña online puede hacerlo desde Kaspersky
Bien, pero lo que a mi me importa es como sabemos, con código. En la clase le he incluido una penalización si nuestra contraseña se encuentra entre las más conocidas.

En C#

    /*
************************************************************************************************************************************************
    * © JOAQUIN MARTINEZ RUS 2020
    * Archivo:         PasswordEntropy.cs
    * Descripción:     Clase que calcula la entropia y el tiempo en descifrar por fuerza bruta de de una contraseña
    * Historial:
    *                  1. Joaquin Martínez Rus - 02 sep 2020. Creación
    *
    * Comentarios:
    *
    *
    ****************************************************************/
    public class PasswordEntropy
    {
        public PasswordEntropy(string password)
        {
            Password = password;

        }

        public string Password { get; set; }
        public double Entropy => GetEntropy();
        public string EntropyToString => GetTimeByEntropy(Entropy);

        private double GetEntropy()
        {
            //Pools
            double pool = 0;

            // Numbers
            pool += Password.Any(k => char.IsDigit(k)) ? 10 : 0;
            // Lower 26
            pool += Password.Any(k => char.IsLower(k)) ? 26 : 0;
            // Upper 26
            pool += Password.Any(k => char.IsUpper(k)) ? 26 : 0;
            // Simbols 30
            pool += Password.Any(k => (char.IsSymbol(k) || char.IsPunctuation(k))) ? 32 : 0;

            if (pool == 0) return pool;
            // entropy = Lenght * log pool / log2
            var p = Math.Log(pool, 2);
            var entropy = Password.Length * Math.Log(pool, 2);

            // el uso de una contraseña famosa, indica una falta de seguridad absoluta
            // por lo que no se incluye como deducción de entropía, sino que se incluye en el
            // mismo cálculo de la entropía
            if (IsFamous(Password))
            {
                entropy = (int)Entropies.NoSecurity - 1; // Inexistencia de seguridad
            }
            return entropy;
        }

        private const double OPERATIONPERSECOND = 4*10E12;

        private bool IsFamous(string password)
        {
            var list = new List()
            {
                "1234",
                "2000",
                "12345",
                "111111",
                "123123",
                "123456",
                "654321",
                "696969",
                "1234567",
                "12345678",
                "abc123",
                "alejandra",
                "america",
                "baseball",
                "bonita",
                "daniel",
                "dragon",
                "estrella",
                "football",
                "harley",
                "iloveyou",
                "jennifer",
                "jesus",
                "jordan",
                "letmein",
                "mariposa",
                "master",
                "michael",
                "monkey",
                "mustang",
                "password",
                "pussy",
                "qwerty",
                "roberto",
                "sebastian",
                "shadow",
                "superman",
                "Tequiero"
            };
            return list.Contains(password);
        }

        public enum Entropies
        {
            Blank = 0,
            NoSecurity =10,
            TooWeak=20,
            VeryWeak=28,
            Weak=35,
            Medium=55,
            Strong=75,
            Stronger=127,
            OverTheTopStrong = 190
        }

        private string GetTimeByEntropy(double entropy)
        {
            if (entropy == 0) return string.Empty;
            string output = "";

            double value = Math.Pow(2, entropy) / OPERATIONPERSECOND;
            double ms = 0;
            double seconds = value;
            double minutes = seconds / 60;
            double hours = minutes / 60;
            double days = hours / 24;
            double months = days / 30;
            double years = months / 12;
            double centuries = years / 100;
            double millennium = centuries / 10;

            seconds = value;
            if (value == 0) return "";

            if (seconds > 0 && seconds  59 && hours > 24 && days  11 && years < 100 && centuries < 1000000)
            {
                output = "Tu contraseña puede ser descifrada en más de un millón de años!";
            }
            else
            {
                millennium = Math.Round(millennium, 1);
                output = $"Tu contraseña puede ser descifrada en {millennium}, {(millennium == 1 ? "milenio" : "milenios")}";
            }

            return output;
        }
    }

static void Main(string[] args)
        {
            var password = "x#Pr0m0cio_N";

            for (int i = 1; i <= password.Length; i++)
            {
                var pwd = new PasswordEntropy(password.Substring(0,i));
                Console.WriteLine($"Password: {pwd.Password}\n{pwd.EntropyToString}");
                Console.WriteLine("Press any key");
            }

            Console.ReadKey();
        }

el resultado iterando por la contraseña que he creado


Password: x
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#P
Tu contraseña puede ser descifrada en 0, milisegundos
Press any key
Password: x#Pr
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr0
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr0m
Tu contraseña puede ser descifrada en 17 milisegundos
Press any key
Password: x#Pr0m0
Tu contraseña puede ser descifrada en 2 segundos
Press any key
Password: x#Pr0m0c
Tu contraseña puede ser descifrada en 3 minutos
Press any key
Password: x#Pr0m0ci
Tu contraseña puede ser descifrada en 4 horas
Press any key
Password: x#Pr0m0cio
Tu contraseña puede ser descifrada en 15,6 dias
Press any key
Password: x#Pr0m0cio_
Tu contraseña puede ser descifrada en 4,1 años
Press any key
Password: x#Pr0m0cio_N
Tu contraseña puede ser descifrada en 3,8 siglos
Press any key

y en Kotlin

class PasswordEntropy(val password: String) {

    init {

    }

    fun entropy(): Double {

        //Pools
        var pool = 0.0

        // Numbers
        pool += if (password.any { c -> c.isDigit() }) 10.0 else 0.0
        // Lower 26
        pool += if (password.any { c -> c.isLowerCase() }) 26.0 else 0.0
        // Upper 26
        pool += if (password.any { c -> c.isUpperCase() }) 26.0 else 0.0
        val (noSymbols, symbols) = password.partition { it.isLetter() || it.isDigit() }
        // Simbols 32
        pool += if (symbols.count()>0) 32.0 else 0.0
        if (pool == 0.0) return pool
        // entropy = Lenght * log pool / log2

        var entropy = password.length * log2(pool)

        // el uso de una contraseña famosa, indica una falta de seguridad absoluta
        // por lo que no se incluye como deducción de entropía, sino que se incluye en el
        // mismo cálculo de la entropía
        if (isFamous()) {
            entropy = 9.0 // Inexistencia de seguridad
        }
        return entropy
    }

    private fun isFamous(): Boolean{
        return listOf(
            "1234",
            "2000",
            "12345",
            "111111",
            "123123",
            "123456",
            "654321",
            "696969",
            "1234567",
            "12345678",
            "abc123",
            "alejandra",
            "america",
            "baseball",
            "bonita",
            "daniel",
            "dragon",
            "estrella",
            "football",
            "harley",
            "iloveyou",
            "jennifer",
            "jesus",
            "jordan",
            "letmein",
            "mariposa",
            "master",
            "michael",
            "monkey",
            "mustang",
            "password",
            "pussy",
            "qwerty",
            "roberto",
            "sebastian",
            "shadow",
            "superman",
            "Tequiero").contains(password)

    }
    private val OPERATION_PER_SECOND: Double = 4*10E12

    fun entropyToString(): String {
        val entropy = entropy()
        if (entropy == 0.0) return ""

        val value = 2.0.pow(entropy) / OPERATION_PER_SECOND
        var ms = 0
        var seconds = value
        val minutes = seconds / 60.0
        val hours = minutes / 60.0
        val days = hours / 24.0
        val months = days / 30.0
        val years = months / 12.0
        val centuries = years / 100.0
        val millennium = centuries / 10.0

        seconds = value
        if (value == 0.0) return ""

        return "Contraseña: $password\n${if (ifa) "Es una contraseña conocida!\n" else ""}${when {
                    ms in 1..999 ->"Tu contraseña puede ser descifrada inmediatamente, yo no lo llamaría contraseña"
                    seconds > 0 && seconds  "Tu contraseña puede ser descifrada en ${seconds.toInt()} ${if (seconds.toInt() == 1) "segundo" else "segundos"}"
                    seconds > 59 && minutes   "Tu contraseña puede ser descifrada en ${minutes.toInt()} ${if (minutes.toInt() == 1) "minuto" else "minutos"}"
                    minutes > 59 && hours "Tu contraseña puede ser descifrada en ${hours.toInt()} ${if (hours.toInt() == 1) "hora" else "horas"}"
                    hours > 24 && days  "Tu contraseña puede ser descifrada en ${days.toInt()} ${if (days.toInt() == 1) "dia" else "dias"}"
                    days > 30 && months  "Tu contraseña puede ser descifrada en ${months.toInt()} ${if (months.toInt() == 1) "mes" else "meses"}"
                    months > 11 && years   "Tu contraseña puede ser descifrada en ${years.toInt()} ${if (years.toInt() == 1) "año" else "años"}"
                    years > 99 && centuries  "Tu contraseña puede ser descifrada en ${"%.1f".format(centuries)} ${if (centuries == 1.0) "siglo" else "siglos"}"
                    millennium > 1000000 -> "Tu contraseña puede ser descifrada en más de un millón de años!"
            else -> "Tu contraseña puede ser descifrada en ${millennium.toInt()} ${if (millennium.toInt() == 1) "milenio" else "milenios"}"}}"
}

fun main(){
    val password = "x#Pr0m0cio_N";

    for (i in (1..password.length)) {
        val pwd = PasswordEntropy(password.substring(0,i))
        println("Password: ${pwd.password}\n${pwd.entropyToString()}\n")

    }
}

el resultado para Kotlin


Password: x
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#P
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr0
Tu contraseña puede ser descifrada en 0 milisegundos
Press any key
Password: x#Pr0m
Tu contraseña puede ser descifrada en 17 milisegundos
Press any key
Password: x#Pr0m0
Tu contraseña puede ser descifrada en 2 segundos
Press any key
Password: x#Pr0m0c
Tu contraseña puede ser descifrada en 3 minutos
Press any key
Password: x#Pr0m0ci
Tu contraseña puede ser descifrada en 4 horas
Press any key
Password: x#Pr0m0cio
Tu contraseña puede ser descifrada en 15,6 dias
Press any key
Password: x#Pr0m0cio_
Tu contraseña puede ser descifrada en 4,1 años
Press any key
Password: x#Pr0m0cio_N
Tu contraseña puede ser descifrada en 3,8 siglos
Press any key

El archivo jar podéis descargarlo desde aquí

Archivo ZIP

SHA256 9314879A535675E813EAC13CEC9B056CAADC4C080E5E033E239E2D88A60F55E3

Archivo jar

SHA256 CA942FB971E34CB775E14F12C5B25E5E456044F02DD54447F5690FA05469C3C8

Saludos a la X Promoción del IPE 2!!!

 

Interface. Genetic Algorithm II

Interface. Genetic Algorithm II
En este post veremos como un algoritmo genético es capaz de ordenar un tablero de ajedrez. Es como si un niño de 2 años pusiera las piezas aleatoriamente en el tablero y el algoritmo se encargara de poner cada una en su sitio.

Crearemos una clase ChessPiece para cada figura de ajedrez y una clase ChessBoard que implementará la interfaz IMutable. Esto quiere decir que nuestro cromosoma es una lista de piezas de ajedrez y que el Fitness es del tipo doble.
Acto seguido, creamos el geneset o conjunto de genes que formarán el cromosoma donde incluiremos también la casilla vacía. Luego le daremos un valor a cada pieza y otro valor a cada casilla, cada vez que se acierte, el fitness se verá incrementado hasta el 100%.

class ChessBoard : IMutable {
    override val geneset = mutableListOf(
            ChessPiece("T",ChessPieceColor.BLACK,11),
            ChessPiece("C",ChessPieceColor.BLACK,13),
            ChessPiece("A",ChessPieceColor.BLACK,15),
            ChessPiece("D",ChessPieceColor.BLACK,16),
            ChessPiece("R",ChessPieceColor.BLACK,18),
            ChessPiece("A",ChessPieceColor.BLACK,15),
            ChessPiece("C",ChessPieceColor.BLACK,13),
            ChessPiece("T",ChessPieceColor.BLACK,11),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("P",ChessPieceColor.BLACK,4),
            ChessPiece("T",ChessPieceColor.WHITE,10),
            ChessPiece("C",ChessPieceColor.WHITE,12),
            ChessPiece("A",ChessPieceColor.WHITE,14),
            ChessPiece("D",ChessPieceColor.WHITE,17),
            ChessPiece("R",ChessPieceColor.WHITE,19),
            ChessPiece("A",ChessPieceColor.WHITE,14),
            ChessPiece("C",ChessPieceColor.WHITE,12),
            ChessPiece("T",ChessPieceColor.WHITE,10),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5),
            ChessPiece("P",ChessPieceColor.WHITE,5))

    init {

        geneset.addAll((1..32).map { ChessPiece("_",ChessPieceColor.EMPTY,0) })
    }

    override val target: Double = 64.0
    override var bestParent = createParent(0)
    override var bestFitness: Double = 0.0
    private val values = mutableListOf(11,13,15,16,18,15,13,11,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,10,12,14,17,19,14,12,10)

    override fun isSuccess(): Boolean = bestFitness == 1.0

    var result=""
    override fun start() {
        bestFitness = getFitness(bestParent)
        var childFitness: Double
        var child: MutableList
        //Display(bestParent, bestFitness)
        var attemps=0

        do {
            do {
                child = mutate(bestParent)
                childFitness = getFitness(child)

            } while (bestFitness > childFitness)

            bestFitness = childFitness
            bestParent = child
            result +=toShortString() + "\n\n\n"
            attemps ++
            println(toShortString() + "\n")
        } while (!isSuccess())
        println("Nº de intentos: $attemps")
    }

    override fun createParent(param: Any): MutableList {
        // llena el tablero con las 32 fichas piezas + 32 vacias
        return geneset.shuffled().toMutableList()
    }

    override fun getFitness(obj: MutableList): Double = obj.mapIndexed { index, chessPiece -> if (values[index] == chessPiece.value) 1.0 else 0.0  }.sum() / target

    override fun mutate(parent: MutableList): MutableList {
        val parentFitness: Double = getFitness(parent)
        var childFitness = 0.0
        var child = mutableListOf()

        do {
            child.clear()
            child.addAll(parent)

            val startIndex = Random.nextInt(bestParent.size)
            val endIndex = Random.nextInt(bestParent.size)
            val start = parent[startIndex]
            val end = parent[endIndex]
            child[startIndex] = end
            child[endIndex] = start
            childFitness = getFitness(child)

        }while (childFitness chessPiece.toString() + if ((index+1) % 8 ==0) "\n" else "\t" }
            .joinToString("")}\nFitness: $bestFitness"

    fun toShortString(): String ="${bestParent
                    .mapIndexed { index, chessPiece -> (if (chessPiece.value==0) " " else if (chessPiece.value == values[index]) (if (chessPiece.color==ChessPieceColor.WHITE) "○" else "●") else "#")+if ((index+1) % 8 == 0) "\n" else "" }
                    .joinToString("")
        }\nFitness: ${"%.3f".format(bestFitness)}"
    fun  foo(collection: MutableList){

    }
}

fun main(){
    val chessBoard = ChessBoard()
    chessBoard.start()
    println(chessBoard.bestParent)
}

Y este es el resultado del progreso de los cromosomas para 36 intentos
cromosomas.png

TN	CN	AN	DN	RN	AN	CN	TN
PN	PN	PN	PN	PN	PN	PN	PN
__	__	__	__	__	__	__	__
__	__	__	__	__	__	__	__
__	__	__	__	__	__	__	__
__	__	__	__	__	__	__	__
PB	PB	PB	PB	PB	PB	PB	PB
TB	CB	AB	DB	RB	AB	CB	TB

Fitness: 1.0

Y ahora implementaremos la interfaz con mi mejor amigo, C#

 public class ChessPiece
    {
        public ChessPiece(string name, Colors color, int value)
        {
            Name = name;
            ChessPieceColor = color;
            Value = value;
        }

        public string Name { get; set; }
        public int Value { get; set; }
        public Colors ChessPieceColor { get; set; }

        public enum Colors
        {
            Black,
            White,
            Empty
        }

        public string ColorToString => ValueToString(ChessPieceColor);

        public new string ToString => $"{Name}{ColorToString}";

        private string ValueToString(Colors color)
        {
            switch (color)
            {
                case Colors.Black:
                    return "N";
                case Colors.White:
                    return "B";
                case Colors.Empty:
                    return "_";
                default:
                    return "";
            }
        }

    }

    public class ChessBoard : IMutable
    {
        public ChessBoard()
        {
            Geneset = new List()
            {
                    new ChessPiece("T", ChessPiece.Colors.Black, 11),
                    new ChessPiece("C", ChessPiece.Colors.Black, 13),
                    new ChessPiece("A", ChessPiece.Colors.Black, 15),
                    new ChessPiece("D", ChessPiece.Colors.Black, 16),
                    new ChessPiece("R", ChessPiece.Colors.Black, 18),
                    new ChessPiece("A", ChessPiece.Colors.Black, 15),
                    new ChessPiece("C", ChessPiece.Colors.Black, 13),
                    new ChessPiece("T", ChessPiece.Colors.Black, 11),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("P", ChessPiece.Colors.Black, 4),
                    new ChessPiece("T", ChessPiece.Colors.White, 10),
                    new ChessPiece("C", ChessPiece.Colors.White, 12),
                    new ChessPiece("A", ChessPiece.Colors.White, 14),
                    new ChessPiece("D", ChessPiece.Colors.White, 17),
                    new ChessPiece("R", ChessPiece.Colors.White, 19),
                    new ChessPiece("A", ChessPiece.Colors.White, 14),
                    new ChessPiece("C", ChessPiece.Colors.White, 12),
                    new ChessPiece("T", ChessPiece.Colors.White, 10),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5),
                    new ChessPiece("P", ChessPiece.Colors.White, 5)
            };

            Geneset.AddRange(Enumerable.Range(0, 32).ToList().Select(k => new ChessPiece("_", ChessPiece.Colors.Empty, 0)));           

        }

        public List Geneset { get; set; }
        public double Target { get; set; } = 64;
        public List BestParent { get; set; }
        public double BestFitness { get; set; }

        private Random rnd = new Random();
        private IList Values = new List() { 11, 13, 15, 16, 18, 15, 13, 11, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 10, 12, 14, 17, 19, 14, 12, 10 };
        private string result = "";

        public List CreateParent(object param) => Suffled(Geneset);

        public double GetFitness(List obj) => obj
            .Select((item, index) => new { Item = item, Index = index })
            .Select(k => k.Item.Value == Values[k.Index] ? 1.0 : 0.0)
            .Sum()/Target;

        public bool IsSuccess() => BestFitness == 1.0;

        public List Mutate(List parent)
        {

            var parentFitness = GetFitness(parent);
            var childFitness = 0.0;
            var child = new List();

            do
            {
                child.Clear();
                child.AddRange(parent);

                var startIndex = rnd.Next(BestParent.Count());
                var endIndex = rnd.Next(BestParent.Count());
                var start = parent[startIndex];
                var end = parent[endIndex];

                child.RemoveAt(startIndex);
                child.Insert(startIndex, end);
                child.RemoveAt(endIndex);
                child.Insert(endIndex, start);

                childFitness = GetFitness(child);
                //print(child);
            } while (childFitness k.Value)));
        }

        public void Start()

        {
            BestParent = CreateParent(null);
            BestFitness = GetFitness(BestParent);
            var childFitness = 0.0;
            var child = new List();

            var attemps = 0;
            do
            {
                do
                {
                    child = Mutate(BestParent);
                    childFitness = GetFitness(child);
                } while (BestFitness > childFitness);

                BestFitness = childFitness;
                BestParent = child;
                result += ToShortString + "\n\n\n";
                Console.WriteLine(result);
                attemps++;
            } while (!IsSuccess());

            Console.WriteLine(ToShortString + "\n");
            Console.WriteLine($"Nº intentos: {attemps}");
        }

        private List Suffled(List source) => source
            .Select(x => new { value = x, order = rnd.Next() })
            .OrderBy(x => x.order).Select(x => x.value).ToList();

        public new string ToString => $"{string.Join("",BestParent.Select((item, index) => new { Item = item, Index = index }).Select(k => k.Item.ToString + (((k.Index + 1) % 8 == 0) ? '\n' : ' '))) }";
        public string ToShortString => $"{string.Join("",BestParent.Select((item, index) => new { Item = item, Index = index }).Select(k => (k.Item.Value == 0 ? " " : (k.Item.Value == Values[k.Index]) ? (k.Item.ChessPieceColor == ChessPiece.Colors.White ? "O" : "■") : "#") + (((k.Index + 1) % 8 == 0) ? '\n' : ' '))) }";

    }
 class Program
    {
        static void Main(string[] args)
        {
            var chessboard = new ChessBoard();
            chessboard.Start();
            Console.WriteLine(chessboard.ToString);
            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }
    }

Si quieres leer mi anterior post sobre la interface de algoritmos genéticos, aquí lo tienes.

Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.

Interface. Genetic Algorithm I

Interface. Genetic Algorithm I

¿Cómo conseguir un objetivo por los mismos medios por los que una especie sobrevive? La respuesta es, mutando y cruzándo sus individuos para obtener ese objetivo.

Los algoritmos genéticos desde el punto de vista del desarrollo de software, tienen casi todos un patrón único y si tienen un patrón único atienden a una estructura común, por tanto es como cualquier interface, atienden siempre a la misma composición, de modo que ¿Por qué no generamos una interface que implemente este comportamiento? ¿Por qué crear una interface? Generamos una interface porque esperamos que cualquier clase que implemente esta interface haga lo mismo y la interface es el elemento adecuado. (¿he entrado en bucle? uhmmm). Para saber más acerca de interfaces, aquí tiene un artículo de Wakicode.

Bien, la verdad que he buscado y «requetebuscado» (que dicen en mi tierra) y no he visto nada parecido acerca de una interface de algoritmo genéticos.

Un algoritmo genético tiene los siguientes elementos:

  • Un conjunto de genes en los que se basan cada uno de objetos generados
  • Un patrón inicial o digamos un Adán o una Eva
  • Un candidato a ser el mejor de la especie
  • Un indicador métrico de aptitud del mejor de la especie

y efectua las siguientes tareas:

  • Inicia el algoritmo
  • Crea el patrón inicial
  • Obtiene la métrica de cualquier objeto de la especie. Función de Aptitud
  • Ejecuta un cruce entre individuos de la especie. Cruce
  • Ejecuta una mutación sobre un objeto. Mutación
  • Comprueba si se ha cumplido con el objetivo. Criterio de parada
  • Si no se ha conseguido el objetivo, volvemos a realizar la tarea
  • Obtención de la solucióndiagrama algoritmo genetico.png

Además un algoritmo genético no tiene porque realizar un cruce porque a lo mejor nuestro problema lo podemos solucionar mutando solamente sus genes sin realizar cruce. Cada algoritmo hay que estudiarlo

Dicho esto nos ponemos manos a la obra y vamos a desarrollar una interfaz que tenga estos elementos y que nos permita realizar estas acciones con diferentes tipos. En principio voy a crear una interface del tipo Mutable y luego heredaré de esta para crear una nueva Crossover  con funciones de cruce.

En Kotlin

/**
 * @author Joaquin Martinez Rus ©
 * @since 15AGO20
 * version 1.1
 */
interface IMutable
{
    val geneset: T
    val target: F
    var bestParent: T
    var bestFitness: F

    /**
     * Return true when target is reached
     * @return Boolean
     */
    fun isSuccess(): Boolean

    /**
     * Start algorithm
     * @sample
     * CreateParent
     * Mutate
     * GetFitness
     * Compare
     * IsSuccess
     */
    fun start()

    /**
     * Return a new parent object
     * @param Parameter of generation
     * @return Type T
     */
    fun createParent(param: Any): T

    /**
     * Get object fitness
     * @return F value
     */
    fun getFitness(obj: T): F

    /**
     * Return a mutation of a parent object
     * @param Parent element
     * @return type T mutated
     */
    fun mutate (parent: T): T
}

/**
 * @author Joaquin Martinez Rus ©
 * @since 15AGO20
 * version 1.1
 */
interface ICrossOver : IMutable
{
    /**
     * Return a crossover of two objects of same type
     * @param Parent element
     * @return type T crossed over
     */
    fun crossOver(father: T, mother: T): T
}

y en C#

/* ************************************************************************************************************************************************
    * © JOAQUIN MARTINEZ RUS 2020
    * Archivo:         Imutable.cs
    * Descripción:     Interface que implementa un algoritmo genético de mutación
    * Historial:
    *                  1. Joaquin Martínez Rus - 15 ago 2020. Creación
    *
    * Comentarios:
    *
    *
    **************************************************************************************************************************************************/
    public interface IMutable where F : IComparable
    {
        public T Geneset { get; set; }
        public F Target { get; set; }
        public T BestParent { get; set; }
        public F BestFitness { get; set; }

        ///
        /// Return true when target is reached
        /// 

        /// Boolean
        bool IsSuccess();

        ///
        ///  Start algorithm
        ///  Example
        ///  CreateParent
        ///  Mutate
        ///  Getfitness
        ///  Compare
        ///  IsSuccess
        /// 

        void Start();

        ///
        /// Return a new parent object
        /// 

        /// Parameter of generation
        /// Type T
        T CreateParent(object param);

        ///
        /// Get object fitness
        /// 

        /// Object from which the fitness is obtained
        /// F Value
        F GetFitness(T obj);

        ///
        /// Return a mutation of a parent object
        /// 

        /// Parent element
        /// T mutated
        T Mutate(T parent);

    }

    /* ************************************************************************************************************************************************
    * © JOAQUIN MARTINEZ RUS 2020
    * Archivo:         ICrossOver.cs
    * Descripción:     Interface que implementa un algoritmo genético de mutación y cruce
    * Historial:
    *                  1. Joaquin Martínez Rus - 15 ago 2020. Creación
    *
    * Comentarios:
    *
    *
    **************************************************************************************************************************************************/
    public interface ICrossOver : IMutable where F: IComparable
    {
        ///
        /// Return a crossover of two objects of same type
        /// 

        /// Fateher
        /// Mother
        /// type T crossed over
        T CrossOver(T father, T mother);

    }

Analicemos la interface.Lo primero. La interface es una interface genérica con dos tipos, T es el tipo del objeto del algoritmo y F es el tipo de la propiedad Fitness que obligatoriamente debe ser comparable. Este será el cromosoma.
Cuatro propiedades, un geneset o conjunto de genes, el objetivo que pretenderá alcanzar el algoritmo (target), un objeto genérico como mejor individuo de su especie (bestParent) y un indicador de aptitud del mejor de los individuos (bestFitness).
Luego tenemos 5 métodos, método start para iniciar el algoritmo, un método createParent que creará el primero de la especie al cual le he incluido un parámetro por si quisiéramos determinar alguna particularidad sobre él, un método mutate que mutará un objeto en otro, un método getFitness que obtiene la aptitud y por último otro método booleano que determina si el algoritmo ha cumplido su objetivo (isSuccess).La interface ICrossOver hereda de esta añadiéndole un método más llamado crossOver con dos parámetros o padre y madre del objeto resultante.Si ahora creamos una clase que implemente esta interface, nos aseguramos que como mínimo tendremos que desarrollar los elementos de la interface, más fácil imposible. ¿Dónde tenemos que estrujarnos el cerebro? en diseñar el tipo de cromosoma, el objetivo como debe alcanzarse o en como debe mutar. No es poco, pero si tienes poca experiencia con algoritmos genéticos, esta es tu interface.

En la práctica, vamos a generar un algoritmo sencillo que adivine una frase. Esto tan fácil como crear una clase que implemente IMutable y en nuestro IDE nos aparecerá en rojo indicándonos que algo mal. La mayoría de los IDE,s tiene un asistente, una bombilla, una herramienta, un algo que al pulsar sobre él nos indica que algo está pasando y este dirá «implement as constructor parameters», seleccionamos las propiedades y et voilá, propiedades en la clase, pulsamos de nuevo y nos dirá implement members.

genetics01.jpg.png

Al pulsar, seleccionamos todos lo métodos y clase lista. Ahora el código

genetics02.png
Y aquí la clase con su código, esta solo mutará por tanto implementa IMutable, donde el algoritmo intentará adivinar unos preciosos versos de Mario Benedetti «Corazón coraza» con 334 caracteres.
El algoritmo creará una cadena aleatoria inicialmente e irá mutando hasta llegar al objetivo deseado.

class GuessString (override val target: Double, override val geneset: String) : IMutable{
    val guess = "Porque te tengo y no porque te pienso\n" +
            "porque la noche está de ojos abiertos\n" +
            "porque la noche pasa y digo amor\n" +
            "porque has venido a recoger tu imagen\n" +
            "y eres mejor que todas tus imágenes\n" +
            "porque eres linda desde el pie hasta el alma\n" +
            "porque eres buena desde el alma a mí\n" +
            "porque te escondes dulce en el orgullo\n" +
            "pequeña y dulce\n" +
            "corazón coraza"
    override var bestParent: String = createParent(guess.length)
    override var bestFitness: Double = getFitness(bestParent)
    private var attempts = 0

    init {
        start()
    }

    override fun start()
    {
        var childFitness: Double
        var child: String

        do {
            do {
                child = mutate(bestParent)
                childFitness = getFitness(child)
            } while (bestFitness >= childFitness)

            bestFitness = childFitness
            bestParent = child
            attempts ++
        } while (!isSuccess())
        println("Intentos: $attempts")
    }

    override fun isSuccess(): Boolean {
        val value = (bestFitness.toString().toDouble() / guess.length)
        return value >= target
    }

    override fun createParent(param: Any) : String {
        val genes = StringBuilder()
        val length = geneset.length
        (0 until param.toString().toInt()).forEach {
            genes.append(geneset[Random.nextInt(length)])
        }

        return genes.toString()
    }

    override fun getFitness(obj: String): Double = guess.mapIndexed { i, c -> if (c==obj[i]) 1.0 else 0.0}.sum()

    override fun mutate(parent: String): String {
        var index = 0
        val parentFitness: Double = getFitness(parent)
        var childFitness = 0.0

        var newGene: Char
        var alternate: Char
        var definitive: Char
        var indexGeneset: Int
        var child: String

        var length =  geneset.length

        do {
            index = Random.nextInt(parent.length)
            indexGeneset = Random.nextInt( length)

            newGene = geneset[indexGeneset]

            indexGeneset = Random.nextInt( length)
            alternate = geneset[indexGeneset]
            //definitivo
            definitive = if (newGene == parent[index]) alternate else newGene

            child = parent.replaceRange(index,index+1, definitive.toString())

            childFitness = getFitness(child)

        } while (parentFitness >= childFitness)

        return child
    }
}

fun main() {
val guess =GuessString(
        1.0,
        " áéíóúabcdefghijklmnñopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,\n")
println(guess.bestParent)
}

Y el resultado

Intentos: 328
Porque te tengo y no porque te pienso
porque la noche está de ojos abiertos
porque la noche pasa y digo amor
porque has venido a recoger tu imagen
y eres mejor que todas tus imágenes
porque eres linda desde el pie hasta el alma
porque eres buena desde el alma a mí
porque te escondes dulce en el orgullo
pequeña y dulce
corazón coraza

Pues aquí tenéis mi interface para algoritmos genéticos.
En el próximo post, veremos un algoritmo genético que posicionará las piezas de ajedrez en su sitio.
Pd: En realidad, la clase de adivinar no es gran cosa, porque se podría haber conseguido por iteración, pero entonces no habriáis aprendido el algortimo genético. Entonces, espero que os haya servido. 😉
Podía haber elegido a Antonio Machado a Calderón de la Barca o a cualquier otro poeta o poema, pero, este me parece especialmente bello. Leedlo completo, es corto, tres estrofas.
Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.

Interfaces

Interfaces

Cuando se empieza a programar, el uso de interfaces es un poco abstracto ya que no se le ve utilidad, pero las interfaces son de los más útiles. ¿Qué es una interface? es un contrato por el que una clase se ve obligada a cumplir en todos sus términos. Es decir, la interface contiene métodos y propiedades y cuando una clase implementa esta interface, la clase debe tener absolutamente todos los métodos y todas las propiedades que la interface le ha dicho.

Un objeto en la mayoría de los lenguajes, solo puede heredar de una clase, pero si puede implementar varias interfaces.

Un ejemplo. Quiero crear una colección de figuras de ajedrez; si quisiera ordenar la colección por valor y color en el que las negras valiesen más, al usar el método sort(), orderby() o el que sea, el objeto como mínimo deberá contener algún método que use ese método para ordenar sus elementos, compararlos y decidir cual va primero y cual después, ¿no?, pues yo lo que haría sería por ejemplo en Kotlin, es que la clase FiguraAjedrez implemente la interface Comparable (lo normal es que las interfaces, dependen del lenguaje comiencen por I, pero todas acaben con -able) que a su vez contiene un método compareTo.

Pues si la FiguraAjedrez tiene ese método, la colección cuando use el método sort encontrará el método compareTo donde nosotros escribiremos nuestro código, comparamos por el valor de la figura y le añadimos un extra por el color.

También, cuando pasamos como argumento una interface, nos estamos asegurando que el objeto que se pasa cumple con las expectativas. En C# si pasamos como argumento en un método un objeto del tipo IEnumerable, no estamos asegurando que el objeto que se pasa, tiene como mínimo un enumerador y que pude moverse por los elementos de la colección. O si le pasamos como argumento la interface IList, nos estamos asegurando que esta interface está heredando de ICollection, IEnumerable<T> e IEnumerable, de modo que puede moverse por sus elementos, puede borrar la colección, añadir, eliminar objetos, saber si tiene un objeto en la colección y hacer copias, todo esto. En Kotlin pasa algo parecido con la interface MutableList que hereda de las interfaces List y MutableCollection para hacer estas mismas acciones y algunas más.

        private static void Foo(IList collection)
        {
            // Do something
        }
         fun  foo(collection: MutableList){
            // Do something
         }

A continuación vamos ver un ejemplo de interface y de una clase que la implemente

interface IChessPiece: Comparable{
    fun doSomething()
    fun move()
    val isBlack: Boolean
    val value: Int
    val piece: String
}
class ChessPiece(override val piece: String, override val isBlack: Boolean, override val value: Int) : IChessPiece {
    override fun doSomething() {
        TODO("Not yet implemented")
    }

    override fun move() {
        TODO("Not yet implemented")
    }

    override fun compareTo(other: ChessPiece): Int {
        // Aqui incluimos el código de comparación
    }

}

fun foo(chessPiece: IChessPiece){

}

En el ejemplo, vemos que la interface IChessPiece implementa IComparable, así que podremos comparar objetos con otros del mismo tipo y luego le añadimos algunas propiedades y métodos, así que la clase ChessPiece obligatoriamente, debe tener cada uno de los métodos y propiedades establecidos en la interface.
En el método foo pasamos como argumento un objeto que implemente la interface, ASEGURANDO que va a hacer y va a tener lo que queremos que haga y que tenga. si mañana cambiamos el código de la clase o creamos una nueva con más funciones, lo que nos importa para que se entienda con el resto del código es que cumpla como mínimo con lo esperado.Usa las interfaces, sobre todo en los modelos y viewmodel, más tarde te alegraras enormemente.
Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.

My Golden Class

My Golden Class

Repasando un problema de @diegorattaggi y #mathiratti sobre φ el número áureo, el cual intenté mediante artificios matemáticos aprovechando las propiedades de las potencias del número aúreo sin llegar a resolverlo, se me ocurrió hacerlo por fuerza bruta, es decir iterando cada uno de los términos hasta conseguir resultados. En vano, solo obtuve un resultado para m=7 y n=5 y además no podía prosperar en cuanto las cifras crecían en número de dígitos. (El problema es bello, pero para resolverlo matemáticamente.)

Luego me acordé de este otro problema y me propuse mejorar la clase que desarrollé para ejecutar la fuerza bruta del problema anterior.

Aprovechando que es una clase nueva, he eliminado cualquier rastro de fuerza bruta y le he incluido algunas mejoras como por ejemplo :

  1. Número infinito de decimales de φ
  2. Cálculo de potencias de φ en función de los elementos de la sucesión de Fibonacci, más rápido y más preciso
  3. Cálculo de raices cuadradas para el tipo BigDecimal, para obtener infinitos decimales de φ.
  4. Obtención de la sucesión de Fibonacci n, como no. (Hasta Fib (315.000) y creo que haciendo algunos ajustes en el compilador de Intellij, alguno más caerá). Le he incluido una versión secursiva y otra iterativa, la función recursiva es mucho más eficiente gracias a la palabra clave modificadora de función tailrec de kotlin,el cual al incluirlo delante de una función recursiva, el compilador la trata como si fuera iterativa convirtiendo la función en un ciclo rápido y muy eficiente, alucinante.
  5. Obtención de un elemento concreto de la sucesión

Y ahora estamos preparados para atacar el problema con software, aunque a mi me gusta más hacerlo con matemáticas. Lo primero la clase con Kotlin

import java.math.BigDecimal
import java.math.BigInteger
import java.math.RoundingMode

class Phi {
    var decimals = 10
    val  TWO= 2.toBigDecimal()
    val  FIVE= 5.toBigDecimal()
    val  SQRTFIVE= sqrt(FIVE)

    val value: BigDecimal
        get() = (BigDecimal.ONE + SQRTFIVE).divide(TWO, decimals, RoundingMode.HALF_DOWN)
    private val fibonacci = mutableListOf()

    init {
        fibonacci.clear()
    }

    private fun calculateFibonacci(n: Int) {
        fibonacci.clear()
        fibonacciRecursive(n.toBigDecimal())
    }

    private fun sqrt(value: BigDecimal, scale: Int=decimals): BigDecimal {
        var x0 = BigDecimal("0")
        var x1 = BigDecimal(kotlin.math.sqrt(value.toDouble()))
        while (x0 != x1) {
            x0 = x1
            x1 = value.divide(x0, scale, RoundingMode.HALF_UP)
            x1 = x1.add(x0)
            x1 = x1.divide(TWO, scale, RoundingMode.HALF_UP)
        }
        return x1
    }

    private tailrec fun fibonacciRecursive(n: BigDecimal, a: BigDecimal = BigDecimal.ZERO, b: BigDecimal = BigDecimal.ONE) {
        fibonacci.add(b)
        when (n) {
            BigDecimal.ZERO -> a
            BigDecimal.ONE -> b
            else -> fibonacciRecursive(n - BigDecimal.ONE, b, a.add(b))
        }
    }

    private fun checkSucession(n:Int) { if (fibonacci.size < n) calculateFibonacci(n)}

    fun fibonacciIterator(n: Int): BigDecimal{
        var l = BigDecimal.ONE
        var lm1 = BigDecimal.ONE
        for (i in 3..n){
            var tmp = l
            l += lm1
            lm1 = tmp
        }
        return l
    }

    fun pow(n: Int) : BigDecimal {
        checkSucession(n)
        return fibonacci[n - 1] * value + fibonacci[n - 2]
    }

    fun fibonacciExplicitItem(n: Int): BigInteger = (getPhi(decimals).pow(n) - (BigDecimal.ONE - value).pow(n)).divide(sqrt(FIVE), decimals, RoundingMode.HALF_DOWN).toBigInteger()

    fun fibonacciItem(n: Int): BigDecimal {
        checkSucession(n)
        return fibonacci[n-1]
    }


    fun fibonacci(n: Int): List {
        checkSucession(n)
        return fibonacci;
    }

    fun sumInverse(n: Int): BigDecimal{
        val pn = value.pow(n)
        return when (n % 2){
            0 -> pn.toBigInteger().toBigDecimal() + BigDecimal.ONE
            1 -> pn.toBigInteger().toBigDecimal()
            else -> BigDecimal.ZERO
        }
    }

    override fun toString(): String {
        return value.toString()
    }

    fun getPhi(decimals:Int): BigDecimal = (BigDecimal.ONE + sqrt(FIVE, decimals )).divide(TWO)

    fun getPhiToString(decimals:Int): String {
        val phi = getPhi(decimals).toString()
        val text : StringBuilder= StringBuilder()
        text.append("1.\n")
        val phi2 = phi.removePrefix("1.")
        phi2.forEachIndexed { index, c ->
            when {
                index % 100 == 0 && index > 0 -> text.append("\t$index:\n$c")
                index % 10 == 0  && index > 0 -> text.append(" $c")
                else -> text.append(c)
            }
        }
        text.append("\t$decimals:")
        return text.toString()
    }
}

Y para iniciar, vamos a ver como funciona

import java.math.BigDecimal
import kotlin.system.measureTimeMillis

fun main(args: Array){
val n = 100000
val power = 1500
val phi = Phi()

val t1 = measureTimeMillis { println("phi: ${phi.getPhi(100000)}") }
println("$n decimals of Phi. Duration: $t1")
val t2 = measureTimeMillis { "Fibonacci($n): ${phi.fibonacci(n)}" }
println("Fibonacci($n). Duration: $t2")
val t3 = measureTimeMillis { println("Fibonacci($n): ${phi.fibonacciItem(n)}") }
println("FibonacciItem($n). Duration: $t3")
val t4 = measureTimeMillis { println("Phi^$power: ${phi.pow(power)}") }
println("Phi^$power. Duration: $t4")
}
  1. Instancia de la clase
  2. Obtenemos el número φ con 100.000 decimales
  3. Obtenemos la sucesión de Fibonacci para n=100.000
  4. Obtenemos el elemento 100.000 de la sucesión de Fibonacci
  5. Elevamos φ a la potencia 1500

Resultado

Phi: 1.618033988... 100.000 decimals ...8836739749559326107
100000 decimals of Phi. Duration: 2601ms
Fibonacci(100000). Duration: 143044ms
Fibonacci(100000): 259740693472217 ... 20.900 digits ... 5699780289236362349895374653428746875
FibonacciItem(100000). Duration: 1ms
Phi^1500: 30301238166550805786929189390145575626423967452224056329446235918567465318942832927313669458439880439962733393211656583769182495024464042800878040985094292794417098116786924311826550387756605278028834211153418987752560366539982408518048936164775701203049457214716895381907861202507701229899701575192565697255980968.78939750000
Phi^1500. Duration: 1ms

Pues para el montón de dígitos, sin paralelismo y lo que conseguimos, Kotlin vuelve a conquistarme.

Para terminar resolvamos el segundo problema

val t1 = measureTimeMillis {
val phi3 = phi.pow(3)
val phi5 = phi.pow(5)
val phi6 = phi.pow(6)
val phi8 = phi.pow(8)

val result =
(phi3 + ((phi3 + ((phi3 + phi5) / (BigDecimal.ONE - phi8))) / (BigDecimal.ONE - ((phi6 + phi8) / (BigDecimal.ONE - phi8))))) /
(((phi6 + ((phi6 + phi8) / (BigDecimal.ONE - phi8))) / (BigDecimal.ONE - ((phi6 + phi8) / (BigDecimal.ONE - phi8)))) - BigDecimal.ONE)
println("Result: $result")
}
println("Result. Duration: $t1")

20200723_155641.jpg

El resultado rápido y preciso y sobretodo, bello en sí. Las matemáticas lo son.

Result: 1.00000000000
Result. Duration: 3ms

Saludos y gracias @diegorattaggi

Pd: El post de Arithmos sobre la cantidad de dígitos de los elementos de la sucesión de Fibonacci, está implementada con esta clase y con buena nota

Las imágenes han sido descargadas del perfil de @diegorattaggi.