/* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille * * ludovic.apvrille AT enst.fr * * This software is a computer program whose purpose is to allow the * edition of TURTLE analysis, design and deployment diagrams, to * allow the generation of RT-LOTOS or Java code from this diagram, * and at last to allow the analysis of formal validation traces * obtained from external tools, e.g. RTL from LAAS-CNRS and CADP * from INRIA Rhone-Alpes. * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/ or redistribute the software under the terms of the CeCILL * license as circulated by CEA, CNRS and INRIA at the following URL * "http://www.cecill.info". * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided only * with a limited warranty and the software's author, the holder of the * economic rights, and the successive licensors have only limited * liability. * * In this respect, the user's attention is drawn to the risks associated * with loading, using, modifying and/or developing or reproducing the * software by the user in light of its specific status of free software, * that may mean that it is complicated to manipulate, and that also * therefore means that it is reserved for developers and experienced * professionals having in-depth computer knowledge. Users are therefore * encouraged to load and test the software's suitability as regards their * requirements in conditions enabling the security of their systems and/or * data to be ensured and, more generally, to use and operate it in the * same conditions as regards security. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL license and that you accept its terms. */ package myutil; import java.util.BitSet; import java.util.LinkedList; /** * Class IntMatrix * Creation: 06/02/2012 * Version 2.0 06/02/2012 * * @author Ludovic APVRILLE */ public class IntMatrix implements Runnable { public int[][] matrice; public int sizeRow; public int sizeColumn; private String[] nameOfRows; private long percentageCompletion; private boolean mustGo; private boolean noMultiplier; private boolean interrupted; private boolean finished; private boolean withHeuristics; public BitSet[] bitSetOfMatrix; public IntMatrix(int _sizeRow, int _sizeColumn) { matrice = new int[_sizeRow][_sizeColumn]; sizeRow = _sizeRow; sizeColumn = _sizeColumn; nameOfRows = new String[sizeRow]; for (int i = 0; i < sizeRow; i++) { nameOfRows[i] = "" + i; } } public long getPercentageCompetion() { return percentageCompletion; } public void setValue(int i, int j, int value) { matrice[i][j] = value; } public void setLineValues(int line, int[] values) { for (int j = 0; j < sizeColumn; j++) { matrice[line][j] = values[j]; } } public int getValue(int i, int j) { try { return matrice[i][j]; } catch (Exception e) { } return -1; } public int getNbOfLines() { return sizeRow; } public String getNameOfLine(int i) { return nameOfRows[i]; } public void putShortNames() { for (int i = 0; i < sizeRow; i++) { nameOfRows[i] = "" + i; } } public int getValueOfLine(int i) { int cpt = 0; for (int j = 0; j < sizeColumn; j++) { cpt += matrice[i][j]; } return cpt; } public int getValueOfLineFromColumn(int columnIndex, int i) { int cpt = 0; for (int j = columnIndex; j < sizeColumn; j++) { cpt += matrice[i][j]; } return cpt; } public void setNameOfLine(int line, String name) { try { nameOfRows[line] = name; } catch (Exception e) { } } public void setNamesOfLine(String[] names) { try { for (int i = 0; i < sizeRow; i++) { nameOfRows[i] = names[i]; } } catch (Exception e) { } } public String toString() { StringBuffer sb = new StringBuffer("Size:" + sizeRow + "x" + sizeColumn + ":\n"); for (int i = 0; i < sizeRow; i++) { sb.append("Row #" + i + " / " + nameOfRows[i] + ": "); for (int j = 0; j < sizeColumn; j++) { sb.append(" " + matrice[i][j]); } sb.append("\n"); } return sb.toString(); } public void swapLines(int line0, int line1) { int tmp; for (int j = 0; j < sizeColumn; j++) { tmp = matrice[line0][j]; matrice[line0][j] = matrice[line1][j]; matrice[line1][j] = tmp; } String tmpName = nameOfRows[line0]; nameOfRows[line0] = nameOfRows[line1]; nameOfRows[line1] = tmpName; } // Apply a division on all elements of a line public void unitLine(int line0, int diviser) { for (int j = 0; j < sizeColumn; j++) { matrice[line0][j] = matrice[line0][j] / diviser; } } // Combine line line0 minus m times line1 ; line0 gets the result public void linearCombination(int line0, int line1, int m) { //TraceManager.addDev("combination l0 = " + line0 + " line1 = " + line1 + " multiplier m=" + m); for (int j = 0; j < sizeColumn; j++) { matrice[line0][j] = matrice[line0][j] - (m * matrice[line1][j]); } } // Returns the line number at which there is the first non nul element of column col0 // Returns -1 in case none is found public int rgpivot(int col0, int nbOfLines) { int i = col0; while ((i < (nbOfLines)) && (matrice[i][col0] == 0)) { i++; } if (matrice[i][col0] == 0) { return 0; } else { return i; } } public IntMatrix clone() { IntMatrix im = new IntMatrix(sizeRow, sizeColumn); for (int i = 0; i < sizeRow; i++) { for (int j = 0; j < sizeColumn; j++) { im.matrice[i][j] = matrice[i][j]; } setNameOfLine(i, nameOfRows[i]); } return im; } public void concatAfter(IntMatrix im) { int tmp = sizeColumn; sizeColumn += im.sizeColumn; int[][] newMatrice = new int[sizeRow][sizeColumn]; for (int i = 0; i < sizeRow; i++) { for (int j = 0; j < sizeColumn; j++) { if (j < tmp) { newMatrice[i][j] = matrice[i][j]; } else { newMatrice[i][j] = im.matrice[i][j - tmp]; } } } matrice = newMatrice; } public int[] getLine(int lineIndex) { int[] line = new int[sizeColumn]; for (int j = 0; j < sizeColumn; j++) { line[j] = matrice[lineIndex][j]; } return line; } public String lineToString(int[] line) { String s = ""; for (int i = 0; i < line.length; i++) { s += line[i] + " "; } return s; } public String namesOfRowToString() { String s = ""; for (int i = 0; i < nameOfRows.length; i++) { s += nameOfRows[i] + "\n"; } return s; } // Add a line at the end of the matrix public void addLine(int[] newLine, String nameOfRow) { sizeRow++; int[][] newMatrice = new int[sizeRow][sizeColumn]; for (int j = 0; j < sizeColumn; j++) { for (int i = 0; i < sizeRow - 1; i++) { newMatrice[i][j] = matrice[i][j]; } newMatrice[sizeRow - 1][j] = newLine[j]; } matrice = newMatrice; String[] newNameOfRows = new String[sizeRow]; for (int k = 0; k < sizeRow - 1; k++) { newNameOfRows[k] = nameOfRows[k]; } if (nameOfRow == null) { newNameOfRows[sizeRow - 1] = "" + (sizeRow - 1); } else { newNameOfRows[sizeRow - 1] = nameOfRow; } nameOfRows = newNameOfRows; } public void addLines(LinkedList<IntLine> lines) { int oldSizeRow = sizeRow; sizeRow += lines.size(); int[][] newMatrice = new int[sizeRow][sizeColumn]; String[] newNameOfRows = new String[sizeRow]; for (int i = 0; i < oldSizeRow; i++) { for (int j = 0; j < sizeColumn; j++) { newMatrice[i][j] = matrice[i][j]; } newNameOfRows[i] = nameOfRows[i]; } matrice = newMatrice; nameOfRows = newNameOfRows; int cpt = oldSizeRow; for (IntLine il : lines) { matrice[cpt] = il.line; nameOfRows[cpt] = il.nameOfLine; cpt++; } } public void addLinesBitSet(LinkedList<IntLine> lines) { int oldSizeRow = sizeRow; sizeRow += lines.size(); int[][] newMatrice = new int[sizeRow][sizeColumn]; String[] newNameOfRows = new String[sizeRow]; BitSet[] newBitSetOfMatrix = new BitSet[sizeRow]; for (int i = 0; i < oldSizeRow; i++) { for (int j = 0; j < sizeColumn; j++) { newMatrice[i][j] = matrice[i][j]; } newNameOfRows[i] = nameOfRows[i]; newBitSetOfMatrix[i] = bitSetOfMatrix[i]; } matrice = newMatrice; nameOfRows = newNameOfRows; bitSetOfMatrix = newBitSetOfMatrix; int cpt = oldSizeRow; for (IntLine il : lines) { matrice[cpt] = il.line; nameOfRows[cpt] = il.nameOfLine; bitSetOfMatrix[cpt] = il.bs; cpt++; } } public void removeLine(int lineIndex) { sizeRow--; int[][] newMatrice = new int[sizeRow][sizeColumn]; for (int i = 0; i < sizeRow + 1; i++) { for (int j = 0; j < sizeColumn; j++) { if (i < lineIndex) { newMatrice[i][j] = matrice[i][j]; } else { if (i > lineIndex) { newMatrice[i - 1][j] = matrice[i][j]; } } } } matrice = newMatrice; String[] newNameOfRows = new String[sizeRow]; int dec = 0; for (int k = 0; k < sizeRow + 1; k++) { if (k != lineIndex) { newNameOfRows[k - dec] = nameOfRows[k]; } else { dec++; } } nameOfRows = newNameOfRows; } public void makeID() { for (int i = 0; i < sizeRow; i++) { for (int j = 0; j < sizeColumn; j++) { if (i == j) { matrice[i][j] = 1; } else { matrice[i][j] = 0; } } } } // noMultiplier indicates whether names of lines may contain the "*" sign, or not. public void Farkas(boolean noMultiplier) { int sizeColumBeforeConcat = sizeColumn; IntMatrix idMat = new IntMatrix(sizeRow, sizeRow); idMat.makeID(); concatAfter(idMat); //int[] lined1, lined2, lined; int[] lined; int gcd; int l, i; String s0, s1; String nameOfNewLine; int cpt; int total = 0; int tmpSizeRow; LinkedList<IntLine> ll = new LinkedList<IntLine>(); for (int j = 0; j < sizeColumBeforeConcat; j++) { // Loop on lines to add line combinations tmpSizeRow = sizeRow; for (i = 0; i < tmpSizeRow - 1; i++) { //lined1 = getLine(i); //tmpSizeRow = sizeRow; for (int k = i + 1; k < tmpSizeRow; k++) { percentageCompletion = total++; if (mustGo == false) { interrupted = true; return; } //TraceManager.addDev("Computing k=" + k + " " + sizeRow + "x" + sizeColumn); //lined2 = getLine(k); // lines d1 and 2 have opposite signs? //if (((lined1[j] < 0) && (lined2[j]>0)) || ((lined1[j]>0) && (lined2[j]<0))) { if (((matrice[i][j] < 0) && (matrice[k][j] > 0)) || ((matrice[i][j] > 0) && (matrice[k][j] < 0))) { lined = new int[sizeColumn]; for (l = 0; l < lined.length; l++) { lined[l] = Math.abs(matrice[k][j]) * matrice[i][l] + Math.abs(matrice[i][j]) * matrice[k][l]; } if (Math.abs(matrice[k][j]) == 1) { s0 = nameOfRows[i] + " + "; } else { if (noMultiplier) { s0 = nameOfRows[i] + " + "; for (cpt = Math.abs(matrice[k][j]); cpt > 1; cpt--) { s0 += nameOfRows[i] + " + "; } } else { s0 = "" + Math.abs(matrice[k][j]) + "*(" + nameOfRows[i] + ") + "; } } if (Math.abs(matrice[i][j]) == 1) { s1 = nameOfRows[k]; } else { if (noMultiplier) { s1 = nameOfRows[k]; for (cpt = Math.abs(matrice[i][j]); cpt > 1; cpt--) { s1 += " +" + nameOfRows[k]; } } else { s1 = "" + Math.abs(matrice[i][j]) + "*(" + nameOfRows[k] + ") + "; } } //TraceManager.addDev("Name of line=" + s0 + "/" + s1); nameOfNewLine = s0 + s1; gcd = MyMath.gcd(lined); //TraceManager.addDev("gcd =" + gcd + " of line =" + lineToString(lined) + " i.e.:" + nameOfNewLine); if (gcd != 0) { for (l = 0; l < lined.length; l++) { lined[l] = lined[l] / gcd; } } ll.add(new IntLine(lined, nameOfNewLine)); //addLine(lined, nameOfNewLine); //TraceManager.addDev("matafterline=\n" + toString() + "\n\n"); } } } TraceManager.addDev("Adding lines, size=" + sizeRow + "x" + sizeColumn); addLines(ll); ll.clear(); TraceManager.addDev("Removing lines, size=" + sizeRow + "x" + sizeColumn); // Remove lines whose element #j is not 0 for (i = 0; i < sizeRow; i++) { if (matrice[i][j] != 0) { removeLine(i); //TraceManager.addDev("matafterremove " + i + "=\n" + toString() + "\n\n"); i--; } } TraceManager.addDev("Lines removed, size=" + sizeRow + "x" + sizeColumn); //TraceManager.addDev("----------------\nD"+ (j+1) +"=\n" + toString() + "\n\n"); } // Remove m first columns } // noMultiplier indicates whether names of lines may contain the "*" sign, or not. public void FarkasForInvariants(boolean noMultiplier) { int sizeColumBeforeConcat = sizeColumn; IntMatrix idMat = new IntMatrix(sizeRow, sizeRow); idMat.makeID(); concatAfter(idMat); //TraceManager.addDev("matconcat=\n" + toString() + "\n\n"); //int[] lined1, lined2, lined; int[] lined; int gcd; int l, i; String s0, s1; String nameOfNewLine; int cpt; long total = 0; int tmpSizeRow; LinkedList<IntLine> ll = new LinkedList<IntLine>(); for (int j = 0; j < sizeColumBeforeConcat; j++) { // Loop on lines to add line combinations tmpSizeRow = sizeRow; for (i = 0; i < tmpSizeRow - 1; i++) { percentageCompletion = (long) (j * 10000.0 / sizeColumBeforeConcat) + (long) (10000.0 * i / tmpSizeRow / sizeColumBeforeConcat); //lined1 = getLine(i); //tmpSizeRow = sizeRow; for (int k = i + 1; k < tmpSizeRow; k++) { if (mustGo == false) { interrupted = true; return; } //TraceManager.addDev("Computing k=" + k + " " + sizeRow + "x" + sizeColumn); //lined2 = getLine(k); // lines d1 and 2 have opposite signs? //if (((lined1[j] < 0) && (lined2[j]>0)) || ((lined1[j]>0) && (lined2[j]<0))) { if (((matrice[i][j] < 0) && (matrice[k][j] > 0)) || ((matrice[i][j] > 0) && (matrice[k][j] < 0))) { lined = new int[sizeColumn]; for (l = 0; l < lined.length; l++) { lined[l] = Math.abs(matrice[k][j]) * matrice[i][l] + Math.abs(matrice[i][j]) * matrice[k][l]; } if (Math.abs(matrice[k][j]) == 1) { s0 = nameOfRows[i] + "+"; } else { if (noMultiplier) { s0 = nameOfRows[i] + "+"; for (cpt = Math.abs(matrice[k][j]); cpt > 1; cpt--) { s0 += nameOfRows[i] + "+"; } } else { s0 = "" + Math.abs(matrice[k][j]) + "*(" + nameOfRows[i] + ") + "; } } if (Math.abs(matrice[i][j]) == 1) { s1 = nameOfRows[k]; } else { if (noMultiplier) { s1 = nameOfRows[k]; for (cpt = Math.abs(matrice[i][j]); cpt > 1; cpt--) { s1 += "+" + nameOfRows[k]; } } else { s1 = "" + Math.abs(matrice[i][j]) + "*(" + nameOfRows[k] + ") + "; } } //TraceManager.addDev("Name of line=" + s0 + "/" + s1); nameOfNewLine = s0 + s1; gcd = MyMath.gcd(lined); //TraceManager.addDev("gcd =" + gcd + " of line =" + lineToString(lined) + " i.e.:" + nameOfNewLine); if (gcd != 0) { for (l = 0; l < lined.length; l++) { lined[l] = lined[l] / gcd; } } ll.add(new IntLine(lined, nameOfNewLine)); //addLine(lined, nameOfNewLine); //TraceManager.addDev("matafterline=\n" + toString() + "\n\n"); } } } TraceManager.addDev("Adding lines, size=" + sizeRow + "x" + sizeColumn); addLines(ll); ll.clear(); TraceManager.addDev("Removing lines, size=" + sizeRow + "x" + sizeColumn); // Remove lines whose element #j is not 0 int nbToRemoved = 0; for (i = 0; i < sizeRow; i++) { if (matrice[i][j] != 0) { nbToRemoved++; //removeLine(i); //TraceManager.addDev("matafterremove " + i + "=\n" + toString() + "\n\n"); //i--; } } TraceManager.addDev("# of lines to be removed: " + nbToRemoved); if (nbToRemoved > 0) { int index = 0; int[][] newMat = new int[sizeRow - nbToRemoved][sizeColumn]; String[] newNames = new String[sizeRow - nbToRemoved]; for (int ii = 0; ii < sizeRow; ii++) { if (matrice[ii][j] == 0) { //TraceManager.addDev("Copying lines to be removed: " + nbToRemoved); // line copy to index for (int jj = 0; jj < sizeColumn; jj++) { newMat[index][jj] = matrice[ii][jj]; } newNames[index] = nameOfRows[ii]; index++; } } matrice = newMat; sizeRow -= nbToRemoved; nameOfRows = newNames; } TraceManager.addDev("Lines removed, size=" + sizeRow + "x" + sizeColumn); //TraceManager.addDev("----------------\nD"+ (j+1) +"=\n" + toString() + "\n\n"); } // Remove m first columns } // noMultiplier indicates whether names of lines may contain the "*" sign, or not. public void FarkasForInvariantsBitSet(boolean withHeuristics) { int sizeColumBeforeConcat = sizeColumn; IntMatrix idMat = new IntMatrix(sizeRow, sizeRow); idMat.makeID(); concatAfter(idMat); //TraceManager.addDev("matconcat=\n" + toString() + "\n\n"); //int[] lined1, lined2, lined; int[] lined; int gcd; int l, i; String s0, s1; String nameOfNewLine; int cpt; long total = 0; int tmpSizeRow; LinkedList<IntLine> ll = new LinkedList<IntLine>(); bitSetOfMatrix = new BitSet[sizeRow]; BitSet bs, bs1, bs2; for (int bi = 0; bi < sizeRow; bi++) { bitSetOfMatrix[bi] = new BitSet(sizeRow); bitSetOfMatrix[bi].set(bi); } for (int j = 0; j < sizeColumBeforeConcat; j++) { // Loop on lines to add line combinations tmpSizeRow = sizeRow; for (i = 0; i < tmpSizeRow - 1; i++) { percentageCompletion = (long) (j * 10000.0 / sizeColumBeforeConcat) + (long) (10000.0 * i / tmpSizeRow / sizeColumBeforeConcat); //lined1 = getLine(i); //tmpSizeRow = sizeRow; for (int k = i + 1; k < tmpSizeRow; k++) { if (mustGo == false) { interrupted = true; return; } //TraceManager.addDev("Computing k=" + k + " " + sizeRow + "x" + sizeColumn); //lined2 = getLine(k); // lines d1 and 2 have opposite signs? //if (((lined1[j] < 0) && (lined2[j]>0)) || ((lined1[j]>0) && (lined2[j]<0))) { if (((matrice[i][j] < 0) && (matrice[k][j] > 0)) || ((matrice[i][j] > 0) && (matrice[k][j] < 0))) { // Take the bit set of the two lines // Lines not yet taken into account? if (!withHeuristics || (!(bitSetOfMatrix[i].intersects(bitSetOfMatrix[k])))) { lined = new int[sizeColumn]; for (l = 0; l < lined.length; l++) { lined[l] = Math.abs(matrice[k][j]) * matrice[i][l] + Math.abs(matrice[i][j]) * matrice[k][l]; } gcd = MyMath.gcd(lined); //TraceManager.addDev("gcd =" + gcd + " of line =" + lineToString(lined) + " i.e.:" + nameOfNewLine); if (gcd != 0) { for (l = 0; l < lined.length; l++) { lined[l] = lined[l] / gcd; } } bs = ((BitSet) (bitSetOfMatrix[i].clone())); bs.or(bitSetOfMatrix[k]); ll.add(new IntLine(lined, bs)); } //addLine(lined, nameOfNewLine); //TraceManager.addDev("matafterline=\n" + toString() + "\n\n"); } } } TraceManager.addDev("Adding lines, size=" + sizeRow + "x" + sizeColumn); addLinesBitSet(ll); ll.clear(); TraceManager.addDev("Removing lines, size=" + sizeRow + "x" + sizeColumn); // Remove lines whose element #j is not 0 int nbToRemoved = 0; for (i = 0; i < sizeRow; i++) { if (matrice[i][j] != 0) { nbToRemoved++; //removeLine(i); //TraceManager.addDev("matafterremove " + i + "=\n" + toString() + "\n\n"); //i--; } } TraceManager.addDev("# of lines to be removed: " + nbToRemoved); if (nbToRemoved > 0) { int index = 0; int[][] newMat = new int[sizeRow - nbToRemoved][sizeColumn]; String[] newNames = new String[sizeRow - nbToRemoved]; BitSet[] newBitSet = new BitSet[sizeRow - nbToRemoved]; for (int ii = 0; ii < sizeRow; ii++) { if (matrice[ii][j] == 0) { //TraceManager.addDev("Copying lines to be removed: " + nbToRemoved); // line copy to index for (int jj = 0; jj < sizeColumn; jj++) { newMat[index][jj] = matrice[ii][jj]; } newNames[index] = nameOfRows[ii]; newBitSet[index] = bitSetOfMatrix[ii]; index++; } } matrice = newMat; sizeRow -= nbToRemoved; nameOfRows = newNames; bitSetOfMatrix = newBitSet; } TraceManager.addDev("Lines removed, size=" + sizeRow + "x" + sizeColumn); //TraceManager.addDev("----------------\nD"+ (j+1) +"=\n" + toString() + "\n\n"); } // Remove m first columns } public synchronized void startFarkas(boolean _noMultiplier, boolean _withHeuristics) { noMultiplier = _noMultiplier; withHeuristics = _withHeuristics; Thread t = new Thread(this); mustGo = true; finished = false; interrupted = false; t.start(); } public synchronized void stopComputation() { mustGo = false; notifyAll(); } public boolean wasInterrupted() { return interrupted; } public synchronized void callFinished() { mustGo = false; notifyAll(); } public synchronized boolean isFinished() { return finished; } public void run() { try { FarkasForInvariantsBitSet(withHeuristics); } catch (Error e) { TraceManager.addDev("Exception when executing Farkas algorithm: " + e.getMessage()); interrupted = true; } if (!interrupted) { stopComputation(); } finished = true; TraceManager.addDev("Farkas thread completed"); } }