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