-
Notifications
You must be signed in to change notification settings - Fork 153
Fix faulty behaviour of #1114 #1117
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
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,15 +9,14 @@ | |
| */ | ||
| package org.chocosolver.solver.variables; | ||
|
|
||
| import org.chocosolver.solver.ICause; | ||
| import org.chocosolver.solver.Model; | ||
| import org.chocosolver.solver.constraints.Constraint; | ||
| import org.chocosolver.solver.exception.ContradictionException; | ||
| import org.chocosolver.solver.learn.ExplanationForSignedClause; | ||
| import org.chocosolver.solver.variables.events.IEventType; | ||
| import org.chocosolver.solver.variables.events.IntEventType; | ||
| import org.chocosolver.solver.variables.view.integer.IntAffineView; | ||
| import org.chocosolver.util.objects.setDataStructures.iterable.IntIterableRangeSet; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.function.Consumer; | ||
|
|
||
| import static org.chocosolver.util.objects.setDataStructures.iterable.IntIterableSetUtils.unionOf; | ||
|
|
@@ -29,7 +28,7 @@ | |
| * @author Jean-Guillaume Fages | ||
| * @since 04/02/2013 | ||
| */ | ||
| public class Task { | ||
| public class Task implements ICause { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused: the Task object was initially designed to maintain the relationship between start, duration and end during propagation. Now, if the relation is maintained explicitly by propagators, what is the purpose of Task ? |
||
|
|
||
| //*********************************************************************************** | ||
| // VARIABLES | ||
|
|
@@ -38,7 +37,7 @@ public class Task { | |
| private final IntVar start; | ||
| private final IntVar duration; | ||
| private final IntVar end; | ||
| private IVariableMonitor<IntVar> update; | ||
| private Constraint arithmConstraint; | ||
|
|
||
| //*********************************************************************************** | ||
| // CONSTRUCTORS | ||
|
|
@@ -53,17 +52,12 @@ public class Task { | |
| * @param lst latest starting time | ||
| * @param d duration | ||
| * @param ect earliest completion time | ||
| * @param lct latest completion time time | ||
| * @param lct latest completion time | ||
| */ | ||
| public Task(Model model, int est, int lst, int d, int ect, int lct) { | ||
| start = model.intVar(est, lst); | ||
| start = model.intVar(Math.max(est, ect - d), Math.min(lst, lct - d)); | ||
| duration = model.intVar(d); | ||
| if(ect == est+d && lct == lst+d) { | ||
| end = start.getModel().offset(start, d); | ||
| } else { | ||
| end = model.intVar(ect, lct); | ||
| declareMonitor(); | ||
| } | ||
| end = start.getModel().offset(start, d); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -79,6 +73,27 @@ public Task(IntVar s, int d) { | |
| end = start.getModel().offset(start, d); | ||
| } | ||
|
|
||
| /** | ||
| * Container representing a task: | ||
| * It ensures that: start + duration = end, end being an offset view of start + duration. | ||
| * | ||
| * @param s start variable | ||
| * @param d duration value | ||
| */ | ||
| public Task(IntVar s, IntVar d) { | ||
| if (d.isInstantiated()) { | ||
| start = s; | ||
| duration = d; | ||
| end = start.getModel().offset(start, d.getValue()); | ||
| } else { | ||
| start = s; | ||
| duration = d; | ||
| end = start.getModel().intVar(s.getLB() + d.getLB(), s.getUB() + d.getUB()); | ||
| arithmConstraint = start.getModel().arithm(start, "+", duration, "=", end); | ||
| arithmConstraint.post(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Container representing a task: | ||
| * It ensures that: start + duration = end, end being an offset view of start + duration. | ||
|
|
@@ -88,12 +103,7 @@ public Task(IntVar s, int d) { | |
| * @param e end variable | ||
| */ | ||
| public Task(IntVar s, int d, IntVar e) { | ||
| start = s; | ||
| duration = start.getModel().intVar(d); | ||
| end = e; | ||
| if(!isOffsetView(s, d, e)) { | ||
| declareMonitor(); | ||
| } | ||
| this(s, s.getModel().intVar(d), e); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -105,38 +115,32 @@ public Task(IntVar s, int d, IntVar e) { | |
| * @param e end variable | ||
| */ | ||
| public Task(IntVar s, IntVar d, IntVar e) { | ||
| this(s, d, e, !d.isInstantiated() || !isOffsetView(s, d.getValue(), e)); | ||
| } | ||
|
|
||
| private Task(IntVar s, IntVar d, IntVar e, boolean postArithm) { | ||
| start = s; | ||
| duration = d; | ||
| end = e; | ||
| if(!d.isInstantiated() || !isOffsetView(s, d.getValue(), e)) { | ||
| declareMonitor(); | ||
| if (postArithm) { | ||
| arithmConstraint = start.getModel().arithm(start, "+", duration, "=", end); | ||
| arithmConstraint.post(); | ||
| } | ||
| } | ||
|
|
||
| private static boolean isOffsetView(IntVar s, int d, IntVar e) { | ||
| if(e instanceof IntAffineView) { | ||
| IntAffineView<?> intOffsetView = (IntAffineView<?>) e; | ||
| return intOffsetView.equals(s, 1, d); | ||
| if (intOffsetView.p) { | ||
| return intOffsetView.equals(s, 1, d); | ||
| } else { | ||
| intOffsetView = (IntAffineView<?>) s; | ||
| return intOffsetView.equals(e.neg().intVar(), -1, -d); | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| private void declareMonitor() { | ||
| if (start.hasEnumeratedDomain() || duration.hasEnumeratedDomain() || end.hasEnumeratedDomain()) { | ||
| update = new TaskMonitor(start, duration, end, true); | ||
| } else { | ||
| update = new TaskMonitor(start, duration, end, false); | ||
| } | ||
| Model model = start.getModel(); | ||
| //noinspection unchecked | ||
| ArrayList<Task> tset = (ArrayList<Task>) model.getHook(Model.TASK_SET_HOOK_NAME); | ||
| if(tset == null){ | ||
| tset = new ArrayList<>(); | ||
| model.addHook(Model.TASK_SET_HOOK_NAME, tset); | ||
| } | ||
| tset.add(this); | ||
| } | ||
|
|
||
| //*********************************************************************************** | ||
| // METHODS | ||
| //*********************************************************************************** | ||
|
|
@@ -147,7 +151,15 @@ private void declareMonitor() { | |
| * @throws ContradictionException thrown if a inconsistency has been detected between start, end and duration | ||
| */ | ||
| public void ensureBoundConsistency() throws ContradictionException { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here again, is this method still relevant? |
||
| update.onUpdate(start, IntEventType.REMOVE); | ||
| boolean hasFiltered; | ||
| do { | ||
| // start | ||
| hasFiltered = start.updateBounds(end.getLB() - duration.getUB(), end.getUB() - duration.getLB(), this); | ||
| // end | ||
| hasFiltered |= end.updateBounds(start.getLB() + duration.getLB(), start.getUB() + duration.getUB(), this); | ||
| // duration | ||
| hasFiltered |= duration.updateBounds(end.getLB() - start.getUB(), end.getUB() - start.getLB(), this); | ||
| } while (hasFiltered); | ||
| } | ||
|
|
||
| //*********************************************************************************** | ||
|
|
@@ -166,8 +178,8 @@ public IntVar getEnd() { | |
| return end; | ||
| } | ||
|
|
||
| public IVariableMonitor<IntVar> getMonitor() { | ||
| return update; | ||
| public Constraint getArithmConstraint() { | ||
| return arithmConstraint; | ||
| } | ||
|
|
||
| private static void doExplain(IntVar S, IntVar D, IntVar E, | ||
|
|
@@ -201,54 +213,21 @@ private static void doExplain(IntVar S, IntVar D, IntVar E, | |
| @Override | ||
| public String toString() { | ||
| return "Task[" + | ||
| "start=" + start + | ||
| ", duration=" + duration + | ||
| ", end=" + end + | ||
| ']'; | ||
| } | ||
|
|
||
| private static class TaskMonitor implements IVariableMonitor<IntVar> { | ||
| private final IntVar S, D, E; | ||
| private final boolean isEnum; | ||
|
|
||
| private TaskMonitor(IntVar S, IntVar D, IntVar E, boolean isEnum) { | ||
| this.S = S; | ||
| this.D = D; | ||
| this.E = E; | ||
| S.addMonitor(this); | ||
| D.addMonitor(this); | ||
| E.addMonitor(this); | ||
| this.isEnum = isEnum; | ||
| } | ||
|
|
||
| @Override | ||
| public void onUpdate(IntVar var, IEventType evt) throws ContradictionException { | ||
| boolean fixpoint; | ||
| do { | ||
| // start | ||
| fixpoint = S.updateBounds(E.getLB() - D.getUB(), E.getUB() - D.getLB(), this); | ||
| // end | ||
| fixpoint |= E.updateBounds(S.getLB() + D.getLB(), S.getUB() + D.getUB(), this); | ||
| // duration | ||
| fixpoint |= D.updateBounds(E.getLB() - S.getUB(), E.getUB() - S.getLB(), this); | ||
| } while (fixpoint && isEnum); | ||
| } | ||
|
|
||
| @Override | ||
| public void explain(int p, ExplanationForSignedClause explanation) { | ||
| doExplain(S, D, E, p, explanation); | ||
| } | ||
| "start=" + start + | ||
| ", duration=" + duration + | ||
| ", end=" + end + | ||
| ']'; | ||
| } | ||
|
|
||
| @Override | ||
| public void forEachIntVar(Consumer<IntVar> action) { | ||
| action.accept(S); | ||
| action.accept(D); | ||
| action.accept(E); | ||
| } | ||
| @Override | ||
| public void explain(int p, ExplanationForSignedClause explanation) { | ||
| doExplain(start, duration, end, p, explanation); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "Task["+S.getName()+"+"+D.getName()+"="+E.getName()+"]"; | ||
| } | ||
| @Override | ||
| public void forEachIntVar(Consumer<IntVar> action) { | ||
| action.accept(start); | ||
| action.accept(duration); | ||
| action.accept(end); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -106,6 +106,8 @@ public void test5(){ | |
|
|
||
| @Test(groups="10s", timeOut=60000) | ||
| public void test6(){ | ||
| long time = System.currentTimeMillis(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be removed |
||
| while ((System.currentTimeMillis() - time) < 10000); | ||
| // this tests raises an exception which is in fact due to the time limit | ||
| // and unlucky random heuristic (fixed by adding last conflict) | ||
| test(16,3,2,4,4,1); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if we don't do that at all and leave it to arithm ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said, the idea is to avoid a ping-pong between arithm constraints and the cumulative one, as the latter could be long to initiate. But maybe it is OK to allow it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I found a new reason : some filtering algorithms rely on the hypothesis of the task relation, especially the one in NRJCumulFilter
But I still can't really explain why we have the performance issues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the slow donw mainly comes from the fact that, with views, only the modified tasks are updated and with the proposal all of them are updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One possible way to avoid iterating over all tasks is to use IVariableMonitor to store modified tasks and only iterate over them. This is, for example, what is done in ActivityBased search.