EqualToSum.java
/* Copyright 2015 Laurent COCAULT
* Licensed to Laurent COCAULT under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Laurent COCAULT licenses this file to You
* under the Apache License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.csp.constraint.model.integer;
import org.csp.constraint.model.TernaryConstraint;
/**
* Constraint specifying that one specific integer variable is the sum of two
* other integer variables.
*/
public class EqualToSum extends TernaryConstraint<IntValue> {
/**
* Constructor of the constraint "FIRST + SECOND = SUM".
* @param first
* First variable
* @param second
* Second variable
* @param sum
* Sum of the two other variables
*/
public EqualToSum(final IntVar first, final IntVar second, final IntVar sum) {
super(first.getName() + "+" + second.getName() + "=" + sum.getName(),
first, second, sum);
}
/**
* {@inheritDoc}
*/
@Override
public void propagate() {
// The sum minimum is the sum of the other variables minimum and the
// sum maximum is the sum of the other variables maximum.
final IntValue sumMin = IntValue.sum(getFirst().getMinValue(),
getSecond().getMinValue());
final boolean sumMinChanged = getSum().reduceWithMinValue(sumMin);
final IntValue sumMax = IntValue.sum(getFirst().getMaxValue(),
getSecond().getMaxValue());
final boolean sumMaxChanged = getSum().reduceWithMaxValue(sumMax);
if (sumMaxChanged || sumMinChanged) {
addRecentChangedVariable(getSum());
}
// Propagate the constraint on the first variable
propagateOnArgument(getFirst(), getSecond(), getSum());
// Propagate the constraint on the second variable
propagateOnArgument(getSecond(), getFirst(), getSum());
}
/**
* Propagate the constraint on an argument. The propagation algorithm is the
* same on the first or the second argument of the constraint: the current
* method is therefore applied twice with a permutation of the variables.
* @param argument
* Argument on which to propagate the constraint
* @param other
* Other argument in the sum
* @param sum
* Sum of the two arguments
*/
private void propagateOnArgument(final IntVar argument, final IntVar other,
final IntVar sum) {
// The argument maximum shall not be greater than the difference between
// the "sum" maximum and the "other" minimum.
final IntValue newMax = IntValue.diff(sum.getMaxValue(),
other.getMinValue());
final boolean maxChanged = argument.reduceWithMaxValue(newMax);
// The argument minimum shall not be lesser than the difference between
// the "sum" minimum and the "other" maximum.
final IntValue newMin = IntValue.diff(sum.getMinValue(),
other.getMaxValue());
final boolean minChanged = argument.reduceWithMinValue(newMin);
if (maxChanged || minChanged) {
addRecentChangedVariable(argument);
}
}
/**
* Get the first argument of the constraint.
* @return First argument
*/
protected IntVar getFirst() {
return (IntVar) getFirstVariable();
}
/**
* Get the second argument of the constraint.
* @return Second argument
*/
protected IntVar getSecond() {
return (IntVar) getSecondVariable();
}
/**
* Get the sum.
* @return Sum (third variable)
*/
protected IntVar getSum() {
return (IntVar) getThirdVariable();
}
}