/*
* Kodkod -- Copyright (c) 2005-present, Emina Torlak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package kodkod.engine.bool;
import java.util.Iterator;
import java.util.Set;
import kodkod.util.collections.Containers;
import kodkod.util.ints.Ints;
/**
* An if-then-else gate.
*
* @specfield ifFormula: BooleanFormula
* @specfield thenFormula: BooleanFormula
* @specfield elseFormula: BooleanFormula
* @invariant inputs = 0->ifFormula + 1->thenFormula + 2->elseFormula
* @invariant this.label > 0
* @invariant this.op = Operator.ITE
* @specfield all input: inputs | this.label > |input.label|
* @author Emina Torlak
*/
public final class ITEGate extends BooleanFormula {
private final BooleanFormula[] inputs;
private final int label, hashcode, labelhash;
/**
* Constructs a new ITEGate from the given formulas and label.
* @requires label >= 0 && null !in ifFormula + thenFormula + elseFormula
* @requires hashcode = ITE.hash(ifFormula, thenFormula, elseFormula)
* @ensures this.label' = label && this.ifFormula' = ifFormula &&
* this.thenFormula' = thenFormula && this.elseFormula' = elseFormula
* @throws NullPointerException owner = null
*/
ITEGate(int label, int hashcode, BooleanFormula ifFormula, BooleanFormula thenFormula, BooleanFormula elseFormula) {
super(null);
assert label >= 0;
this.label = label;
this.labelhash = Ints.superFastHash(label);
this.hashcode = hashcode;
this.inputs = new BooleanFormula[3];
inputs[0] = ifFormula;
inputs[1] = thenFormula;
inputs[2] = elseFormula;
}
/**
* Returns a hash of this.label
* @return a hash of this.label
*/
@Override
int hash(Operator op) {
return labelhash;
}
/**
* Returns an iterator over this.inputs
* @return returns an iterator over this.inputs
* @see kodkod.engine.bool.BooleanFormula#iterator()
*/
@Override
public Iterator<BooleanFormula> iterator() {
return Containers.iterate(inputs);
}
/**
* Returns 3.
* @return 2
* @see kodkod.engine.bool.BooleanFormula#size()
*/
@Override
public int size() {
return 3;
}
/**
* Returns this.label
* @return this.label
* @see kodkod.engine.bool.BooleanValue#label()
*/
@Override
public int label() {
return label;
}
/**
* Passes this value and the given
* argument value to the visitor, and returns the resulting value.
* @return the value produced by the visitor when visiting this node
* with the given argument.
* @see kodkod.engine.bool.BooleanFormula#accept(kodkod.engine.bool.BooleanVisitor, Object)
*/
@Override
public <T, A> T accept(BooleanVisitor<T, A> visitor, A arg) {
return visitor.visit(this, arg);
}
/**
* Returns a string representation of this ITE gate.
* @return a string representation of this ITE gate.
*/
public String toString() {
return "(" + inputs[0] + "?" + inputs[1] + ":" + inputs[2] + ")";
}
/**
* Returns the hashcode for this if-then-else gate.
* @return the hashcode for this gate.
*/
public int hashCode() {
return hashcode;
}
/**
* Returns Operator.ITE.
* @return Operator.ITE
*/
@Override
public kodkod.engine.bool.Operator op() {
return kodkod.engine.bool.Operator.ITE;
}
/**
* Returns this.inputs[i].
* @return this.inputs[i]
* @throws IndexOutOfBoundsException 0 < i || i > 2
*/
@Override
public BooleanFormula input(int i) {
if (i < 0 || i > 2)
throw new IndexOutOfBoundsException();
return inputs[i];
}
/**
* Returns an integer k' such that 0 < |k'| < k and |k'| is the number of flattening
* steps that need to be taken to determine that this circuit has (or does not have)
* an input with the given label.
* A positive k' indicates that f is found to be an input to this circuit in k' steps.
* A negative k' indicates that f is not an input to this circuit, when it is flattened
* using at most k steps.
* @requires k > 0
* @return this=f => 1 else op=ITE && k>2 && f in this.inputs[int].label => 3 else -3
*/
@Override
int contains(Operator op, int f, int k) {
assert k > 0;
if (f==label) return 1;
else if (op != Operator.ITE || k < 3 || f>label || -f>label) return -1;
else return (inputs[0].label()==f || inputs[1].label()==f || inputs[2].label()==f) ? 3 : -3;
}
/**
* Flattens this circuit with respect to the given operator into
* the provided set.
* @requires k > 0
* @ensures op = Operator.ITE && k> 2 => flat.elts' = flat.elts + this.inputs[ints],
* flat.elts' = flat.elts + this
*/
@Override
void flatten(Operator op, Set<BooleanFormula> flat, int k) {
assert k > 0;
if (op==Operator.ITE && k > 2) {
flat.add(inputs[0]);
flat.add(inputs[1]);
flat.add(inputs[2]);
} else {
flat.add(this);
}
}
}