001package org.cpsolver.ifs.assignment.context;
002
003import org.cpsolver.ifs.assignment.Assignment;
004import org.cpsolver.ifs.model.Model;
005import org.cpsolver.ifs.model.Value;
006import org.cpsolver.ifs.model.Variable;
007
008/**
009 * A model with an assignment context. In order to be able to hold multiple assignments in memory
010 * it is desired for all the assignment dependent data a constraint may need (to effectively enumerate
011 * problem objectives), to store these data in a separate class (implementing the 
012 * {@link AssignmentConstraintContext} interface). This context is created by calling
013 * {@link ConstraintWithContext#createAssignmentContext(Assignment)} and accessed by
014 * {@link ConstraintWithContext#getContext(Assignment)}.
015 * 
016 * 
017 * @see AssignmentContext
018 * 
019 * @version IFS 1.3 (Iterative Forward Search)<br>
020 *          Copyright (C) 2014 Tomáš Müller<br>
021 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
022 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
023 * <br>
024 *          This library is free software; you can redistribute it and/or modify
025 *          it under the terms of the GNU Lesser General Public License as
026 *          published by the Free Software Foundation; either version 3 of the
027 *          License, or (at your option) any later version. <br>
028 * <br>
029 *          This library is distributed in the hope that it will be useful, but
030 *          WITHOUT ANY WARRANTY; without even the implied warranty of
031 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
032 *          Lesser General Public License for more details. <br>
033 * <br>
034 *          You should have received a copy of the GNU Lesser General Public
035 *          License along with this library; if not see <a href='http://www.gnu.org/licenses'>http://www.gnu.org/licenses</a>.
036 * @param <V> Variable
037 * @param <T> Value
038 * @param <C> Assignment Context
039 **/
040public abstract class ModelWithContext<V extends Variable<V, T>, T extends Value<V, T>, C extends AssignmentConstraintContext<V, T>> extends Model<V, T> implements HasAssignmentContext<V, T, C>, CanHoldContext {
041    
042    private AssignmentContextReference<V, T, C> iContextReference = null;
043    private AssignmentContext[] iContext = new AssignmentContext[CanHoldContext.sMaxSize];
044    
045    /**
046     * Defines how the context of the model should be automatically updated (i.e., when {@link AssignmentConstraintContext#assigned(Assignment, Value)} and {@link AssignmentConstraintContext#unassigned(Assignment, Value)} are called).
047     */
048    protected static enum ContextUpdateType {
049        /** Update is done before an unassignment and before an assignment. */
050        BeforeUnassignedBeforeAssigned,
051        /** Update is done after an unassignment and before an assignment. */
052        AfterUnassignedBeforeAssigned,
053        /** Update is done before an unassignment and after an assignment. */
054        BeforeUnassignedAfterAssigned,
055        /** Update is done after an unassignment and after an assignment. This is the default. */
056        AfterUnassignedAfterAssigned,
057        /** Context is to be updated manually. */
058        NoUpdate
059    }
060    private ContextUpdateType iContextUpdateType = ContextUpdateType.BeforeUnassignedAfterAssigned;
061    
062    public ModelWithContext() {
063        super();
064        iContextReference = createReference(this);
065    }
066    
067    /**
068     * Returns an assignment context associated with this model. If there is no 
069     * assignment context associated with this model yet, one is created using the
070     * {@link ConstraintWithContext#createAssignmentContext(Assignment)} method. From that time on,
071     * this context is kept with the assignment and automatically updated by calling the
072     * {@link AssignmentConstraintContext#assigned(Assignment, Value)} and {@link AssignmentConstraintContext#unassigned(Assignment, Value)}
073     * whenever a variable is changed.
074     * @param assignment given assignment
075     * @return assignment context associated with this model and the given assignment
076     */
077    @Override
078    public C getContext(Assignment<V, T> assignment) {
079        return AssignmentContextHelper.getContext(this, assignment);
080    }
081
082    @Override
083    public AssignmentContextReference<V, T, C> getAssignmentContextReference() { return iContextReference; }
084
085    @Override
086    public void setAssignmentContextReference(AssignmentContextReference<V, T, C> reference) { iContextReference = reference; }
087
088    @Override
089    public AssignmentContext[] getContext() { return iContext; }
090    
091    @Override
092    public void beforeUnassigned(Assignment<V, T> assignment, long iteration, T value) {
093        super.beforeUnassigned(assignment, iteration, value);
094        switch (getContextUpdateType()) {
095            case BeforeUnassignedAfterAssigned:
096            case BeforeUnassignedBeforeAssigned:
097                getContext(assignment).unassigned(assignment, value);
098        }
099    }
100    
101    @Override
102    public void afterUnassigned(Assignment<V, T> assignment, long iteration, T value) {
103        super.afterUnassigned(assignment, iteration, value);
104        switch (getContextUpdateType()) {
105            case AfterUnassignedAfterAssigned:
106            case AfterUnassignedBeforeAssigned:
107                getContext(assignment).unassigned(assignment, value);
108        }
109    }
110    
111    @Override
112    public void afterAssigned(Assignment<V, T> assignment, long iteration, T value) {
113        super.afterAssigned(assignment, iteration, value);
114        switch (getContextUpdateType()) {
115            case AfterUnassignedAfterAssigned:
116            case BeforeUnassignedAfterAssigned:
117                getContext(assignment).assigned(assignment, value);
118        }
119    }
120    
121    @Override
122    public void beforeAssigned(Assignment<V, T> assignment, long iteration, T value) {
123        super.beforeAssigned(assignment, iteration, value);
124        switch (getContextUpdateType()) {
125            case AfterUnassignedBeforeAssigned:
126            case BeforeUnassignedBeforeAssigned:
127                getContext(assignment).assigned(assignment, value);
128        }
129    }
130
131    public ContextUpdateType getContextUpdateType() {
132        return iContextUpdateType;
133    }
134
135    public void setContextUpdateType(ContextUpdateType iContextUpdateType) {
136        this.iContextUpdateType = iContextUpdateType;
137    }
138
139}