diff --git a/.gitignore b/.gitignore index b0a9905575783f18d92dd5f505a52d187802980d..57f16fb67c1b1589981416b323d7a9debc728665 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,41 @@ -.idea/ -.settings/ -build/ +/build* +/workspace +setting.xml +release/ target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +icy.log + +### IntelliJ IDEA ### +.idea/ +*.iws *.iml +*.ipr + +### Eclipse ### +.apt_generated .classpath +.factorypath .project -**/.DS_Store \ No newline at end of file +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +**/.DS_Store +Icon? \ No newline at end of file diff --git a/pom.xml b/pom.xml index 18fcc240c7888a84cc7b677b3c3cbdb759e63f20..4ae3a2f216d7bc146d03cf00b8e70c077821bf81 100644 --- a/pom.xml +++ b/pom.xml @@ -7,11 +7,11 @@ <parent> <groupId>org.bioimageanalysis.icy</groupId> <artifactId>pom-icy</artifactId> - <version>2.2.0</version> + <version>3.0.0-a.1</version> </parent> <artifactId>linear-programming</artifactId> - <version>2.0.0</version> + <version>2.0.0-a.1</version> <name>Linear Programming</name> <description> @@ -26,7 +26,7 @@ <repositories> <repository> <id>icy</id> - <url>https://icy-nexus.pasteur.fr/repository/Icy/</url> + <url>https://nexus-icy.pasteur.cloud/repository/icy/</url> </repository> </repositories> </project> \ No newline at end of file diff --git a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/CanonicalProgramParameters.java b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/CanonicalProgramParameters.java index 2c85ae237efeae731d28ffcea9fe379133b9b20c..3ace13d908dc3f1ef2dc34298a5ec3e1440e3b11 100644 --- a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/CanonicalProgramParameters.java +++ b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/CanonicalProgramParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -45,7 +45,6 @@ package plugins.nchenouard.linearprogrammingfullsimplex; * * @author Nicolas Chenouard (nicolas.chenouard.dev@gmail.com) */ - public class CanonicalProgramParameters { /** * The objective function coefficient: c'*x or sum_i c[i]*x[i] for the variable x. diff --git a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/CanonicalSimplexProgram.java b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/CanonicalSimplexProgram.java index d54cfb9fa1386b403badc4e3b720f29f5a4c546c..64ddf5ec455e8e2123bff8a5228898339e8eb749 100644 --- a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/CanonicalSimplexProgram.java +++ b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/CanonicalSimplexProgram.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,7 +18,9 @@ package plugins.nchenouard.linearprogrammingfullsimplex; -import icy.system.IcyExceptionHandler; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; import java.io.*; @@ -45,7 +47,6 @@ import java.io.*; * * @author Nicolas Chenouard (nicolas.chenouard.dev@gmail.com) */ - public abstract class CanonicalSimplexProgram { /** * Parameters defining the linear programming problem @@ -86,7 +87,7 @@ public abstract class CanonicalSimplexProgram { * @param equality indicates whether each constraint is an equality. Else it is * <=. */ - public CanonicalSimplexProgram(final double[][] A, final double[] b, final double[] c, final boolean maximization, final boolean[] equality) { + public CanonicalSimplexProgram(final double[][] A, final double @NotNull [] b, final double @NotNull [] c, final boolean maximization, final boolean[] equality) { this.parameters = new CanonicalProgramParameters(); this.parameters.A = A; this.parameters.b = b; @@ -102,7 +103,8 @@ public abstract class CanonicalSimplexProgram { * * @param p Parameters of the linear programming problem. */ - public CanonicalSimplexProgram(final CanonicalProgramParameters p) { + @Contract(pure = true) + public CanonicalSimplexProgram(final @NotNull CanonicalProgramParameters p) { this.parameters = p; this.numVariables = p.c.length; this.numConstraints = p.b.length; @@ -224,7 +226,7 @@ public abstract class CanonicalSimplexProgram { // Canonical form: initial tableau is built by introducing unit vectors solvePhaseICanonicalSimplex(); if (verbose) { - System.out.println("Tableau after phase 1 :"); + IcyLogger.trace(this.getClass(), "Tableau after phase 1: "); tableau0.printTableau(); } // Phase II: optimisation by Gauss-Jordan replacement of non-basic columns @@ -269,7 +271,7 @@ public abstract class CanonicalSimplexProgram { if (!success) return false; if (verbose) { - System.out.println("Phase 1 "); + IcyLogger.trace(this.getClass(), "Phase 1 "); tableau0.printTableau(); } if (Math.abs(tableau0.scoreValue) < tol) // optimal score should be 0 @@ -337,22 +339,22 @@ public abstract class CanonicalSimplexProgram { } else { if (verbose) - System.out.println("replacement: row = " + rowIdx + ", column = " + colIdx); + IcyLogger.trace(this.getClass(), "replacement: row = " + rowIdx + ", column = " + colIdx); tableau.pivot(colIdx, rowIdx); } } if (verbose) { - System.out.println("Tableau at iteration:"); + IcyLogger.trace(this.getClass(), "Tableau at iteration: "); tableau.printTableau(); } } if (verbose) { - System.out.println("Final tableau:"); + IcyLogger.trace(this.getClass(), "Final tableau: "); tableau.printTableau(); } if (!feasible) { if (verbose) - System.out.println("UNFEASIBLE problem"); + IcyLogger.trace(this.getClass(), "UNFEASIBLE problem"); return false; } else { @@ -404,7 +406,7 @@ public abstract class CanonicalSimplexProgram { for (int j = 0; j < solution.length; j++) { v += A0[i][j] * solution[j]; } - System.out.println(v + "<?>" + b0[i]); + IcyLogger.info(this.getClass(), v + "<?>" + b0[i]); } } } @@ -465,36 +467,35 @@ public abstract class CanonicalSimplexProgram { public void displayProblem() { - System.out.println("Linear Programming problem max c'x st. Ax <= b, x >= 0 and some equality contraints defined by eq"); + IcyLogger.info(this.getClass(), "Linear Programming problem max c'x st. Ax <= b, x >= 0 and some equality contraints defined by eq"); if (parameters.maximization) - System.out.println("Maximization problem"); + IcyLogger.info(this.getClass(), "Maximization problem"); else - System.out.println("Minimization problem"); - System.out.print("c = ["); + IcyLogger.info(this.getClass(), "Minimization problem"); + IcyLogger.info(this.getClass(), "c = ["); for (int i = 0; i < parameters.c.length; i++) - System.out.print(parameters.c[i] + ", "); - System.out.println("]"); - System.out.print("b = ["); + IcyLogger.info(this.getClass(), parameters.c[i] + ", "); + IcyLogger.info(this.getClass(), "]"); + IcyLogger.info(this.getClass(), "b = ["); for (int i = 0; i < parameters.b.length; i++) - System.out.print(parameters.b[i] + ", "); - System.out.println("]"); - System.out.print("eq = ["); + IcyLogger.info(this.getClass(), parameters.b[i] + ", "); + IcyLogger.info(this.getClass(), "]"); + IcyLogger.info(this.getClass(), "eq = ["); for (int i = 0; i < parameters.equalityConstraints.length; i++) - System.out.print(parameters.equalityConstraints[i] + ", "); - System.out.println("]"); - System.out.print("A = ["); + IcyLogger.info(this.getClass(), parameters.equalityConstraints[i] + ", "); + IcyLogger.info(this.getClass(), "]"); + IcyLogger.info(this.getClass(), "A = ["); for (int i = 0; i < parameters.A.length; i++) { - System.out.print("["); + IcyLogger.info(this.getClass(), "["); for (int j = 0; j < parameters.A[i].length; j++) - System.out.print(parameters.A[i][j] + ", "); - System.out.println("],"); + IcyLogger.info(this.getClass(), parameters.A[i][j] + ", "); + IcyLogger.info(this.getClass(), "],"); } - System.out.println("]"); + IcyLogger.info(this.getClass(), "]"); } public void displayProblemTutorial() { - System.out.println("Linear Programming problem:"); - System.out.println(); + IcyLogger.info(this.getClass(), "Linear Programming problem:"); StringBuilder line = new StringBuilder(); if (parameters.maximization) line.append("max_x"); @@ -507,10 +508,8 @@ public abstract class CanonicalSimplexProgram { else line.append(" - ").append(Math.abs(parameters.c[i])).append("*x[").append(i).append("]"); } - System.out.println(line); - System.out.println(); - System.out.println("Such that x >= 0 and:"); - System.out.println(); + IcyLogger.info(this.getClass(), line.toString()); + IcyLogger.info(this.getClass(), "Such that x >= 0 and:"); for (int i = 0; i < parameters.b.length; i++) { line = new StringBuilder(); for (int j = 0; j < parameters.A[i].length; j++) { @@ -524,7 +523,7 @@ public abstract class CanonicalSimplexProgram { else line.append(" <= "); line.append(parameters.b[i]); - System.out.println(line); + IcyLogger.info(this.getClass(), line.toString()); } } @@ -532,30 +531,31 @@ public abstract class CanonicalSimplexProgram { * @return Manual of the library for stand-alone use through command line */ public static String getHelp() { - return "Run the solver for example problems or for a user-defined system\n" - + "Empty arguments to use the default example.\n" - + "Enter an integer from 0 to 3 for different example scenarios.\n" - + "Enter -1 for a user-defined scenario through text files.\n " - + "For custom scenarios, enter filenames (text files) for different parameters of the problem preceded by the appropriate prefix:\n" - + "-c for the objective function file.\n" - + "-A for constraint matrix file.\n" - + "-b for the constraint value file.\n" - + "-e for the equality constraint file.\n" - + "-max or -min to indicate a maximization or minimization problem, respectively. Default in minimization.\n" - + "Example arguments: java -jar linearProgrammingICY.jar -c c.txt -A A.txt -b b.txt -e eq.txt -max -o solution.txt" - + "Each text file must contain a series of double values separated by ',' in a single line, except for the constraint file which contains one line per constraint.\n" - + "For the equality file '0' stands for 'false' and '1' for true.\n\n" - + "Version 1.0. April 2014. Author: Nicolas Chenouard. nicolas.chenouard.dev@gmail.com. Licence GPL V3.0"; + return """ + Run the solver for example problems or for a user-defined system + Empty arguments to use the default example. + Enter an integer from 0 to 3 for different example scenarios. + Enter -1 for a user-defined scenario through text files. + For custom scenarios, enter filenames (text files) for different parameters of the problem preceded by the appropriate prefix: + -c for the objective function file. + -A for constraint matrix file. + -b for the constraint value file. + -e for the equality constraint file. + -max or -min to indicate a maximization or minimization problem, respectively. Default in minimization. + Example arguments: java -jar linearProgrammingICY.jar -c c.txt -A A.txt -b b.txt -e eq.txt -max -o solution.txt\ + Each text file must contain a series of double values separated by ',' in a single line, except for the constraint file which contains one line per constraint. + For the equality file '0' stands for 'false' and '1' for true. + + Version 1.0. April 2014. Author: Nicolas Chenouard. nicolas.chenouard.dev@gmail.com. Licence GPL V3.0"""; } /** * Display the manual of the library for stand-alone use through command line */ public static void displayHelp() { - System.out.println(getHelp()); + IcyLogger.info(CanonicalSimplexProgram.class, getHelp()); } - /** * Run the solver for example problems or for a user-defined system * @@ -575,7 +575,7 @@ public abstract class CanonicalSimplexProgram { * Each text file must contain a series of double values separated by ',' in a single line, except for the constraint file which contains one line per constraint. * For the equality file '0' stands for 'false' and '1' for true. */ - public static void main(final String[] args) { + public static void main(final String @NotNull [] args) { int scenario = 0; if (args.length > 0) { if (args[0].compareTo("-h") == 0 || args[0].compareTo("-help") == 0 || args[0].compareTo("--h") == 0 || args[0].compareTo("--help") == 0) { @@ -587,20 +587,28 @@ public abstract class CanonicalSimplexProgram { scenario = Integer.parseInt(args[0]); } catch (final NumberFormatException e) { - System.out.println("Invalid input argument"); - System.out.println("Use input option -help to display the manual of the software"); - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error( + CanonicalSimplexProgram.class, + "Invalid input argument", + "Use input option -help to display the manual of the software" + ); return; } } } else { - System.out.println("Solving a default simple linear problem with the Simplex algorithm."); - System.out.println("Enter -help for the manual explicating the customization options."); + IcyLogger.info( + CanonicalSimplexProgram.class, + "Solving a default simple linear problem with the Simplex algorithm.", + "Enter -help for the manual explicating the customization options." + ); } if (scenario < -1 || scenario > 3) { - System.out.println("Invalid input argument"); - System.out.println("Use input option -help to display the manual of the software"); + IcyLogger.error( + CanonicalSimplexProgram.class, + "Invalid input argument", + "Use input option -help to display the manual of the software" + ); return; } boolean maximization = false; @@ -633,8 +641,11 @@ public abstract class CanonicalSimplexProgram { } } if (fileA == null) { - System.out.println("Missing -A input argument"); - System.out.println("Use input option -help to display the manual of the software"); + IcyLogger.error( + CanonicalSimplexProgram.class, + "Missing -A input argument", + "Use input option -help to display the manual of the software" + ); return; } String fileB = null; @@ -645,8 +656,11 @@ public abstract class CanonicalSimplexProgram { } } if (fileB == null) { - System.out.println("Missing -b input argument"); - System.out.println("Use input option -help to display the manual of the software"); + IcyLogger.error( + CanonicalSimplexProgram.class, + "Missing -b input argument", + "Use input option -help to display the manual of the software" + ); return; } @@ -658,8 +672,11 @@ public abstract class CanonicalSimplexProgram { } } if (fileC == null) { - System.out.println("Missing -c input argument"); - System.out.println("Use input option -help to display the manual of the software"); + IcyLogger.error( + CanonicalSimplexProgram.class, + "Missing -c input argument", + "Use input option -help to display the manual of the software" + ); return; } for (int i = 0; i < args.length - 1; i++) { @@ -676,8 +693,11 @@ public abstract class CanonicalSimplexProgram { } } if (fileE == null) { - System.out.println("Missing -e input argument"); - System.out.println("Use input option -help to display the manual of the software"); + IcyLogger.error( + CanonicalSimplexProgram.class, + "Missing -e input argument", + "Use input option -help to display the manual of the software" + ); return; } try { @@ -738,15 +758,18 @@ public abstract class CanonicalSimplexProgram { fis.close(); } catch (final IOException e) { - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(CanonicalSimplexProgram.class, e); return; } break; } case 0: { - System.out.println("Basic example with 3 pivots"); - System.out.println("Optimal is 6.5"); - System.out.println("Solution is [1.0, 1.0, 0.5, 0.0]"); + IcyLogger.info( + CanonicalSimplexProgram.class, + "Basic example with 3 pivots", + "Optimal is 6.5", + "Solution is [1.0, 1.0, 0.5, 0.0]" + ); A = new double[][]{{2, 1, 0, 0}, {0, 1, 4, 1}, {1, 3, 0, 1} @@ -758,9 +781,12 @@ public abstract class CanonicalSimplexProgram { break; } case 1: { - System.out.println("Example that would cycle with Bland rule."); - System.out.println("Optimal score is 1/20."); - System.out.println("Solution is [1/25, 0, 1, 0]."); + IcyLogger.info( + CanonicalSimplexProgram.class, + "Example that would cycle with Bland rule.", + "Optimal score is 1/20.", + "Solution is [1/25, 0, 1, 0]." + ); A = new double[][]{{1d / 4, -60, -1d / 25, 9}, {1d / 2, -90, -1d / 50, 3}, {0, 0, 1, 0} @@ -772,8 +798,11 @@ public abstract class CanonicalSimplexProgram { break; } case 2: { - System.out.println("An example with equality constraints"); - System.out.println("Solution is [0, 4/7, 1 + 5/7, 0, 0]."); + IcyLogger.info( + CanonicalSimplexProgram.class, + "An example with equality constraints", + "Solution is [0, 4/7, 1 + 5/7, 0, 0]." + ); A = new double[][] {{5, -4, 13, -2, 1}, {1, -1, 5, -1, 1}, @@ -785,9 +814,12 @@ public abstract class CanonicalSimplexProgram { break; } case 3: { - System.out.println("An example with equality constraints and negative right-hand-side"); - System.out.println("Optimal score is -3 - 1/16."); - System.out.println("Solution is [3/16, 1 + 1/4, 0, 5/16]."); + IcyLogger.info( + CanonicalSimplexProgram.class, + "An example with equality constraints and negative right-hand-side", + "Optimal score is -3 - 1/16.", + "Solution is [3/16, 1 + 1/4, 0, 5/16]." + ); A = new double[][] {{1, 2, 1, 1}, {1, -2, 2, 1}, @@ -800,8 +832,11 @@ public abstract class CanonicalSimplexProgram { } } if (A == null || b == null || c == null || equality == null) { - System.out.println("Missing arguments"); - System.out.println("Use input option -help to display the manual of the software"); + IcyLogger.error( + CanonicalSimplexProgram.class, + "Missing arguments", + "Use input option -help to display the manual of the software" + ); return; } final CanonicalSimplexProgram program = new SimplexLEXICO(A, b, c, maximization, equality); @@ -811,21 +846,21 @@ public abstract class CanonicalSimplexProgram { if (program.solvePrimalSimplex()) { final double[] solution = program.solution; if (verbose) { - System.out.print("Computed solution = ["); + IcyLogger.trace(CanonicalSimplexProgram.class, "Computed solution = ["); for (final double value : solution) - System.out.print(value + ", "); - System.out.println("]"); - System.out.println("Computed score = " + program.tableau0.scoreValue); - System.out.println("Computed constraint values:"); + IcyLogger.trace(CanonicalSimplexProgram.class, value + ", "); + IcyLogger.trace(CanonicalSimplexProgram.class, "]"); + IcyLogger.trace(CanonicalSimplexProgram.class, "Computed score = " + program.tableau0.scoreValue); + IcyLogger.trace(CanonicalSimplexProgram.class, "Computed constraint values:"); for (int i = 0; i < A.length; i++) { double v = 0; // compute the constraint for (int j = 0; j < A[i].length; j++) v += A[i][j] * solution[j]; if (equality[i]) - System.out.println(v + " == " + b[i]); + IcyLogger.trace(CanonicalSimplexProgram.class, v + " == " + b[i]); else - System.out.println(v + " <= " + b[i]); + IcyLogger.trace(CanonicalSimplexProgram.class, v + " <= " + b[i]); } } if (outputFile != null) { @@ -841,19 +876,18 @@ public abstract class CanonicalSimplexProgram { out.close(); } catch (final IOException e) { - IcyExceptionHandler.showErrorMessage(e, true); + IcyLogger.error(CanonicalSimplexProgram.class, e); } } } else { - System.out.println("Solve simplex failed"); + IcyLogger.error(CanonicalSimplexProgram.class, "Solve simplex failed"); } } public static void runExampleScenario(final int scenario) { if (scenario < 0 || scenario > 3) { - System.out.println("Invalid input argument"); - System.out.println("Scenario indices are: 0, 1, 2 and 3"); + IcyLogger.error(CanonicalSimplexProgram.class, "Invalid input argument", "Scenario indices are: 0, 1, 2 and 3"); return; } boolean maximization = false; @@ -864,9 +898,12 @@ public abstract class CanonicalSimplexProgram { final boolean verbose = true; switch (scenario) { case 0: { - System.out.println("Basic example with 3 pivots"); - System.out.println("Optimal score is 6.5"); - System.out.println("Solution is [1.0, 1.0, 0.5, 0.0]"); + IcyLogger.info( + CanonicalSimplexProgram.class, + "Basic example with 3 pivots", + "Optimal score is 6.5", + "Solution is [1.0, 1.0, 0.5, 0.0]" + ); A = new double[][]{{2, 1, 0, 0}, {0, 1, 4, 1}, {1, 3, 0, 1} @@ -878,9 +915,12 @@ public abstract class CanonicalSimplexProgram { break; } case 1: { - System.out.println("Example that would cycle with Bland rule."); - System.out.println("Optimal score is 1/20."); - System.out.println("Solution is [1/25, 0, 1, 0]."); + IcyLogger.info( + CanonicalSimplexProgram.class, + "Example that would cycle with Bland rule.", + "Optimal score is 1/20.", + "Solution is [1/25, 0, 1, 0]." + ); A = new double[][]{{1d / 4, -60, -1d / 25, 9}, {1d / 2, -90, -1d / 50, 3}, {0, 0, 1, 0} @@ -892,8 +932,11 @@ public abstract class CanonicalSimplexProgram { break; } case 2: { - System.out.println("An example with equality constraints"); - System.out.println("Solution is [0, 4/7, 1 + 5/7, 0, 0]."); + IcyLogger.info( + CanonicalSimplexProgram.class, + "An example with equality constraints", + "Solution is [0, 4/7, 1 + 5/7, 0, 0]." + ); A = new double[][] {{5, -4, 13, -2, 1}, {1, -1, 5, -1, 1}, @@ -905,9 +948,12 @@ public abstract class CanonicalSimplexProgram { break; } case 3: { - System.out.println("An example with equality constraints and negative right-hand-side"); - System.out.println("Optimal score is -3 - 1/16."); - System.out.println("Solution is [3/16, 1 + 1/4, 0, 5/16]."); + IcyLogger.info( + CanonicalSimplexProgram.class, + "An example with equality constraints and negative right-hand-side", + "Optimal score is -3 - 1/16.", + "Solution is [3/16, 1 + 1/4, 0, 5/16]." + ); A = new double[][] {{1, 2, 1, 1}, {1, -2, 2, 1}, @@ -922,35 +968,31 @@ public abstract class CanonicalSimplexProgram { } final CanonicalSimplexProgram program = new SimplexLEXICO(A, b, c, maximization, equality); if (verbose) { - System.out.println(); program.displayProblemTutorial(); } if (program.solvePrimalSimplex()) { final double[] solution = program.solution; if (verbose) { - System.out.println(); - System.out.print("Computed solution = ["); + IcyLogger.trace(CanonicalSimplexProgram.class, "Computed solution = ["); for (final double value : solution) - System.out.print(value + ", "); - System.out.println("]"); - System.out.println(); - System.out.println("Computed score = " + program.tableau0.scoreValue); - System.out.println(); - System.out.println("Computed constraint values:"); + IcyLogger.trace(CanonicalSimplexProgram.class, value + ", "); + IcyLogger.trace(CanonicalSimplexProgram.class, "]"); + IcyLogger.trace(CanonicalSimplexProgram.class, "Computed score = " + program.tableau0.scoreValue); + IcyLogger.trace(CanonicalSimplexProgram.class, "Computed constraint values:"); for (int i = 0; i < A.length; i++) { double v = 0; // compute the constraint for (int j = 0; j < A[i].length; j++) v += A[i][j] * solution[j]; if (equality[i]) - System.out.println(v + " == " + b[i]); + IcyLogger.trace(CanonicalSimplexProgram.class, v + " == " + b[i]); else - System.out.println(v + " <= " + b[i]); + IcyLogger.trace(CanonicalSimplexProgram.class, v + " <= " + b[i]); } } } else { - System.out.println("Solve simplex failed"); + IcyLogger.error(CanonicalSimplexProgram.class, "Solve simplex failed"); } } } \ No newline at end of file diff --git a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/LinearProgrammingICYPlugin.java b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/LinearProgrammingICYPlugin.java index 728b638cc0ec9a6309b0c23985b02aca5b14b130..b3df71c62d5b2dff290f2bb7bb89777096af2cf3 100644 --- a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/LinearProgrammingICYPlugin.java +++ b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/LinearProgrammingICYPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,20 +18,22 @@ package plugins.nchenouard.linearprogrammingfullsimplex; -import icy.gui.frame.progress.AnnounceFrame; -import icy.plugin.abstract_.PluginActionable; +import org.bioimageanalysis.icy.extension.plugin.abstract_.PluginActionable; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName; +import org.bioimageanalysis.icy.gui.frame.progress.AnnounceFrame; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +@IcyPluginName("Linear Programming Example") +@IcyPluginIcon(path = "/linear-programming.png") public class LinearProgrammingICYPlugin extends PluginActionable { @Override public void run() { new AnnounceFrame("It is now running a series of example optimization problems. See the console for the output."); - new AnnounceFrame("This is a utility plugin, intended to be used by other ICY plugins."); + new AnnounceFrame("This is an utility plugin, intended to be used by other ICY plugins."); for (int i = 0; i < 3; i++) { - System.out.println(); - System.out.println("=== Linear Programming test scenario " + i + " ==="); - System.out.println(); + IcyLogger.info(this.getClass(), "=== Linear Programming test scenario " + i + " ==="); CanonicalSimplexProgram.runExampleScenario(i); } } - } diff --git a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexBLAND.java b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexBLAND.java index a92558acbc8a79bb5ef7742d619125b645ef3813..79b2b283c7b72b6dda76b6b3374f539e891453de 100644 --- a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexBLAND.java +++ b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexBLAND.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,12 +18,14 @@ package plugins.nchenouard.linearprogrammingfullsimplex; +import org.jetbrains.annotations.NotNull; + /** * Implements the Bland rule for pivoting for the Simplex algorithm. * <p> * Warning: this rule shows high probability of cycling. * <p> - * Part of the Linear Programming plugin for ICY http://icy.bioimageanalysis.org + * Part of the Linear Programming plugin for ICY <a href="https://icy.bioimageanalysis.org">https://icy.bioimageanalysis.org</a> * * @author Nicolas Chenouard (nicolas.chenouard.dev@gmail.com) */ @@ -59,7 +61,7 @@ public class SimplexBLAND extends CanonicalSimplexProgram { * @return the row index in the tableau */ @Override - protected int getRowidx(final TableauWithSlackVariables tableau, final int colIdx) { + protected int getRowidx(final @NotNull TableauWithSlackVariables tableau, final int colIdx) { boolean found = false; double maxVal = -1; int rowIdx = -1; diff --git a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexLEXICO.java b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexLEXICO.java index 172848cf4ed0a44182c754f0e4ddb80f91270506..61f78404f3393822989e08502283a7892b7547da 100644 --- a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexLEXICO.java +++ b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexLEXICO.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,12 +18,14 @@ package plugins.nchenouard.linearprogrammingfullsimplex; +import org.jetbrains.annotations.NotNull; + import java.util.ArrayList; /** * Implements the lexicographic rule for pivoting for the Simplex algorithm. * <p> - * Part of the Linear Programming plugin for ICY http://icy.bioimageanalysis.org + * Part of the Linear Programming plugin for ICY <a href="https://icy.bioimageanalysis.org">https://icy.bioimageanalysis.org</a> * * @author Nicolas Chenouard (nicolas.chenouard.dev@gmail.com) */ @@ -100,7 +102,7 @@ public class SimplexLEXICO extends CanonicalSimplexProgram { * @return the row index in the tableau */ @Override - protected int getRowidx(final TableauWithSlackVariables tableau, final int colIdx) { + protected int getRowidx(final @NotNull TableauWithSlackVariables tableau, final int colIdx) { int rowIdx = -1; int numBasicRow = 0; final ArrayList<Integer> basicCols = new ArrayList<>(); diff --git a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexMAX.java b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexMAX.java index a65f066db8104b58b7a399262f754a9ed97d6d6e..e1a13e3eb06e3667892a562bf5f33b05d80f3d99 100644 --- a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexMAX.java +++ b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/SimplexMAX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,12 +18,14 @@ package plugins.nchenouard.linearprogrammingfullsimplex; +import org.jetbrains.annotations.NotNull; + /** * Implements the maximum score rule for pivoting for the Simplex algorithm. * <p> * Warning: this rule shows high probability of cycling. * <p> - * Part of the Linear Programming plugin for ICY http://icy.bioimageanalysis.org + * Part of the Linear Programming plugin for ICY <a href="https://icy.bioimageanalysis.org">https://icy.bioimageanalysis.org</a> * * @author Nicolas Chenouard (nicolas.chenouard.dev@gmail.com) */ @@ -96,7 +98,7 @@ public class SimplexMAX extends CanonicalSimplexProgram { * @return the row index in the tableau */ @Override - protected int getRowidx(final TableauWithSlackVariables tableau, final int colIdx) { + protected int getRowidx(final @NotNull TableauWithSlackVariables tableau, final int colIdx) { boolean found = false; double maxVal = -1; int rowIdx = -1; diff --git a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/TableauMinSlackObjective.java b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/TableauMinSlackObjective.java index 55a2ac2a29a356aac9ebad6bc04e02803273cd77..d386e2cc6f73c376eb8ba9235d0812009258ff9b 100644 --- a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/TableauMinSlackObjective.java +++ b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/TableauMinSlackObjective.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,6 +18,8 @@ package plugins.nchenouard.linearprogrammingfullsimplex; +import org.jetbrains.annotations.NotNull; + /** * Tableau used for Gauss-Jordan elimination in which slack variables are given a 1 score depending on whether constraints are equalities. * Slack variables are added to the set of column vectors in a leading position. @@ -27,7 +29,6 @@ package plugins.nchenouard.linearprogrammingfullsimplex; * @author Nicolas Chenouard (nicolas.chenouard.dev@gmail.com) */ public class TableauMinSlackObjective extends TableauWithSlackVariables { - /** * Create the tableau based on a linear program. The scores in the tableau * will not be initialized to their standard value but set to handle @@ -35,7 +36,7 @@ public class TableauMinSlackObjective extends TableauWithSlackVariables { * * @param simplexProgram parameters defining the linear optimization problem. */ - public TableauMinSlackObjective(final CanonicalSimplexProgram simplexProgram) { + public TableauMinSlackObjective(final @NotNull CanonicalSimplexProgram simplexProgram) { super(simplexProgram.parameters.A); // now make the slacks feasible xCol = simplexProgram.parameters.b.clone(); // equal to b since we start with unit vectors as initial left vectors diff --git a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/TableauWithSlackVariables.java b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/TableauWithSlackVariables.java index 110f17d2a770324cb1ce761b9a7555e8f24817b6..f22c28dae60c078bb8e1a658927417589fc9081c 100644 --- a/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/TableauWithSlackVariables.java +++ b/src/main/java/plugins/nchenouard/linearprogrammingfullsimplex/TableauWithSlackVariables.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023. Institut Pasteur. + * Copyright (c) 2010-2024. Institut Pasteur. * * This file is part of Icy. * Icy is free software: you can redistribute it and/or modify @@ -18,6 +18,9 @@ package plugins.nchenouard.linearprogrammingfullsimplex; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.jetbrains.annotations.NotNull; + /** * Tableau used for Gauss-Jordan elimination. * Initial basis is built by using slack variables. @@ -88,7 +91,7 @@ public class TableauWithSlackVariables { * * @param parameters parameters defining the linear optimization problem. */ - public TableauWithSlackVariables(final CanonicalProgramParameters parameters) { + public TableauWithSlackVariables(final @NotNull CanonicalProgramParameters parameters) { createVectors(parameters.A); // constraint value column xCol = parameters.b.clone(); // equal to b since we start with unit vectors as initial left vectors // build the score row @@ -141,7 +144,7 @@ public class TableauWithSlackVariables { * * @param A Constraint matrix. Each element A[i] defines a linear combination of the variable corresponding to a constraint. */ - protected void createVectors(final double[][] A) { + protected void createVectors(final double @NotNull [] @NotNull [] A) { final int numConstraints = A.length; numVariables = A[0].length; numCol = numConstraints + numVariables; @@ -174,42 +177,39 @@ public class TableauWithSlackVariables { * Print the tableau */ public void printTableau() { - System.out.println("Column vectors"); + IcyLogger.trace(this.getClass(), "Column vectors"); for (int i = 0; i < columnVectors.length; i++) { final double[] vector = columnVectors[i]; - System.out.print("a" + i + " = ["); + IcyLogger.trace(this.getClass(), "a" + i + " = ["); for (final double v : vector) - System.out.print(v + ", "); - System.out.println("]'"); + IcyLogger.trace(this.getClass(), v + ", "); + IcyLogger.trace(this.getClass(), "]'"); } - System.out.println("Basis vectors"); + IcyLogger.trace(this.getClass(), "Basis vectors"); for (int i = 0; i < leftVectorsIdx.length; i++) { final double[] vector = columnVectors[leftVectorsIdx[i]]; - System.out.print("v" + i + " = ["); + IcyLogger.trace(this.getClass(), "v" + i + " = ["); for (final double v : vector) - System.out.print(v + ", "); - System.out.println("]'"); + IcyLogger.trace(this.getClass(), v + ", "); + IcyLogger.trace(this.getClass(), "]'"); } - System.out.println("Tableau"); + IcyLogger.trace(this.getClass(), "Tableau"); for (final double[] doubles : tableau) { for (final double aDouble : doubles) - System.out.print(aDouble + " "); - System.out.println(); + IcyLogger.trace(this.getClass(), aDouble + " "); } - System.out.println(); - System.out.print("x = ["); + IcyLogger.trace(this.getClass(), "x = ["); for (final double v : xCol) - System.out.print(v + ", "); - System.out.println("]'"); + IcyLogger.trace(this.getClass(), v + ", "); + IcyLogger.trace(this.getClass(), "]'"); - System.out.println(); - System.out.print("score row = ["); + IcyLogger.trace(this.getClass(), "score row = ["); for (final double v : scoreRow) - System.out.print(v + ", "); - System.out.println("]'"); + IcyLogger.trace(this.getClass(), v + ", "); + IcyLogger.trace(this.getClass(), "]'"); - System.out.println("Score = " + scoreValue); + IcyLogger.trace(this.getClass(), "Score = " + scoreValue); } /** diff --git a/src/main/resources/linear-programming.png b/src/main/resources/linear-programming.png new file mode 100644 index 0000000000000000000000000000000000000000..1fa196a7fa57ccec31dd2c97d41796e623c8be23 Binary files /dev/null and b/src/main/resources/linear-programming.png differ