Revelando el Intrigante Arte de la Ruleta: Desentrañando el Hack de la Cadena de Markov

(1/1)

profinet:
Saludos a la comunidad apasionada de la ruleta. Hoy, me complace compartir con ustedes un fascinante enfoque que ha capturado la atención de los entusiastas del juego y los amantes de las estrategias ingeniosas: el hack de la cadena de Markov en la ruleta. ¿Qué sucede cuando la probabilidad se encuentra con la emoción del juego? La respuesta yace en la asombrosa intersección entre la teoría de la cadena de Markov y la rueda giratoria del destino.

Antes de sumergirnos en los detalles, tomémonos un momento para apreciar la magia que impulsa este hack. La cadena de Markov, conocida por su capacidad para modelar sistemas estocásticos, se convierte en una aliada inesperada en el universo impredecible de la ruleta. ¿Será esta la clave para desbloquear patrones ocultos en la ruleta? Descubramos juntos si este hack es un truco astuto o una revelación genuina.

LA CADENA DE MARKOV

Una cadena de Markov es un modelo matemático que describe una secuencia de eventos donde la probabilidad de que ocurra un evento particular depende solo del evento inmediatamente anterior. Es decir, en una cadena de Markov, el futuro solo está condicionado por el presente, y no retiene información sobre el pasado más allá del último estado.

Matemáticamente, la propiedad de Markov se expresa de la siguiente manera:


portal foto

En palabras simples, esta fórmula indica que la probabilidad de pasar al estado s en el próximo paso, dado el estado actual st, no depende de la secuencia completa de estados anteriores, sino solo del estado actual.

LA MATRIZ DE TRANSICIÓN

La matriz de transición, P, es una matriz que representa las probabilidades de transición entre los estados de una cadena de Markov. En una cadena con n estados, P es una matriz n×n, y Pij​ representa la probabilidad de pasar del estado i al estado j.

portal foto

CÁLCULO DEL VECTOR DE ESTADOS

Si tenemos un vector de probabilidades inicial vt​ en el paso t, la actualización del vector de probabilidades al paso t+1 se realiza multiplicando el vector por la matriz de transición P.


portal foto

EL CÓDIGO!

Código
/* ROULETTE MARKOV CHAIN SIMULATION by profinet
 
 In the ethereal realm of Markov chains, we delve into the enchanting world
 of probabilities governing the game of Roulette. Before we unveil the magic
 woven by this C program, let's unravel the mathematical essence of a Markov chain.
 
 MARKOV CHAIN:
 
 A Markov chain is a stochastic model that describes a sequence of events where
 the probability of transitioning to any particular state depends solely on the
 current state and time elapsed, not on the sequence of events that preceded it.
 This memoryless property is known as the Markov property.
 
 - State Space: Sets A, B, C, and D represent the states in our Roulette Markov
 chain. Each state corresponds to a range of numbers on the Roulette wheel.
 
 - Transition Probabilities: The heart of the Markov chain lies in the probabilities
 of transitioning from one state to another. These probabilities form a transition
 matrix, where each element signifies the likelihood of moving between states.
 
 - Transition Matrix: A square matrix where rows and columns correspond to states,
 and each entry represents the probability of transitioning from one state to another.
 In our Roulette context, this matrix captures the dynamics of the game over spins.
 
 - Markov Property: The future state of the system depends only on its current state,
 adhering to the Markov property. The dynamics of the system are memoryless,
 simplifying the modeling of random processes.
 
 Now, armed with the knowledge of Markov chains, let's witness the magic of
 probabilities and state transitions as we simulate the dance of fate on the
 Roulette wheel with this enchanting C program.
 
 INITIAL STATE VECTOR CALCULATION:
 
 Before embarking on our magical journey through the Roulette Markov chain,
 let's decipher the incantation that conjures the initial state vector, v0.
 
 The mystical probabilities for each zone are as follows:
 - Zone A: 1/37 = 0.02702702702
 - Zone B [1-12]: 1/37 * 12 = 0.32432432432
 - Zone C [13-24]: 1/37 * 12 = 0.32432432432
 - Zone D [25-36]: 1/37 * 12 = 0.32432432432
 
 Therefore, the initial state vector v0 is crafted with these probabilities:
 v0 = { 0.02702702702, 0.32432432432, 0.32432432432, 0.32432432432 }
 
 This vector sets the stage for our journey, representing the initial likelihood
 of finding ourselves in each enchanted zone after the first spin of the Roulette wheel.
 
 Now, let the magic unfold as we traverse the Markov chain, weaving the threads
 of destiny and revealing the ever-shifting cosmic energies within the enchanted lands.
 
 THE DARK SPIRIT SCRIPT:
 
 Legend has it that sets A, B, C, and D correspond to specific ranges of numbers
 on the Roulette wheel. Zone A encompasses the single number 0, while zones B, C,
 and D represent ranges [1-12], [13-24], and [25-36], respectively.
 
 Then, the script unfolds as follows:
 
 1. A sample array of mystical symbols is presented, representing the outcome
 of a Roulette game.
 
 2. The `countSpecificTransitions` function takes the mystical sample array and
 counts transitions between sets A, B, C, and D. The ancient spirits are
 summoned to calculate the probabilities of weaving the threads of destiny
 from one set to another.
 
 3. The calculated probabilities are then used to build a powerful transition
 matrix with the `buildTransitionMatrix` function. Each element of the matrix
 represents the likelihood of moving from one enchanted zone to another.
 
 4. The transition matrix is unveiled to mortal eyes through the `printMatrix`
 function, revealing the hidden patterns and cosmic energies.
 
 5. A mystical ritual is performed with the `multiplyMatrixVector` function,
 combining the powers of the sacred matrix and a humble vector. The result is
 a new vector that holds the secrets of transformation, representing the
 probabilities of ending up in each enchanted zone after a Roulette spin.
 
 May the ancient spirits guide you through the script, and may the probabilities
 revealed here bring fortune and wisdom to those who seek the mystical insights
 of the Roulette wheel.
 
 Best of luck on your magical journey! */
 
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
 
