Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
110 views
in Technique[技术] by (71.8m points)

Testing Markov chains in Java

I have been given a question where I am supposed to write a Java function that implements the markov chain and returns an array of its probabilities. I have looked at both these questions, case 1 and case 2 which are relevant in solving my question based on the title. Both cases use java. Case 2's voted answer may involve knowledge of linear algebra of which I have only the essentials and I do not know how to implement Case 1's voted answer into code. The challenge is as follows:

Doomsday challenge

Making fuel for the LAMBCHOP's reactor core is a tricky process because of the exotic matter involved. It starts as raw ore, then during processing, begins randomly changing between forms, eventually reaching a stable form. There may be multiple stable forms that a sample could ultimately reach, not all of which are useful as fuel.

Commander Lambda has tasked you to help the scientists increase fuel creation efficiency by predicting the end state of a given ore sample. You have carefully studied the different structures that the ore can take and which transitions it undergoes. It appears that, while random, the probability of each structure transforming is fixed. That is, each time the ore is in 1 state, it has the same probabilities of entering the next state (which might be the same state). You have recorded the observed transitions in a matrix. The others in the lab have hypothesized more exotic forms that the ore can become, but you haven't seen all of them.

Write a function solution(m) that takes an array of array of nonnegative ints representing how many times that state has gone to the next state and return an array of ints for each terminal state giving the exact probabilities of each terminal state, represented as the numerator for each state, then the denominator for all of them at the end and in simplest form. The matrix is at most 10 by 10. It is guaranteed that no matter which state the ore is in, there is a path from that state to a terminal state. That is, the processing will always eventually end in a stable state. The ore starts in state 0. The denominator will fit within a signed 32-bit integer during the calculation, as long as the fraction is simplified regularly.

Below is the code (link above) of case 1 by Guy Wiks on this site.
Case 1

import java.util.ArrayList;
import java.util.Arrays;

public class trial34 {
    public static int[] solution(int[][] m) {
        double[][] mDouble = toDouble(m);
        //TODO: change the double back into an int
        // GOAL ONE: find Q matrix :
        // 1:seperate the input into two 2d arrays
        ArrayList<double[]> ters = new ArrayList<double[]>();
        ArrayList<double[]> nonTers = new ArrayList<double[]>();
        for (int i = 0; i < mDouble.length; i++) {
            boolean isTerminal = true;
            int sum = 0;
            for (int j = 0; j < mDouble[0].length; j++) {
                sum += mDouble[i][j];
                if (mDouble[i][j] != 0) {
                    isTerminal = false;
                }
            }

            if (isTerminal) {
                ters.add(mDouble[i]);
            } else {
                for (int j = 0; j < mDouble[0].length; j++) {
                    mDouble[i][j] = mDouble[i][j] / sum;
                }
                nonTers.add(mDouble[i]);
            }
        }
        double[][] terminalStates = new double[ters.size()][m.length];
        double[][] nonTerminalStates = new double[nonTers.size()][m.length];

        for (int i = 0; i < ters.size(); i++) {
            terminalStates[i] = ters.get(i);
        }
        for (int i = 0; i < nonTers.size(); i++) {
            nonTerminalStates[i] = nonTers.get(i);
        }
        // 2: Plug into a function that will create the 2d array
        double[][] QMatrix = getQMatrix(nonTerminalStates);
        // GOAL TWO: find I matrix
        double[][] IMatrix = makeIMatrix(QMatrix.length);
        //GOAL 3: Find F matrix
        //1: subtract the q matrix from the I matrix
        double[][] AMatrix = SubtractMatrices(IMatrix, QMatrix);
        //2: find the inverse TODO WRITE FUNCTION
        double[][] FMatrix = invert(AMatrix);
        //GOAL 4: multiply by R Matrix
        //1: find r Matrx
        double[][] RMatrix = getRMatrix(nonTerminalStates, terminalStates.length);
        //2: use multiply function to get FR Matrix
        double[][] FRMatrix = multiplyMatrices(FMatrix, RMatrix);
        //GOAL 5: find answer array
        //1: get the one dimensional answer
        double[] unsimplifiedAns = FRMatrix[0];
        //2: get fractions for the answers
        int[] ans = fractionAns(unsimplifiedAns);
        return ans;
    }

    public static int[] fractionAns(double[] uAns) {
        int[] ans = new int[uAns.length + 1];
        int[] denominators = new int[uAns.length];
        int[] numerators = new int[uAns.length];
        for (int i = 0; i < uAns.length; i++) {
            denominators[i] = (int) (convertDecimalToFraction(uAns[i])[1]);
            numerators[i] = (int) (convertDecimalToFraction(uAns[i])[0]);
        }
        int lcm = (int) lcm_of_array_elements(denominators);
        for (int i = 0; i < uAns.length; i++) {
            ans[i] = numerators[i] * (lcm / convertDecimalToFraction(uAns[i])[1]);
        }
        ans[ans.length - 1] = lcm;
        return ans;
    }

