All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.chocosolver.solver.variables.impl.SetVarImpl Maven / Gradle / Ivy

There is a newer version: 4.10.16
Show newest version
/**
 * Copyright (c) 2016, Ecole des Mines de Nantes
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the .
 * 4. Neither the name of the  nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY  ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.chocosolver.solver.variables.impl;

import gnu.trove.set.hash.TIntHashSet;
import org.chocosolver.solver.ICause;
import org.chocosolver.solver.Model;
import org.chocosolver.solver.constraints.Constraint;
import org.chocosolver.solver.constraints.set.PropCardinality;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.SetVar;
import org.chocosolver.solver.variables.delta.SetDelta;
import org.chocosolver.solver.variables.delta.monitor.SetDeltaMonitor;
import org.chocosolver.solver.variables.events.IEventType;
import org.chocosolver.solver.variables.events.SetEventType;
import org.chocosolver.util.objects.setDataStructures.ISet;
import org.chocosolver.util.objects.setDataStructures.SetFactory;
import org.chocosolver.util.objects.setDataStructures.SetType;
import org.chocosolver.util.objects.setDataStructures.Set_ReadOnly;

/**
 * Set variable to represent a set of integers, i.e. a value is a set
 *
 * @author Jean-Guillaume Fages
 * @since Oct 2012
 */
public class SetVarImpl extends AbstractVariable implements SetVar {

    //***********************************************************************************
    // VARIABLES
    //***********************************************************************************

    protected final ISet lb, ub, lbReadOnly, ubReadOnly;
    protected SetDelta delta;
    protected boolean reactOnModification;
    protected IntVar cardinality = null;

    //***********************************************************************************
    // CONSTRUCTORS
    //***********************************************************************************

	/**
	 * Creates a Set variable
	 *
	 * @param name		name of the variable
	 * @param ker		initial kernel domain
	 * @param kerType	data structure of the kernel
	 * @param env		initial envelope domain
	 * @param envType	data structure of the envelope
	 * @param model	solver of the variable.
	 */
	public SetVarImpl(String name, int[] ker, SetType kerType, int[] env, SetType envType, Model model) {
		super(name, model);
		ker = new TIntHashSet(ker).toArray();
		env = new TIntHashSet(env).toArray();
		int offSet = env.length>0?env[0]:0;
		for(int i:env){
			offSet = Math.min(offSet,i);
		}
		lb = SetFactory.makeStoredSet(kerType, offSet, model);
		ub = SetFactory.makeStoredSet(envType, offSet, model);
		lbReadOnly = new Set_ReadOnly(lb);
		ubReadOnly = new Set_ReadOnly(ub);
		for(int i:env){
			ub.add(i);
		}
		for(int i:ker){
			lb.add(i);
			if(!ub.contains(i)){
				throw new UnsupportedOperationException("Invalid SetVar domain definition : "
						+i+" is in the LB but not in the UB.");
			}
		}
	}

	/**
	 * Creates a set variable, of domain [lb, ub]
	 * Beware : Use this constructor with caution (domain is directly accessible)
	 * lb and ub should be created properly (e.g. lb subset of ub) and should not be modified externally
	 *
	 * Both lb and ub should be backtrackable sets (stored sets): use SetFactory.makeStoredSet to build them
	 *
	 * @param name		name of the variable
	 * @param lb		lower bound of the set variable (mandatory elements)
	 * @param ub		upper bound of the set variable (potential elements)
	 * @param model	solver of the variable.
	 */
	public SetVarImpl(String name, ISet lb, ISet ub, Model model) {
		super(name, model);
		this.lb = lb;
		this.ub = ub;
		lbReadOnly = new Set_ReadOnly(lb);
		ubReadOnly = new Set_ReadOnly(ub);
		for(int i:lb){
			if(!ub.contains(i)){
				throw new UnsupportedOperationException("Invalid SetVar domain definition : "
						+i+" is in the LB but not in the UB.");
			}
		}
	}

	/**
	 * Creates a fixed Set variable, equal to value
	 * Beware : Use this constructor with caution (domain is directly accessible)
	 * value should be created properly and should not be modified afterward
	 *
	 * @param name		name of the variable
	 * @param value		value of the set variable
	 * @param model	solver of the variable.
	 */
	public SetVarImpl(String name, ISet value, Model model) {
		super(name, model);
		lb = value;
		ub = lb;
		lbReadOnly = new Set_ReadOnly(lb);
		ubReadOnly = new Set_ReadOnly(ub);
	}