/**
 * @brief Count specific transitions in the sample and calculate transition probabilities.
 *
 * This magical function takes a mystical sample array and counts the transitions between
 * enchanted sets A, B, C, and D. It then summons the ancient spirits to calculate the
 * probabilities of weaving the threads of destiny from one set to another.
 *
 * @param sample The magical sample array containing mystical symbols.
 * @param size The size of the sample array (the length of your magical journey).
 * @param counters The counters representing the cosmic energies of transitions.
 * @param probabilities The probabilities of weaving the threads of destiny between sets.
 */
static void countSpecificTransitions(int sample[], int size, int *counters,
double *probabilities) {
int i, j, k;
 
// Define the sets
int sets[][12] = { { 0 },                                       // A
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 },     // B
{ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }, // C
{ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36 }   // D
};
 
// Wipe off counters
for (i = 0; i < 16; i++) {
counters[i] = 0;
probabilities[i] = 0.0;
}
 
// Let's go on a magical journey through the sample array
for (i = 0; i < size - 1; i++) {
int currentSet = -1;
int nextSet = -1;
 
// Seeking the meaning of life in the current set
for (j = 0; j < 4; j++) {
for (k = 0; k < 12; k++) {
/* If our sample number aligns
* with the mystical symbols in the current set */
if (sample[i] == sets[j][k]) {
// We've found it!
currentSet = j;
break;
}
}
/* If we've already found the meaning of life
* there's no need to keep searching */
if (currentSet != -1) {
break;
}
}
 
// Gazing into the crystal ball to find the next set
for (j = 0; j < 4; j++) {
for (k = 0; k < 12; k++) {
if (sample[i + 1] == sets[j][k]) {
nextSet = j;
break;
}
}
if (nextSet != -1) {
break;
}
}
 
// Summoning the ancient spirits to increment the counters
if (currentSet != -1 && nextSet != -1) {
/* We're not just incrementing counters;
* we're weaving the threads of destiny! */
counters[currentSet * 4 + nextSet]++;
}
}
 
// Let's do some magic math
int totalTransitions = size - 1;
for (i = 0; i < 16; i++) {
probabilities[i] = (double) counters[i] / totalTransitions;
}
}
 
/**
 * @brief Build the transition matrix using mystical probabilities.
 *
 * This function takes a set of magical probabilities and weaves them into a powerful
 * transition matrix. Each element of the matrix represents the likelihood of moving
 * from one enchanted zone to another.
 *
 * @param matrix The matrix that will be imbued with magical probabilities.
 * @param probabilities The mystical probabilities, carefully chosen by sorcery.
 */
static void buildTransitionMatrix(double matrix[4][4], double *probabilities) {
/* Fill the matrix with the provided probabilities
* creating a tapestry of transitions */
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
matrix[i][j] = probabilities[i * 4 + j];
}
}
}
 
/**
 * @brief Normalizes a matrix and tries to make it feel like it fits in.
 *
 * This function takes a matrix and makes each row behave, by subtracting a bit from each element.
 * Think of it as matrix therapy - we're helping them get along better with their row-mates.
 *
 * @param N The size of the matrix.
 * @param matrix The matrix to normalize.
 */
static void normalizeMatrix(int N, double matrix[N][N]) {
   for (int i = 0; i < N; i++) {
       double rowSum = 0.0;
 
       /* Finding the sum of the row
         * - because everyone needs to know their worth! */
       for (int j = 0; j < N; j++) {
           rowSum += matrix[i][j];
       }
 
       /* Subtracting (rowSum - 1) / N from every value in this row
         * - just a little adjustment therapy */
       for (int j = 0; j < N; j++) {
           matrix[i][j] -= (rowSum - 1) / N;
       }
   }
}
 
/**
 * @brief Checks if a matrix is living its best stochastic life.
 *
 * This function takes a matrix and interrogates its rows to see if they're all adding up to 1.
 * It's like a reality show for matrices - if they're not pulling their weight, they're out!
 *
 * @param N The size of the matrix.
 * @param matrix The matrix to investigate.
 * @return Returns true if the matrix is living the stochastic dream, false otherwise.
 */
static bool isStochasticMatrix(int N, double matrix[N][N]) {
   for (int i = 0; i < N; i++) {
       double rowSum = 0.0;
 
       /* Calculating the sum of the current row
         * - because each row is a unique individual */
       for (int j = 0; j < N; j++) {
           rowSum += matrix[i][j];
       }
 
       /* Checking if the sum is approximately equal to 1
         * - because a row that adds up to 1 is a happy row! */
       if (fabs(rowSum - 1.0) > 1e-6) {
           return false;
       }
   }
 
   // The matrix is living its best life!
   return true;
}
 
/**
 * @brief Cast a spell to reveal the mystical matrix.
 *
 * This function is a magical incantation that unleashes the enchanted matrix
 * into the mortal realm. It gracefully prints the ethereal values with precision,
 * allowing mere mortals to catch a glimpse of the hidden patterns.
 *
 * @param matrix The mystical matrix to be unveiled.
 */
static void printMatrix(double matrix[4][4]) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
// Reveal the magical values with four decimal places
printf("%.4f ", matrix[i][j]);
}
// Move to the next line, as the magic unfolds row by row
printf("\n");
}
}
 
/**
 * @brief Unleash the magic of matrix-vector multiplication.
 *
 * This function is a mystical ritual that combines the powers of a sacred matrix
 * and a humble vector. It gracefully performs the multiplication, weaving the
 * threads of destiny to produce a new vector that holds the secrets of transformation.
 *
 * @param matrix The sacred matrix, carefully crafted by the wizards of computation.
 * @param inputVector The humble vector offering itself to the magic of multiplication.
 * @param resultVector The newborn vector, now imbued with the enchanted transformation.
 */
static void multiplyMatrixVector(double matrix[4][4], double *inputVector,
double *resultVector) {
for (int i = 0; i < 4; i++) {
// Prepare the newborn vector, clearing any remnants of previous enchantments
resultVector[i] = 0.0;
for (int j = 0; j < 4; j++) {
// Unleash the magic: combine the powers of matrix and vector
resultVector[i] += matrix[i][j] * inputVector[j];
}
}
}
 
/**
 * @brief Normalizes a vector and makes its elements feel like they're on a diet.
 *
 * This magical function takes a vector on a sumptuous feast and says, "Enough is enough!"
 * It calculates the sum of the elements, scolds them for overindulgence, and puts them on
 * a strict diet by dividing each element by the sum. Now, the vector is light, fit, and ready
 * for the runway – or any mathematical adventure!
 *
 * @param vector The vector to be normalized, because even vectors need to watch their weight.
 * @param size The size of the vector – because size matters, especially in the world of vectors.
 */
void normalizeVector(double *vector, int size) {
   double sum = 0.0;
 
   // Calculate the sum of the elements – a grand feast awaits!
   for (int i = 0; i < size; i++) {
       sum += vector[i];
   }
 
   // Normalize by dividing each element by the sum of the elements
   for (int i = 0; i < size; i++) {
       vector[i] /= sum;
   }
}
 
 
/**
 * @brief Generates a random list of numbers to keep life exciting.
 *
 * This function is your go-to party planner for creating a list that's as unpredictable as life itself.
 * It seeds the random number generator with the current time, ensuring a unique and lively mix every time.
 *
 * @param list The list to be filled with random numbers.
 * @param size The size of the list - because size matters, especially in random number lists.
 */
static void generateRandomList(int *list, int size) {
   // Let's throw a dice and see where the randomness takes us!
   srand((unsigned int) time(NULL));
 
   // Generating random numbers and filling the list with excitement
   for (int i = 0; i < size; i++) {
      /* Generating a random number between 0 and 36
        * - because variety is the spice of life! */
    list[i] = rand() % 37;
   }
}
 
/**
 * @brief Embark on a magical journey through the enchanted realms of sets A, B, C, and D.
 *
 * This mystical main function leads a daring expedition into the unseen world of transitions
 * and probabilities. A sample array of mystical symbols is presented to the ancient wizards
 * who count specific transitions, unveil the secrets of probability, and build a powerful
 * transition matrix. The enchanted matrix is then used to transform an initial state vector
 * into a new state, revealing the ever-shifting cosmic energies within the enchanted lands.
 *
 * @return The triumphant return code, signifying the successful completion of the magical journey.
 */
int main() {
   // Sample array
   int initialData[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };
   int size = (int)sizeof(initialData) / sizeof(initialData[0]);
 
   // Declare and allocate memory for the sample array
   int *sample = (int *)malloc(size * sizeof(int));
 
   // Check if memory allocation was successful
   if (sample == NULL) {
       fprintf(stderr, "Memory allocation failed :(\n");
       return 1; // Return an error code
   }
 
   // Initialize sample array with default values
   for (int i = 0; i < size; i++) {
       sample[i] = i;
   }
 
   // Initialize counters and probabilities
   int counters[16];
   double probabilities[16];
 
   int i = 0;
   int winningBet = 0;
 
   do {
       // Count specific transitions
       countSpecificTransitions(sample, size, counters, probabilities);
 
       // Print the results
       printf("\n");
       for (i = 0; i < 16; i++) {
           char currentSet = (char)('A' + i / 4);
           char nextSet = (char)('A' + i % 4);
 
           printf("Transition %c->%c: %d, Probability: %.4f\n", currentSet, nextSet, counters[i], probabilities[i]);
       }
 
       // Build the transition matrix
       double transitionMatrix[4][4];
       buildTransitionMatrix(transitionMatrix, probabilities);
       if (!isStochasticMatrix(4, transitionMatrix)) {
           normalizeMatrix(4, transitionMatrix);
       }
 
       // Print the transition matrix
       printf("\nTransition Matrix:\n");
       printMatrix(transitionMatrix);
 
       // Build the new state vector
       double initialState[4] = {0.02702702702, 0.32432432432, 0.32432432432, 0.32432432432};
       double newState[4];
       multiplyMatrixVector(transitionMatrix, initialState, newState);
 
       // Normalize the new state vector
       normalizeVector(newState, 4);
 
       // Print the new state vector with corresponding zones and intervals
       printf("\nNew state vector:\n");
       for (i = 0; i < 4; i++) {
           char zoneLabel;
           const char *intervalDescription;
 
           // Determine the zone label and interval description
           switch (i) {
           case 0:
               zoneLabel = 'A';
               intervalDescription = "Only 0 ";
               break;
           case 1:
               zoneLabel = 'B';
               intervalDescription = "[1-12] ";
               break;
           case 2:
               zoneLabel = 'C';
               intervalDescription = "[13-24]";
               break;
           case 3:
               zoneLabel = 'D';
               intervalDescription = "[25-36]";
               break;
           default:
               // Handle an unexpected index (this should not happen)
               zoneLabel = '?';
               intervalDescription = "Unknown Interval";
               break;
           }
 
           // Print the probability along with zone and interval information
           printf("Zone %c %s -> %.3f%%\n", zoneLabel, intervalDescription, (double)newState[i] * 100);
       }
 
       printf("\nEnter a new winningBet (or any non-integer to exit): ");
       if (scanf("%d", &winningBet) != 1) {
           break;
       }
 
       // Update the sample array with the new winningBet
       // (For simplicity, just add the winningBet to the end of the array
       sample = realloc(sample, (size + 1) * sizeof(int));
       if (sample == NULL) {
           fprintf(stderr, "Memory reallocation failed :(\n");
           return 1; // Return an error code
       }
       sample[size] = winningBet;
       size++;
 
   } while (1);
 
   // Free the allocated memory
   free(sample);
 
   // The triumphant return code!
   return 0;
}
 



portal foto

Serapis:
Pues si te resulta interesante las cadenas de Markov, te recomiendo que explores el algoritmo de Viterbi... que trata precisamente con modelos ocultos de Markov (HMM).

Navegación

[0] Índice de Mensajes