    static private int[] convertDecimalToFraction(double x) {
        double tolerance = 1.0E-10;
        double h1 = 1;
        double h2 = 0;
        double k1 = 0;
        double k2 = 1;
        double b = x;
        do {
            double a = Math.floor(b);
            double aux = h1;
            h1 = a * h1 + h2;
            h2 = aux;
            aux = k1;
            k1 = a * k1 + k2;
            k2 = aux;
            b = 1 / (b - a);
        } while (Math.abs(x - h1 / k1) > x * tolerance);

        return new int[]{(int) h1, (int) k1};
    }

    public static long lcm_of_array_elements(int[] element_array) {
        long lcm_of_array_elements = 1;
        int divisor = 2;

        while (true) {
            int counter = 0;
            boolean divisible = false;

            for (int i = 0; i < element_array.length; i++) {

                // lcm_of_array_elements (n1, n2, ... 0) = 0.
                // For negative number we convert into
                // positive and calculate lcm_of_array_elements.

                if (element_array[i] == 0) {
                    return 0;
                } else if (element_array[i] < 0) {
                    element_array[i] = element_array[i] * (-1);
                }
                if (element_array[i] == 1) {
                    counter++;
                }

                // Divide element_array by devisor if complete
                // division i.e. without remainder then replace
                // number with quotient; used for find next factor
                if (element_array[i] % divisor == 0) {
                    divisible = true;
                    element_array[i] = element_array[i] / divisor;
                }
            }

            // If divisor able to completely divide any number
            // from array multiply with lcm_of_array_elements
            // and store into lcm_of_array_elements and continue
            // to same divisor for next factor finding.
            // else increment divisor
            if (divisible) {
                lcm_of_array_elements = lcm_of_array_elements * divisor;
            } else {
                divisor++;
            }

            // Check if all element_array is 1 indicate
            // we found all factors and terminate while loop.
            if (counter == element_array.length) {
                return lcm_of_array_elements;
            }
        }
    }

    public static double[][] toDouble(int[][] ma) {
        double[][] retArr = new double[ma.length][ma.length];
        for (int i = 0; i < retArr.length; i++) {
            for (int j = 0; j < retArr[0].length; j++) {
                retArr[i][j] = (ma[i][j]);
            }
        }
        return retArr;
    }

    public static double[][] getRMatrix(double[][] nonTerminals, int terminalLength) {
        double[][] retArr = new double[nonTerminals.length][terminalLength];
        for (int i = 0; i < retArr.length; i++) {
            for (int j = nonTerminals.length; j < nonTerminals[0].length; j++) {
                retArr[i][j - nonTerminals.length] = (nonTerminals[i][j]);
            }
        }
        return retArr;
    }

    public static double[][] multiplyMatrices(double[][] firstMatrix, double[][] secondMatrix) {
        int r1 = firstMatrix.length;
        int c1 = firstMatrix[0].length;
        int c2 = secondMatrix[0].length;
        double[][] product = new double[r1][c2];
        for (int i = 0; i < r1; i++) {
            for (int j = 0; j < c2; j++) {
                for (int k = 0; k < c1; k++) {
                    product[i][j] += firstMatrix[i][k] * secondMatrix[k][j];
                }
            }
        }

        return product;
    }

    public static double[][] inverseMatrix(double[][] Amatrix) {
        return null;
    }

    public static double[][] SubtractMatrices(double[][] I, double[][] Q) {
        double[][] retArr = new double[I.length][I.length];
        for (int i = 0; i < retArr.length; i++) {
            for (int j = 0; j < retArr.length; j++) {
                retArr[i][j] = I[i][j] - Q[i][j];
            }
        }
        return retArr;
    }

    public static double[][] getQMatrix(double[][] qArr) {
        int size = qArr.length;
        double[][] retArr = new double[size][size];
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                retArr[i][j] = qArr[i][j];
            }
        }
        return retArr;
    }

    public static double[][] makeIMatrix(int size) {
        double[][] retArr = new double[size][size];
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (i == j) {
                    retArr[i][j] = 1;
                } else {
                    retArr[i][j] = 0;
                }
            }
        }
        return retArr;
    }

    public static double[][] invert(double a[][]) {
        int n = a.length;
        double x[][] = new double[n][n];
        double b[][] = new double[n][n];
        int index[] = new int[n];
        for (int i = 0; i < n; ++i)
            b[i][i] = 1;

        // Transform the matrix into an upper triangle
        gaussian(a, index);

        // Update the matrix b[i][j] with the ratios stored
        for (int i = 0; i < n - 1; ++i)
            for (int j = i + 1; j < n; ++j)
                for (int k = 0; k < n; ++k)
                    b[index[j]][k]
                            -= a[index[j]][i] * b[index[i]][k];

        // Perform backward substitutions
        for (int i = 0; i < n; ++i) {
            x[n - 1][i] = b[index[n - 1]][i] / a[index[n - 1]][n - 1];
            for (int j = n - 2; j >= 0; --j) {
                x[j][i] = b[index[j]][i];
                for (int k = j + 1; k < n; ++k) {
                    x[j][i] -= a[index[j]][k] * x[k][i];
                }
      

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...