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
      *                     &lt;=.
      */
-    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