Below is my matrix code, I want to fill the gaps with unique numbers. But I can't figure out why it doesn't work. I tried going step by step in it but I can't seem to figure where I have made a mistake. So, the thing is, I have a given 9 x 9 matrix with some numbers in it, and I want to complete the rest of it with unique numbers so that every line and column there is all numbers from 1 to 9 but different on each column / row.
Please help me, thank you!
package com.javagement;
import java.util.Random;
public class Main {
public static void main(String[] args) {
int[][] matriceBuni = new int[9][9];
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
matriceBuni[i][j] = 0;
}
}
matriceBuni[0][0] = 8;
matriceBuni[0][4] = 6;
matriceBuni[0][8] = 4;
matriceBuni[1][2] = 7;
matriceBuni[1][4] = 3;
matriceBuni[1][8] = 5;
matriceBuni[2][0] = 3;
matriceBuni[2][1] = 9;
matriceBuni[2][5] = 5;
matriceBuni[2][7] = 8;
matriceBuni[3][2] = 8;
matriceBuni[3][3] = 6;
matriceBuni[3][6] = 7;
matriceBuni[3][7] = 5;
matriceBuni[4][2] = 5;
matriceBuni[4][3] = 8;
matriceBuni[4][7] = 9;
matriceBuni[5][1] = 6;
matriceBuni[5][2] = 3;
matriceBuni[5][5] = 7;
matriceBuni[5][6] = 4;
matriceBuni[6][0] = 7;
matriceBuni[6][1] = 3;
matriceBuni[6][3] = 2;
matriceBuni[6][5] = 9;
matriceBuni[7][0] = 1;
matriceBuni[7][1] = 8;
matriceBuni[7][7] = 5;
matriceBuni[7][8] = 9;
matriceBuni[8][4] = 8;
matriceBuni[8][5] = 1;
matriceBuni[8][6] = 2;
for(int m = 0; m < 9; m++) {
for(int n = 0; n < 9; n++) {
System.out.print(matriceBuni[m][n] + " ");
}
System.out.println();
}
System.out.println("*****************************************");
for(int r = 0; r < 9; r++) {
for(int c = 0; c < 9; c++) {
if(matriceBuni[r][c] == 0) {
boolean isUnique = false;
while(!isUnique) {
int uniqueNumber = getRandomNumberInRange(1,9);
int countUnique = 0;
for(int a = 0; a < 9; a++) {
if (matriceBuni[r][a] == uniqueNumber) {
countUnique++;
}
}
for(int b = 0; b < 9; b++) {
if (matriceBuni[b][c] == uniqueNumber) {
countUnique++;
}
}
if (countUnique == 0) {
isUnique = true;
matriceBuni[r][c] = uniqueNumber;
}
}
}
}
}
for(int m = 0; m < 9; m++) {
for (int n = 0; n < 9; n++) {
System.out.print(matriceBuni[m][n] + " ");
}
System.out.println();
}
}
private static int getRandomNumberInRange(int min, int max) {
Random r = new Random();
return r.nextInt((max - min) + 1) + min;
}
}
Related
The program should multiply 2 matrices 4x1 and 1x4 and output the result to the console (matrix 4X4). But nothing displays. What's the problem?
public class Matrix {
public static void main(String[] args) {
int[][] matrixA = new int[4][1];
int[][] matrixB = new int[1][4];
int[][] matrixC = new int[4][4];
matrixA[0][0] = 1;
matrixA[1][0] = 2;
matrixA[2][0] = 3;
matrixA[3][0] = 4;
matrixB[0][0] = 4;
matrixB[0][1] = 3;
matrixB[0][2] = 2;
matrixB[0][3] = 1;
for (int i = 0; i < 4; i++) { // A rows
for (int j = 0; j < 4; j++) { // B columns
for (int k = 0; k < 1; k++) { // A columns
matrixC[i][j] += matrixA[i][k] * matrixB[k][j];
System.out.print(matrixC[i][j] + " ");
}
}
}
int j = 0;
for (int i = 0; i < 4; i++) {
for (int k = 0; k < 1; k++)
System.out.print(matrixC[i][j] + " ");
System.out.println();
}
} //end main
} //end class
You introduced a variable j before your second set of for loops. Also, even if they're optional, I would highly recommend always including braces. And k < 4. Like,
for (int i = 0; i < 4; i++) {
for (int k = 0; k < 4; k++) {
System.out.print(matrixC[i][k] + " "); // not [i][j]
}
System.out.println();
}
or just use Arrays.deepToString(Object[]) like
System.out.println(Arrays.deepToString(matrixC));
Hope this helps:
public class Matrix {
public static void main(String[] args) {
int[][] matrixA = {{1}, {2}, {3}, {4}};
int[][] matrixB = {{4, 3, 2, 1}};
int[][] matrixC = new int[4][4];
for (int i = 0; i < 4; i++) { // A rows
for (int j = 0; j < 4; j++) { // B columns
for (int k = 0; k < 1; k++) { // A columns
matrixC[i][j] += matrixA[i][k] * matrixB[k][j];
System.out.print(matrixC[i][j] + " ");
}
}
System.out.println();
}
}
}
Output:
4 3 2 1
8 6 4 2
12 9 6 3
16 12 8 4
Trying to write a method that swaps the rows of a 2D array in order of increasing row sum.
For example, if I have the following 2d array:
int [][] array = {4,5,6},{3,4,5},{2,3,4};
I would want it to output an array as so:
{2 3 4}, {3 4 5}, {4 5 6}
Methodology:
a.) take the sums of each row and make a 1D array of the sums
b.) do a bubble sort on rowSum array
c.) swap the rows of the original array based on the bubble sort swaps made
d.) then print the newly row sorted array.
Here's my code so far:
public void sortedArrayByRowTot() {
int [][] tempArray2 = new int [salaryArray.length [salaryArray[0].length];
for (int i = 0; i < tempArray2.length; i++) {
for (int j = 0; j < tempArray2[i].length; j++) {
tempArray2[i][j] = salaryArray[i][j];
}
}
int [] rowSums = new int [tempArray2.length];
int sum = 0;
for (int i = 0; i < tempArray2.length; i++) {
for (int j = 0; j < tempArray2[i].length; j++) {
sum += tempArray2[i][j];
}
rowSums[i] = sum;
sum = 0;
}
int temp;
int i = -1;
for(int j = rowSums.length; j > 0; j--){
boolean isSwap = false;
for (i = 1; i < j; i++) {
if(rowSums[i-1] > rowSums[i]) {
temp = rowSums[i-1];
rowSums[i-1] = rowSums[i];
rowSums[i] = temp;
isSwap = true;
}
}
if(!isSwap){
break;
}
}
for (int k = 0; k < tempArray2.length; k++) {
temp = tempArray2[i-1][k];
tempArray2[i-1][k] = tempArray2[i][k];
tempArray2[i][k] = temp;
}
for (int b = 0; b < tempArray2.length; b++) {
for (int c = 0; c < tempArray2[b].length; c++) {
System.out.print(tempArray2[b][c] + " ");
}
}
}
}
Not sure if I am doing part c of my methodology correctly?
It keeps saying "Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2"
As #shmosel said, you can do it like this:
public static void sortedArrayByRowTot() {
int [][] array = {{4,5,6},{3,4,5},{2,3,4}};
Arrays.sort(array, Comparator.comparingInt(a -> IntStream.of(a).sum()));
}
I was able to solve my question. Thanks.
public void sortedArrayByRowTot() {
//Creates tempArray2 to copy salaryArray into
int [][] tempArray2 = new int [salaryArray.length][salaryArray[0].length];
//Copies salaryArray into tempArray2
for (int i = 0; i < salaryArray.length; i++) {
for (int j = 0; j < salaryArray[i].length; j++) {
tempArray2[i][j] = salaryArray[i][j];
}
}
//Creates rowSum array to store sum of each row
int [] rowSums = new int [tempArray2.length];
for (int i = 0; i < tempArray2.length; i++) {
for (int j = 0; j < tempArray2[0].length; j++) {
rowSums[i] += tempArray2[i][j];
}
}
//Modified Bubble Sort of rowSum array (highest to lowest values)
int temp;
int i = 0;
for(int j = rowSums.length; j > 0; j--){
boolean isSwap = false;
for (i = 1; i < j; i++) {
if(rowSums[i-1] < rowSums[i]) {
temp = rowSums[i-1];
rowSums[i-1] = rowSums[i];
rowSums[i] = temp;
isSwap = true;
//swaps rows in corresponding tempArray2
int [] temp2 = tempArray2[i-1];
tempArray2[i-1] = tempArray2[i];
tempArray2[i] = temp2;
}
}
if(!isSwap){
break;
}
}
//Prints sorted array
System.out.println("Sorted array: ");
for (i = 0; i < tempArray2.length; i++) {
for (int j = 0; j < tempArray2[i].length; j++) {
System.out.print("$"+ tempArray2[i][j] + " ");
}
System.out.println();
}
}
You may try this way. That I have solved.
public class Solution{
public static void sortedArrayByRowTot() {
int [][] salaryArray = { {4,5,6},{3,4,5},{2,3,4} };
int [][] tempArray2 = new int [salaryArray.length][salaryArray[0].length];
for (int i = 0; i < salaryArray.length; i++) {
for (int j = 0; j < salaryArray[i].length; j++) {
tempArray2[i][j] = salaryArray[i][j];
}
}
// Buble Sort to store rowSums
int [] rowSums = new int [tempArray2.length];
for (int i = 0; i < tempArray2.length; i++) {
for (int j = 0; j < tempArray2[0].length; j++) {
rowSums[i] += tempArray2[i][j];
}
}
//Buble Sort by Rows Sum (Lowest Value to Highest)
int temp;
int i = 0;
for(int j = rowSums.length; j > 0; j--){
boolean isSwap = false;
for (i = 1; i < j; i++) {
if(rowSums[i-1] > rowSums[i]) {
temp = rowSums[i-1];
rowSums[i-1] = rowSums[i];
rowSums[i] = temp;
isSwap = true;
//swaps rows in corresponding tempArray2
int [] temp2 = tempArray2[i-1];
tempArray2[i-1] = tempArray2[i];
tempArray2[i] = temp2;
}
}
if(!isSwap){
break;
}
}
/** No Need.
for (int k = 0; k < tempArray2.length; k++) {
temp = tempArray2[i-1][k];
tempArray2[i-1][k] = tempArray2[i][k];
tempArray2[i][k] = temp;
}
*/
for (int b = 0; b < tempArray2.length; b++) {
for (int c = 0; c < tempArray2[b].length; c++) {
System.out.print(tempArray2[b][c] + " ");
}
}
}
public static void main(String[] args) {
sortedArrayByRowTot();
}
}
I have to build Simplex Algorithm and its working but I want to allow user to input data, in method main I made few "for" loops where I put date into arrays, but that I put the same data in another arrays, (they have exactly the same data) I have no idea how to fix it.
When I try to make just one arrays for one type of date, it's crash.
[edit]
Yep, I update those Scanners (thanks guys)
And right now I have this error:
"Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at simplex.Simplex$Modeler.(Simplex.java:224)
at simplex.Simplex.main(Simplex.java:196)"
package simplex;
import java.awt.List;
import java.util.ArrayList;
import java.util.Scanner;
public class Simplex {
private double[][] macierz; // macierz
private int LiczbaOgraniczen; // liczba ograniczen
private int LiczbaX; // liczba zmiennych "orginalnych"
private boolean MaxCzyMin;
private static final boolean MAX = true;
private static final boolean MIN = false;
private int[] baza; // baza[i] = basic variable corresponding to row i
public Simplex(double[][] macierz, int LiczbaOgraniczen, int numberOfOriginalVariable, boolean MaxCzyMin) {
this.MaxCzyMin = MaxCzyMin;
this.LiczbaOgraniczen = LiczbaOgraniczen;
this.LiczbaX = numberOfOriginalVariable;
this.macierz = macierz;
baza = new int[LiczbaOgraniczen];
for (int i = 0; i < LiczbaOgraniczen; i++)
baza[i] = LiczbaX + i;
Licz();
}
// Licz algorytm simples od startowych BFS
private void Licz() {
while (true) {
DrukujInteracje();
int q = 0;
// znajdz kolumne q wchodzącą do bazy
if (MaxCzyMin) {
q = ZnajdzIndexPoz(); //jesli szukamy max
} else {
q = ZnajdzIndexNeg(); //jesli szukamy min
}
if (q == -1){
break; // optimum
}
// znajdz rzad p wychodzący z bazy
int p = minRatioRule(q);
if (p == -1){
throw new ArithmeticException("BLAD");
}
//wiersz - kolumna
piwot(p, q);
// zaktualizuj baze
baza[p] = q;
}
}
// znajdowanie indexu niebazowej kolumny z najbardzoje pozytywnym kosztem
private int ZnajdzIndexPoz() {
int q = 0;
for (int j = 1; j < LiczbaOgraniczen + LiczbaX; j++)
if (macierz[LiczbaOgraniczen][j] > macierz[LiczbaOgraniczen][q])
q = j;
if (macierz[LiczbaOgraniczen][q] <= 0){
return -1; // optimum
} else {
return q;
}
}
// znajdowanie indexu niebazowej kolumny z najbardziej negatywnym kosztem
private int ZnajdzIndexNeg() {
int q = 0;
for (int j = 1; j < LiczbaOgraniczen + LiczbaX; j++)
if (macierz[LiczbaOgraniczen][j] < macierz[LiczbaOgraniczen][q])
q = j;
if (macierz[LiczbaOgraniczen][q] >= 0){
return -1; // optimum
} else {
return q;
}
}
// find row p using min ratio rule (-1 if no such row)
private int minRatioRule(int q) {
int p = -1;
for (int i = 0; i < LiczbaOgraniczen; i++) {
if (macierz[i][q] <= 0)
continue;
else if (p == -1)
p = i;
else if ((macierz[i][LiczbaOgraniczen
+ LiczbaX] / macierz[i][q]) < (macierz[p][LiczbaOgraniczen
+ LiczbaX] / macierz[p][q]))
p = i;
}
return p;
}
//zastosowanie metody Gauss-Jordan, aby doprowadzic macierz do postaci bazowej
private void piwot(int p, int q) {
for (int i = 0; i <= LiczbaOgraniczen; i++)
for (int j = 0; j <= LiczbaOgraniczen + LiczbaX; j++)
if (i != p && j != q)
macierz[i][j] -= macierz[p][j] * macierz[i][q] / macierz[p][q];
for (int i = 0; i <= LiczbaOgraniczen; i++)
if (i != p)
macierz[i][q] = 0.0;
for (int j = 0; j <= LiczbaOgraniczen + LiczbaX; j++)
if (j != q)
macierz[p][j] /= macierz[p][q];
macierz[p][q] = 1.0;
}
// Metoda zwraca wartosc funkcji celu
public double WartoscFunkcjiCelu() {
return -macierz[LiczbaOgraniczen][LiczbaOgraniczen + LiczbaX];
}
// metoda zwaraca wartosc x-ow
public double[] WyliczX() {
double[] x = new double[LiczbaX];
for (int i = 0; i < LiczbaOgraniczen; i++)
if (baza[i] < LiczbaX)
x[baza[i]] = macierz[i][LiczbaOgraniczen + LiczbaX];
return x;
}
// drukuj macierz => drukuj tabele
public void DrukujInteracje() {
System.out.println("Liczba Ograniczen = " + LiczbaOgraniczen);
System.out.println("Liczba zmiennych 'orginalnych' = " + LiczbaX);
for (int i = 0; i <= LiczbaOgraniczen; i++) {
for (int j = 0; j <= LiczbaOgraniczen
+ LiczbaX; j++) {
System.out.printf("%7.2f ", macierz[i][j]);
}
System.out.println();
}
System.out.println("Funkcja celu = " + WartoscFunkcjiCelu());
for (int i = 0; i < LiczbaOgraniczen; i++)
if (baza[i] < LiczbaX)
System.out.println("x_"
+ baza[i]
+ " = "
+ macierz[i][LiczbaOgraniczen + LiczbaX]);
System.out.println();
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Podaj ilosc x");
int iloscX = scan.nextInt();
double[] WspolczynnikiFunkcjiCelu = new double[iloscX + 1];
for(int ggg = 0; ggg < iloscX; ggg++){
System.out.println("Podaj x" + ggg);
WspolczynnikiFunkcjiCelu[ggg] =scan.nextDouble();
}
System.out.println("Podaj ilosc ograniczen");
int iloscOgraniczen = scan.nextInt();
double[][] LewaStronaOgraniczen = new double[iloscOgraniczen][iloscX];
double[] PrawaStronaOgraniczen = new double[iloscOgraniczen + 1];
Znaki[] OperatorOgraniczen = new Znaki [iloscOgraniczen + 1];
for(int ggh = 0;ggh <iloscOgraniczen; ggh++){
System.out.println("Podaj znak ograniczenia (lessThan - equal - greatherThan ");
OperatorOgraniczen[ggh] = Znaki.valueOf(scan.next());
System.out.println("Podaj prawa strone ograniczenia");
PrawaStronaOgraniczen[ggh] = scan.nextDouble();
for(int haha = 0; haha < iloscX; haha++){
System.out.println("Lewa strona: Podaj wspolczynnik przy x" + haha);
LewaStronaOgraniczen[ggh][haha] =scan.nextDouble();
}
}
//double[] WspolczynnikiFunkcjiCelu = {Xsy[0], Xsy[1]};
// double[][] LewaStronaOgraniczen = {
// { TablicaTablic[0][0], TablicaTablic[0][1] }, { TablicaTablic[1][0], TablicaTablic[1][1] }, { TablicaTablic[2][0], TablicaTablic[2][1] }, { TablicaTablic[3][0], TablicaTablic[3][1] } };
//Znaki[] OperatorOgraniczen = { TablicaOgraniczen[0], TablicaOgraniczen[1], TablicaOgraniczen[2], TablicaOgraniczen[3] };
//double[] PrawaStronaOgraniczen = {TablicaPrawejStrony[0],TablicaPrawejStrony[1],TablicaPrawejStrony[2],TablicaPrawejStrony[3]};
Modeler model = new Modeler(LewaStronaOgraniczen, PrawaStronaOgraniczen, OperatorOgraniczen, WspolczynnikiFunkcjiCelu);
Simplex simplex = new Simplex(model.getmacierz(),
model.getLiczbaOgraniczen(),
model.getLiczbaX(), MAX);
double[] x = simplex.WyliczX();
for (int i = 0; i < x.length; i++)
System.out.println("x[" + i + "] = " + x[i]);
System.out.println("Rozwiazanie optymalne: " + simplex.WartoscFunkcjiCelu());
}
//zbior mozliwych znakow ograniczajacych
private enum Znaki {
lessThan, equal, greatherThan
}
public static class Modeler {
private double[][] a; // macierz
private int LiczbaOgraniczen; // Liczba Ograniczen
private int LiczbaX; // Liczba x w funkcji celu
public Modeler(double[][] LewaStronaOgraniczen,double[] PrawaStronaOgraniczen, Znaki[] OperatorOgraniczen, double[] WspolczynnikiFunkcjiCelu) {
LiczbaOgraniczen = PrawaStronaOgraniczen.length;
LiczbaX = WspolczynnikiFunkcjiCelu.length;
a = new double[LiczbaOgraniczen + 1][LiczbaX + LiczbaOgraniczen + 1];
for (int i = 0; i < LiczbaOgraniczen; i++) {
for (int j = 0; j < LiczbaX; j++) {
a[i][j] = LewaStronaOgraniczen[i][j];
}
}
for (int i = 0; i < LiczbaOgraniczen; i++)
a[i][LiczbaOgraniczen + LiczbaX] = PrawaStronaOgraniczen[i];
for (int i = 0; i < LiczbaOgraniczen; i++) {
int slack = 0;
switch (OperatorOgraniczen[i]) {
case greatherThan:
slack = -1;
break;
case lessThan:
slack = 1;
break;
default:
}
a[i][LiczbaX + i] = slack;
}
for (int j = 0; j < LiczbaX; j++)
a[LiczbaOgraniczen][j] = WspolczynnikiFunkcjiCelu[j];
}
public double[][] getmacierz() {
return a;
}
public int getLiczbaOgraniczen() {
return LiczbaOgraniczen;
}
public int getLiczbaX() {
return LiczbaX;
}
}
}
why have you so many scanners? Try use only one. Declare and initialize it at the beginning main method.
I have a class which is :
public class CCTest {
public double f;
public double[][][] x;
public double counter;
};
and i have assigned random number to x,
CCTest[] cls = new CCTest[5];
for (int i = 0; i < cls.length; i++) {
cls[i] = new CCTest();
}
for (int i = 0; i < (Size = 5); i++) {
cls[i].x = new double[this.c][this.D][this.Size];
for (int j = 0; j < this.D; j++) {
cls[i].x = getRandomX(this.c, this.D, this.Size);
}
}
then I tried to display the result using :
public static void display(double[][][] array) {
int rows = array.length;
int columns = array[0].length;
int depth = array[0][0].length;
for (int d = 0; d < depth; d++) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
System.out.print(array[r][c][d] + " ");
}
System.out.println();
}
System.out.println();
}
}
The Random Generation method is :
public static double[][][] getRandomX(int x, int y, int z) {
double[][][] result = new double[x][y][z];
Random r = new Random();
for (int i = 0; i < z; i++) {
for (int j = 0; j < y; j++) {
for (int k = 0; k < x; k++) {
result[k][j][i] = r.nextDouble();
}
}
}
return result;
}
but the output is empty [] , any idea please
The inner loop : for (int j = 0; j < this.D; j++) {...} is useless so you can remove this.The display and getRandomX() functions are fine. Try this in main , works in my environment:
CCTest[] cls = new CCTest[5];
for (int i = 0; i < cls.length; i++) {
cls[i] = new CCTest();
}
for (int i = 0; i < (Size = 5); i++) {
cls[i].x = new double[c][D][S];
cls[i].x = getRandomX(c, D, S);
}
for (int i = 0; i < (Size = 5); i++) {
display(cls[0].x);
}
Your display method should rather look like:
public static void display(double[][][] array) {
for (int x = 0; x < array.length; x++) {
for (int y = 0; y < array[x].length; y++) {
for (int z = 0; z < array[x][y].length; z++) {
System.out.println(array[x][y][z]);
}
}
}
}
There is another question which comes to my mind. What is getRandomX? You haven't shown us. I'd use the following:
public static double[][][] getRandom3DArray(double[][][] array) {
Random r = new Random();
for (int x = 0; x < array.length; x++) {
for (int y = 0; y < array[x].length; y++) {
for (int z = 0; z < array[x][y].length; z++) {
array[x][y][z] = r.nextDouble();
}
}
}
return array;
}
You're mistaking rows with depth in your display.
I am trying to train a two-state Hidden Markov model with a scaled Baum-Welch, but I noticed when my emission sequence is too small. My probabilities turn to NaN in java. Is this normal? I have posted my code in java below:
import java.util.ArrayList;
/*
Scaled Baum-Welch Algorithm implementation
author: Ricky Chang
*/
public class HMModeltest {
public static double[][] stateTransitionMatrix = new double[2][2]; // State Transition Matrix
public static double[][] emissionMatrix; // Emission Probability Matrix
public static double[] pi = new double[2]; // Initial State Distribution
double[] scaler; // This is used for scaling to prevent underflow
private static int emissions_id = 1; // To identify if the emissions are for the price changes or spread changes
private static int numEmissions = 0; // The amount of emissions
private static int numStates = 2; // The number of states in hmm
public static double improvementVar; // Used to assess how much the model has improved
private static double genState; // Generated state, it is used to generate observations below
// Create an ArrayList to store the emissions
public static ArrayList<Integer> eSequence = new ArrayList<Integer>();
// Initialize H, emission_id: 1 is price change, 2 are spreads; count is for the amount of different emissions
public HMModeltest(int id, int count){
emissions_id = id;
numEmissions = count;
stateTransitionMatrix = set2DValues(numStates,numStates); // Give the STM row stochastic values
emissionMatrix = new double[numStates][numEmissions];
emissionMatrix = set2DValues(numStates,numEmissions); // Give the Emission probability matrix row stochastic values
pi = set1DValues(numStates); // Give the initial matrix row stochastic values
}
// Categorize the price change emissions; I may want to put these in the Implementation.
private int identifyE1(double e){
if( e == 0) return 4;
if( e > 0){
if(e == 1) return 5;
else if(e == 3) return 6;
else if(e == 5) return 7;
else return 8;
}
else{
if(e == -1) return 3;
else if(e == -3) return 2;
else if(e == -5) return 1;
else return 0;
}
}
// Categorize the spread emissions
private int identifyE2(double e){
if(e == 1) return 0;
else if(e == 3) return 1;
else return 2;
}
public void updateE(int emission){
if(emissions_id == 1) eSequence.add( identifyE1(emission) );
else eSequence.add( identifyE2(emission) );
}
// Used to intialize random row stochastic values to vectors
private double[] set1DValues(int col){
double sum = 0;
double temp = 0;
double [] returnVector = new double[col];
for(int i = 0; i < col; i++){
temp = Math.round(Math.random() * 1000);
returnVector[i] = temp;
sum = sum + temp;
}
for(int i = 0; i < col; i++){
returnVector[i] = returnVector[i] / sum;
}
return returnVector;
}
// Used to initialize random row stochastic values to matrices
public double[][] set2DValues(int row, int col){
double sum = 0;
double temp = 0;
double[][] returnMatrix = new double[row][col];
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
temp = Math.round(Math.random() * 1000);
returnMatrix[i][j] = temp;
sum = sum + temp;
}
for(int j = 0; j < col; j++){
returnMatrix[i][j] = returnMatrix[i][j] / sum;
}
sum = 0;
}
return returnMatrix;
}
// Use forward algorithm to calculate alpha for all states and times
public double[][] forwardAlgo(int time){
double alpha[][] = new double[numStates][time];
scaler = new double[time];
// Intialize alpha for time 0
scaler[0] = 0; // c0 is for scaling purposes to avoid underflow
for(int i = 0; i < numStates; i ++){
alpha[i][0] = pi[i] * emissionMatrix[i][eSequence.get(0)];
scaler[0] = scaler[0] + alpha[i][0];
}
// Scale alpha_0
scaler[0] = 1 / scaler[0];
for(int i = 0; i < numStates; i++){
alpha[i][0] = scaler[0] * alpha[i][0];
}
// Use recursive method to calculate alpha
double tempAlpha = 0;
for(int t = 1; t < time; t++){
scaler[t] = 0;
for(int i = 0; i < numStates; i++){
for(int j = 0; j < numStates; j++){
tempAlpha = tempAlpha + alpha[j][t-1] * stateTransitionMatrix[j][i];
}
alpha[i][t] = tempAlpha * emissionMatrix[i][eSequence.get(t)];
scaler[t] = scaler[t] + alpha[i][t];
tempAlpha = 0;
}
scaler[t] = 1 / scaler[t];
for(int i = 0; i < numStates; i++){
alpha[i][t] = scaler[t] * alpha[i][t];
}
}
System.out.format("scaler: ");
for(int t = 0; t < time; t++){
System.out.format("%f, ", scaler[t]);
}
System.out.print('\n');
return alpha;
}
// Use backward algorithm to calculate beta for all states
public double[][] backwardAlgo(int time){
double beta[][] = new double[2][time];
// Intialize beta for current time
for(int i = 0; i < numStates; i++){
beta[i][time-1] = scaler[time-1];
}
// Use recursive method to calculate beta
double tempBeta = 0;
for(int t = time-2; t >= 0; t--){
for(int i = 0; i < numStates; i++){
for(int j = 0; j < numStates; j++){
tempBeta = tempBeta + (stateTransitionMatrix[i][j] * emissionMatrix[j][eSequence.get(t+1)] * beta[j][t+1]);
}
beta[i][t] = tempBeta;
beta[i][t] = scaler[t] * beta[i][t];
tempBeta = 0;
}
}
return beta;
}
// Calculate the probability of emission sequence given the model (it is also the denominator to calculate gamma and digamma)
public double calcP(int t, double[][] alpha, double[][] beta){
double p = 0;
for(int i = 0; i < numStates; i++){
for(int j = 0; j < numStates; j++){
p = p + (alpha[i][t] * stateTransitionMatrix[i][j] * emissionMatrix[j][eSequence.get(t+1)] * beta[j][t+1]);
}
}
return p;
}
// Calculate digamma; i and j are both states
public double calcDigamma(double p, int t, int i, int j, double[][] alpha, double[][] beta){
double digamma = (alpha[i][t] * stateTransitionMatrix[i][j] * emissionMatrix[j][eSequence.get(t+1)] * beta[j][t+1]) / p;
return digamma;
}
public void updatePi(double[][] gamma){
for(int i = 0; i < numStates; i++){
pi[i] = gamma[i][0];
}
}
public void updateAll(){
int time = eSequence.size();
double alpha[][] = forwardAlgo(time);
double beta[][] = backwardAlgo(time);
double initialp = calcLogEProb(time);
double nextState0, nextState1;
double p = 0;
double[][][] digamma = new double[numStates][numStates][time];
double[][] gamma = new double[numStates][time];
for(int t = 0; t < time-1; t++){
p = calcP(t, alpha, beta);
for(int i = 0; i < numStates; i++){
gamma[i][t] = 0;
for(int j = 0; j < numStates; j++){
digamma[i][j][t] = calcDigamma(p, t, i, j, alpha, beta);
gamma[i][t] = gamma[i][t] + digamma[i][j][t];
}
}
}
updatePi(gamma);
updateA(digamma, gamma);
updateB(gamma);
alpha = forwardAlgo(time);
double postp = calcLogEProb(time);
improvementVar = postp - initialp;
}
// Update the state transition matrix
public void updateA(double[][][] digamma, double[][] gamma){
int time = eSequence.size();
double num = 0;
double denom = 0;
for(int i = 0; i < numStates; i++){
for(int j = 0; j < numStates; j++){
for(int t = 0; t < time-1; t++){
num = num + digamma[i][j][t];
denom = denom + gamma[i][t];
}
stateTransitionMatrix[i][j] = num/denom;
num = 0;
denom = 0;
}
}
}
public void updateB(double[][] gamma){
int time = eSequence.size();
double num = 0;
double denom = 0;
// k is an observation, j is a state, t is time
for(int i = 0; i < numStates; i++){
for(int k = 0; k < numEmissions; k++){
for(int t = 0; t < time-1; t++){
if( eSequence.get(t) == k) num = num + gamma[i][t];
denom = denom + gamma[i][t];
}
emissionMatrix[i][k] = num/denom;
num = 0;
denom = 0;
}
}
}
public double calcLogEProb(int time){
double logProb = 0;
for(int t = 0; t < time; t++){
logProb = logProb + Math.log(scaler[t]);
}
return -logProb;
}
public double calcNextState(int time, int state, double[][] gamma){
double p = 0;
for(int i = 0; i < numStates; i++){
for(int j = 0; j < numStates; j++){
p = p + gamma[i][time-2] * stateTransitionMatrix[i][j] * stateTransitionMatrix[j][state];
}
}
return p;
}
// Print parameters
public void print(){
System.out.println("Pi:");
System.out.print('[');
for(int i = 0; i < 2; i++){
System.out.format("%f, ", pi[i]);
}
System.out.print(']');
System.out.print('\n');
System.out.println("A:");
for(int i = 0; i < 2; i++){
System.out.print('[');
for(int j = 0; j < 2; j++){
System.out.format("%f, ", stateTransitionMatrix[i][j]);
}
System.out.print(']');
System.out.print('\n');
}
System.out.println("B:");
for(int i = 0; i < 2; i++){
System.out.print('[');
for(int j = 0; j < 9; j++){
System.out.format("%f, ", emissionMatrix[i][j]);
}
System.out.print(']');
System.out.print('\n');
}
System.out.print('\n');
}
/* Generate sample data to test HMM training with the following params:
* [ .3, .7 ]
* [ .8, .2 ] [ .45 .1 .08 .05 .03 .02 .05 .2 .02 ]
* [ .36 .02 .06 .15 .04 .05 .2 .1 .02 ]
* With these as observations: {-10, -5, -3, -1, 0, 1, 3, 5, 10}
*/
public static int sampleDataGen(){
double rand = 0;
rand = Math.random();
if(genState == 1){
if(rand < .3) genState = 1;
else genState = 2;
rand = Math.random();
if(rand < .45) return -10;
else if(rand < .55) return -5;
else if(rand < .63) return -3;
else if(rand < .68) return -1;
else if(rand < .71) return 0;
else if(rand < .73) return 1;
else if(rand < .78) return 3;
else if(rand < .98) return 5;
else return 10;
}
else {
if(rand < .8) genState = 1;
else genState = 2;
rand = Math.random();
if(rand < .36) return -10;
else if(rand < .38) return -5;
else if(rand < .44) return -3;
else if(rand < .59) return -1;
else if(rand < .63) return 0;
else if(rand < .68) return 1;
else if(rand < .88) return 3;
else if(rand < .98) return 5;
else return 10;
}
}
public static void main(String[] args){
HMModeltest test = new HMModeltest(1,9);
test.print();
System.out.print('\n');
for(int i = 0; i < 20; i++){
test.updateE(sampleDataGen());
}
test.updateAll();
System.out.print('\n');
test.print();
System.out.print('\n');
for(int i = 0; i < 10; i++){
test.updateE(sampleDataGen());
}
test.updateAll();
System.out.print('\n');
test.print();
System.out.print('\n');
}
}
My guess is that since the sample is too small, sometimes the probabilities don't exist for some observations. But it would be nice to have some confirmation.
You could refer the "Scaling" section in Rabiner's paper, which solves the underflow problem.
You could also do the calculations in log space, that's what HTK and R do. Multiplication and division become addition and subtraction. For the other two, look at the LAdd/ LSub and logspace_add/logspace_sub functions in the respective toolkits.
The log-sum-exp trick might be helpful too.