Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Update to choco 4.10.10 #53

Closed
arnaud-m opened this issue Nov 17, 2022 · 4 comments · Fixed by #77
Closed

[FEATURE] Update to choco 4.10.10 #53

arnaud-m opened this issue Nov 17, 2022 · 4 comments · Fixed by #77
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@arnaud-m
Copy link
Owner

Is your feature request related to a problem? Please describe.
Update choco to benefit from the latest enhancements and to seek support more easily.

Describe the solution you'd like
Update to the latest choco release.

Additional context
A first attempt has shown that the expression handling has changed : some tests will fail.
We must determine if the tests fails because of a regression.
It requires to isolate the failing tests, hard-code the models and post issues in the choco project if needed.

@arnaud-m arnaud-m added the enhancement New feature or request label Nov 17, 2022
@arnaud-m arnaud-m added this to the v0.5.1 milestone Nov 22, 2022
@Imp95
Copy link
Collaborator

Imp95 commented Nov 28, 2022

JUnit tests that shows a case where choco found results in 4.10.6 but not in 4.10.10


import org.junit.Before;
import org.junit.Test;

import org.chocosolver.solver.Model;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.variables.IntVar;

public class LittleTest {

    public static Model model;
    public static IntVar copper, neon, iron, silver, result;

    @Before
    /***
     * Tests if choco can solve "copper*neon=iron*silver" via various way of writing constraints
     */
    public void setup(){
        model = new Model("copper*neon=iron*silver");
        //model.getSettings().getWelcomeMessage();
        copper = model.intVar("copper",100000,999999);
        neon = model.intVar("neon",1000,9999);
        iron = model.intVar("iron",1000,9999);
        silver = model.intVar("silver",100000,999999);
        //result is an intermediary to compare copper*neon and iron*silver
        //all test would fail if ub was equal to 'org.chocosolver.solver.variables.IntVar.MAX_INT_BOUND'
        result = model.intVar("result",0,org.chocosolver.solver.variables.IntVar.MAX_INT_BOUND*10);

        model.allDifferent(new IntVar[]{copper,neon,iron,silver}).post();
    }

    @Test
    /***
     * Using times dirrectly to make our constraint
     * will fail to find any solution because value needed is out of result's bound
     */
    public void model1(){
        result = model.intVar("result",0,org.chocosolver.solver.variables.IntVar.MAX_INT_BOUND);
        model.times(copper, neon, result).post();
        model.times(silver, iron, result).post();
        Solver solver = model.getSolver();
        //solver.showStatistics();
        //solver.showSolutions();
        solver.findSolution();
        //solver.printVersion();
        assertEquals(solver.getSolutionCount(),0);
    }
    @Test
    /***
     * Working version of the previous test.
     */
    public void model1Success(){
        model.times(copper, neon, result).post();
        model.times(silver, iron, result).post();
        Solver solver = model.getSolver();
        //solver.showStatistics();
        //solver.showSolutions();
        solver.findSolution();
        //solver.printVersion();
        assertEquals(solver.getSolutionCount(),1);
    }
    @Test
    /***
     * Creating a model using arithm instead of times directly.
     */
    public void model2(){
        model.arithm(copper, "*",neon,"=",result).post();
        model.arithm(iron, "*",silver,"=",result).post();
        Solver solver = model.getSolver();
        solver.findSolution();
        assertEquals(solver.getSolutionCount(),1);
    }
    @Test
    /***
     * Creating a model using the operators function given by IntVar
     */
    public void model3(){
        copper.mul(neon).eq(result).post();
        iron.mul(silver).eq(result).post();
        System.out.println(model.toString());
        Solver solver = model.getSolver();
        solver.findSolution();
        assertEquals(solver.getSolutionCount(),1);
    }
    @Test
    /***
     * Creating a model using the operators function given by IntVar without using result as an intermediary
     */
    public void model4(){
        copper.mul(neon).eq(iron.mul(silver)).post();
        System.out.println(model.toString());
        Solver solver = model.getSolver();
        solver.findSolution();
        assertEquals(solver.getSolutionCount(),1);
    }
}

@arnaud-m
Copy link
Owner Author

My conclusions are that:

  • The use of MAX_INT_BOUND is unclear, because it is not checked when creating a variable (see setupResult).
  • The introduction of auxiliary variable is an issue (see for instance model1 and model2).

The issue is that the domain of the right member (result) is not used for defining the domain of the auxiliary variable.
For instance, it is the case for the arithm constraint : see here or just below.

                    // v1 * v2 OP v3
                    int[] bounds = VariableUtils.boundsForMultiplication(var1, var2);
                    IntVar var4 = ref().intVar(bounds[0], bounds[1]);
                    ref().times(var1, var2, var4).post();
                    return arithm(var4, op2, var3);

In this case, it is unclear to me why the variable v4 is introduced.

I have slightly improved the code. You can find it below.

import org.chocosolver.solver.Model;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.variables.IntVar;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class ProductTest {

    private Model model;
    private IntVar copper, neon, iron, silver, result;

    @Before
    /***
     * Tests if choco can solve "copper*neon=iron*silver" via various way of writing constraints
     */
    public void setup(){
        model = new Model("copper*neon=iron*silver");
        copper = model.intVar("copper",100000,999999);
        neon = model.intVar("neon",1000,9999);
        iron = model.intVar("iron",1000,9999);
        silver = model.intVar("silver",100000,999999);
        model.allDifferent(new IntVar[]{copper,neon,iron,silver}).post();
    }
    
    public void setupResult(int factor) {
      //result is an intermediary to compare copper*neon and iron*silver
      //all test would fail if factor = 1.
        result = model.intVar("result",0, factor * IntVar.MAX_INT_BOUND);
    }
    
    public void solve(int solutionCount) {
        Solver solver = model.getSolver();
        System.out.println(model);
        solver.printVersion();
        solver.showStatistics();
        solver.showSolutions();
        solver.findSolution();
        Assert.assertEquals(solutionCount, solver.getSolutionCount());
    }
        

    @Test
    /***
     * Using times directly to make our constraint
     * will fail to find any solution because value needed is greater than the result's upper bound.
     */
    public void model1NoSol(){
        setupResult(1);
        model.times(copper, neon, result).post();
        model.times(silver, iron, result).post();
        solve(0);
    }
    
    @Test
    /***
     * Working version of the previous test.
     */
    public void model1(){
        setupResult(10);        
        model.times(copper, neon, result).post();
        model.times(silver, iron, result).post();
        solve(1);
    }
    @Test
    /***
     * Creating a model using arithm instead of times directly.
     */
    public void model2(){
        setupResult(10);        
        model.arithm(copper, "*",neon,"=",result).post();
        model.arithm(iron, "*",silver,"=",result).post();
        solve(1);
    }
    @Test
    /***
     * Creating a model using the operators function given by IntVar
     */
    public void model3(){
        setupResult(10);        
        copper.mul(neon).eq(result).post();
        iron.mul(silver).eq(result).post();
        solve(1);
    }
    @Test
    /***
     * Creating a model using the operators function given by IntVar without using result as an intermediary
     */
    public void model4(){
        copper.mul(neon).eq(iron.mul(silver)).post();
        solve(1);
    }
}

@arnaud-m
Copy link
Owner Author

You can now move the tests in Failing.java with a comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants