001package org.cpsolver.ifs.assignment;
002
003import java.util.Arrays;
004import java.util.Collection;
005import java.util.HashMap;
006import java.util.Map;
007import java.util.concurrent.locks.ReentrantReadWriteLock;
008
009import org.cpsolver.ifs.assignment.context.DefaultParallelAssignmentContextHolder;
010import org.cpsolver.ifs.model.Model;
011import org.cpsolver.ifs.model.Value;
012import org.cpsolver.ifs.model.Variable;
013import org.cpsolver.ifs.solver.ParallelSolver;
014
015
016/**
017 * An assignment using the {@link Variable#setAssignments(Value[])} to store values of all the
018 * variables of the model. Besides of that, a set of assigned variables is kept in memory.
019 * Each extra contains an array of values, indexed by {@link Assignment#getIndex()}.
020 * Useful for a small, fixed number of assignments. Used by the {@link ParallelSolver},
021 * where there is one assignment for each thread. 
022 * 
023 * @see Assignment
024 * @see ParallelSolver
025 * 
026 * @version IFS 1.3 (Iterative Forward Search)<br>
027 *          Copyright (C) 2014 Tomas Muller<br>
028 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
029 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
030 * <br>
031 *          This library is free software; you can redistribute it and/or modify
032 *          it under the terms of the GNU Lesser General Public License as
033 *          published by the Free Software Foundation; either version 3 of the
034 *          License, or (at your option) any later version. <br>
035 * <br>
036 *          This library is distributed in the hope that it will be useful, but
037 *          WITHOUT ANY WARRANTY; without even the implied warranty of
038 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
039 *          Lesser General Public License for more details. <br>
040 * <br>
041 *          You should have received a copy of the GNU Lesser General Public
042 *          License along with this library; if not see <a href='http://www.gnu.org/licenses'>http://www.gnu.org/licenses</a>.
043 * @param <V> Variable
044 * @param <T> Value
045 **/
046public class DefaultParallelAssignment <V extends Variable<V, T>, T extends Value<V, T>> extends AssignmentAbstract<V, T> {
047    private Map<V, Long> iAssignedVariables = new HashMap<V, Long>();
048    private int iIndex;
049    private final ReentrantReadWriteLock iLock = new ReentrantReadWriteLock();
050
051    public DefaultParallelAssignment(int threadIndex) {
052        super(new DefaultParallelAssignmentContextHolder<V, T>(threadIndex));
053        iIndex = threadIndex;
054    }
055    
056    public DefaultParallelAssignment() {
057        this(0);
058    }
059    
060    public DefaultParallelAssignment(int threadIndex, Model<V, T> model, Assignment<V, T> assignment) {
061        this(threadIndex);
062        for (V variable: model.variables())
063            setValueInternal(0, variable, assignment != null ? assignment.getValue(variable) : null);
064    }
065
066    @Override
067    public long getIteration(V variable) {
068        Long it = iAssignedVariables.get(variable);
069        return (it == null ? 0 : it.longValue());
070    }
071
072    @Override
073    public Collection<V> assignedVariables() {
074        return iAssignedVariables.keySet();
075    }
076    
077    @SuppressWarnings({ "unchecked", "deprecation" })
078    protected T[] getAssignments(V variable) {
079        iLock.readLock().lock();
080        try {
081            T[] assignments = variable.getAssignments();
082            if (assignments != null && iIndex < assignments.length) return assignments;
083        } finally {
084            iLock.readLock().unlock();
085        }
086        iLock.writeLock().lock();
087        try {
088            T[] assignments = variable.getAssignments();
089            if (assignments == null) {
090                assignments = (T[])new Value[Math.max(10, 1 + iIndex)];
091                variable.setAssignments(assignments);
092            } else if (assignments.length <= iIndex) {
093                assignments = Arrays.copyOf(assignments, 10 + iIndex);
094                variable.setAssignments(assignments);
095            }
096            return assignments;
097        } finally {
098            iLock.writeLock().unlock();
099        }
100    }
101
102    @Override
103    protected T getValueInternal(V variable) {
104        return getAssignments(variable)[iIndex];
105    }
106    
107    @Override
108    protected void setValueInternal(long iteration, V variable, T value) {
109        getAssignments(variable)[iIndex] = value;
110        if (value == null)
111            iAssignedVariables.remove(variable);
112        else
113            iAssignedVariables.put(variable, iteration);
114    }
115
116    @Override
117    public int getIndex() {
118        return iIndex;
119    }
120}