	/**
	 * Creates a fixed Set variable, equal to value
	 *
	 * @param name		name of the variable
	 * @param value		value of the set variable
	 * @param model	solver of the variable.
	 */
	public SetVarImpl(String name, int[] value, Model model) {
		super(name, model);
		lb = SetFactory.makeConstantSet(new TIntHashSet(value).toArray());
		ub = lb;
		lbReadOnly = new Set_ReadOnly(lb);
		ubReadOnly = new Set_ReadOnly(ub);
	}

	//***********************************************************************************
    // METHODS
    //***********************************************************************************

    @Override
    public boolean isInstantiated() {
        return ub.size() == lb.size();
    }

	@Override
	public ISet getLB() {
		return lbReadOnly;
	}

	@Override
	public ISet getUB() {
		return ubReadOnly;
	}
	
	@Override
	public IntVar getCard() {
		if(!hasCard()){
			int ubc =  ub.size(), lbc = lb.size();
			if(ubc==lbc) cardinality = model.intVar(ubc);
			else{
				cardinality = model.intVar(name+".card", lbc, ubc);
				new Constraint("SetCard", new PropCardinality(this, cardinality)).post();
			}
		}
		return cardinality;
	}
	
	@Override
	public boolean hasCard() {
            return cardinality != null;
	}
        
	@Override
	public void setCard(IntVar card) {
		if(!hasCard()){
			cardinality=card;
			new Constraint("SetCard", new PropCardinality(this, card)).post();
		} else {
			model.arithm(cardinality, "=", card).post();
		}
	}

	@Override
    public boolean force(int element, ICause cause) throws ContradictionException {
        assert cause != null;
        if (!ub.contains(element)) {
            contradiction(cause, "");
            return true;
        }
        if (lb.add(element)) {
			if (reactOnModification) {
				delta.add(element, SetDelta.LB, cause);
			}
			SetEventType e = SetEventType.ADD_TO_KER;
			notifyPropagators(e, cause);
			return true;
		}
		return false;
    }

    @Override
    public boolean remove(int element, ICause cause) throws ContradictionException {
        assert cause != null;
        if (lb.contains(element)) {
            contradiction(cause, "");
            return true;
        }
		if (ub.remove(element)) {
			if (reactOnModification) {
				delta.add(element, SetDelta.UB, cause);
			}
			SetEventType e = SetEventType.REMOVE_FROM_ENVELOPE;
			notifyPropagators(e, cause);
			return true;
		}
        return false;
    }

    @Override
    public boolean instantiateTo(int[] value, ICause cause) throws ContradictionException {
        boolean changed = !isInstantiated();
        for (int i : value) {
            force(i, cause);
        }
        if (lb.size() != value.length) {
            contradiction(cause, "");
        }
        if (ub.size() != value.length) {
            for (int i : getUB()) {
                if (!getLB().contains(i)) {
                    remove(i, cause);
                }
            }
        }
        return changed;
    }

    @Override
    public SetDelta getDelta() {
        return delta;
    }

    @Override
    public int getTypeAndKind() {
        return VAR | SET;
    }

    @Override
    public String toString() {
		if(isInstantiated()){
			return getName()+" = "+getLB().toString();
		}else {
			return getName()+" = ["+getLB()+", "+getUB()+"]";
		}
    }

    @Override
    public void createDelta() {
        if (!reactOnModification) {
            reactOnModification = true;
            delta = new SetDelta(model.getEnvironment());
        }
    }

    @Override
    public SetDeltaMonitor monitorDelta(ICause propagator) {
        createDelta();
        return new SetDeltaMonitor(delta, propagator);
    }

    @Override
    public void notifyMonitors(IEventType event) throws ContradictionException {
        for (int i = mIdx - 1; i >= 0; i--) {
            monitors[i].onUpdate(this, event);
        }
    }

    @Override
    public void contradiction(ICause cause, String message) throws ContradictionException {
        assert cause != null;
        model.getSolver().getEngine().fails(cause, this, message);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy