/*
* 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 static kodkod.engine.bool.BooleanConstant.FALSE;
import static kodkod.engine.bool.BooleanConstant.TRUE;
import static kodkod.engine.bool.Operator.AND;
import static kodkod.engine.bool.Operator.OR;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.List;
import kodkod.util.collections.Containers;
/**
* Two's complement integer representation. Supports comparisons, addition and subtraction.
* Integers are represented in little-endian (least significant bit first) order.
* @author Emina Torlak
*/
final class TwosComplementInt extends Int {
private final BooleanValue[] bits;
/**
* Constructs a TwosComplementInt out of the given factory and bits.
* @requires bits is well formed
* @ensures this.factory' = factory && this.bits' = bits
*/
private TwosComplementInt(BooleanFactory factory, BooleanValue[] bits) {
super(factory);
this.bits = bits;
}
/**
* Constructs a TwosComplementInt that represents either 0 or the given number, depending on
* the value of the given bit.
* @requires factory.encoding = TWOSCOMPLEMENT && bit in factory.components
* @ensures this.factory' = factory
* @ensures bits is a two's-complement representation of the given number
* that uses the provided bit in place of 1's
*/
TwosComplementInt(BooleanFactory factory, int number, BooleanValue bit) {
super(factory);
final int width = bitwidth(number);
this.bits = new BooleanValue[width];
for(int i = 0; i < width; i++) {
bits[i] = (number & (1<<i)) == 0 ? FALSE : bit;
}
}
/**
* Returns the number of bits needed/allowed to represent the given number.
* @return the number of bits needed/allowed to represent the given number.
*/
private int bitwidth(int number) {
if (number > 0)
return StrictMath.min(33 - Integer.numberOfLeadingZeros(number), factory.bitwidth);
else if (number < 0)
return StrictMath.min(33 - Integer.numberOfLeadingZeros(~number), factory.bitwidth);
else // number = 0
return 1;
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#isConstant()
*/
public final boolean isConstant() {
for(int i = width()-1; i >= 0; i--) {
BooleanValue b = bit(i);
if (b!=TRUE && b!=FALSE)
return false;
}
return true;
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#twosComplementBits()
*/
@Override
public final List<BooleanValue> twosComplementBits() {
return new AbstractList<BooleanValue>() {
@Override
public BooleanValue get(int i) {
if (i < 0 || i >= factory.bitwidth)
throw new IndexOutOfBoundsException();
return bit(i);
}
@Override
public int size() { return factory.bitwidth; }
};
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#width()
*/
@Override
public int width() {
return bits.length;
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#value()
*/
public final int value() {
int ret = 0;
final int max = bits.length-1;
for(int i = 0; i < max; i++) {
if (bits[i]==TRUE) ret += 1<<i;
else if (bits[i]!=FALSE)
throw new IllegalStateException(this + " is not constant.");
}
if (bits[max]==TRUE) ret -= 1<<max;
else if (bits[max]!=FALSE)
throw new IllegalStateException(this + " is not constant.");
return ret;
}
/**
* Returns the BooleanValue at the specified index.
* @requires 0 <= i < this.factory.bitwidth
* @return this.bits[i]
*/
public final BooleanValue bit(long i) {
return bits[(int)StrictMath.min(i, bits.length-1)];
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#eq(kodkod.engine.bool.Int)
*/
public final BooleanValue eq(Int other) {
validate(other);
final BooleanAccumulator cmp = BooleanAccumulator.treeGate(AND);
for(int i = 0, width = StrictMath.max(width(), other.width()); i < width; i++) {
if (cmp.add(factory.iff(bit(i), other.bit(i)))==FALSE)
return FALSE;
}
return factory.accumulate(cmp);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#lt(kodkod.engine.bool.Int)
*/
public final BooleanValue lt(Int other) {
final BooleanValue leq = lte(other);
final BooleanAccumulator acc = BooleanAccumulator.treeGate(OR);
for(int i = 0, width = StrictMath.max(width(), other.width()); i < width; i++) {
acc.add(factory.xor(bit(i), other.bit(i)));
}
return factory.and(leq, factory.accumulate(acc));
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#lte(kodkod.engine.bool.Int)
*/
@Override
public BooleanValue lte(Int other) {
validate(other);
final BooleanAccumulator cmp = BooleanAccumulator.treeGate(Operator.AND);
final int last = StrictMath.max(width(), other.width())-1;
cmp.add(factory.implies(other.bit(last), bit(last)));
BooleanValue prevEquals = factory.iff(bit(last), other.bit(last));
for(int i = last-1; i >= 0; i--) {
BooleanValue v0 = bit(i), v1 = other.bit(i);
cmp.add(factory.implies(prevEquals, factory.implies(v0, v1)));
prevEquals = factory.and(prevEquals, factory.iff(v0, v1));
}
return factory.accumulate(cmp);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#plus(kodkod.engine.bool.Int)
*/
@Override
public Int plus(Int other) {
validate(other);
final int width = StrictMath.min(StrictMath.max(width(), other.width()) + 1, factory.bitwidth);
final BooleanValue[] plus = new BooleanValue[width];
BooleanValue carry = FALSE;
for(int i = 0; i < width; i++) {
BooleanValue v0 = bit(i), v1 = other.bit(i);
plus[i] = factory.sum(v0, v1, carry);
carry = factory.carry(v0, v1, carry);
}
return new TwosComplementInt(factory, plus);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#minus(kodkod.engine.bool.Int)
*/
@Override
public Int minus(Int other) {
validate(other);
final int width = StrictMath.min(StrictMath.max(width(), other.width()) + 1, factory.bitwidth);
final BooleanValue[] minus = new BooleanValue[width];
BooleanValue carry = TRUE;
for(int i = 0; i < width; i++) {
BooleanValue v0 = bit(i), v1 = other.bit(i).negation();
minus[i] = factory.sum(v0, v1, carry);
carry = factory.carry(v0, v1, carry);
}
return new TwosComplementInt(factory, minus);
}
/**
* Adds the newBit and the given carry to this.bits[index] and returns the new carry.
* @requires 0 <= index < this.width
* @ensures this.bits'[index] = this.factory.sum(this.bits[index], newBit, cin)
* @return this.factory.carry(this.bits[index], newBit, cin)
*/
private BooleanValue addAndCarry(int index, BooleanValue newBit, BooleanValue cin) {
BooleanValue oldBit = bits[index];
bits[index] = factory.sum(oldBit, newBit, cin);
return factory.carry(oldBit, newBit, cin);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#multiply(kodkod.engine.bool.Int)
*/
@Override
public Int multiply(Int other) {
validate(other);
final int width = StrictMath.min(width()+other.width(), factory.bitwidth);
final BooleanValue[] mult = new BooleanValue[width];
final TwosComplementInt ret = new TwosComplementInt(factory, mult);
/* first partial sum */
BooleanValue iBit = bit(0), carry;
for(int j = 0; j < width; j++) {
mult[j] = factory.and(iBit, other.bit(j));
}
final int last = width-1;
/* intermediate partial sums */
for(int i = 1; i < last; i++) {
carry = FALSE;
iBit = bit(i);
for(int j = 0, jmax = width-i; j < jmax; j++) {
carry = ret.addAndCarry(j+i, factory.and(iBit, other.bit(j)), carry);
}
}
/* last partial sum is subtracted (see http://en.wikipedia.org/wiki/Multiplication_ALU) */
ret.addAndCarry(last, factory.and(this.bit(last), other.bit(0)).negation(), TRUE);
// System.out.println("this.width="+width() + ", other.width=" + other.width() + ", ret.width=" + width);
//System.out.println(ret);
return ret;
}
/**
* Returns an array of BooleanValues that represents the same
* integer as this, but using extwidth bits.
* @requires extwidth >= this.width()
* @return an array of BooleanValues that represents the same
* integer as this, but using extwidth bits.
*/
private BooleanValue[] extend(int extwidth) {
final BooleanValue[] ext = new BooleanValue[extwidth];
final int width = width();
for(int i = 0; i < width; i++) {
ext[i] = bits[i];
}
final BooleanValue sign = bits[width-1];
for(int i = width; i < extwidth; i++) {
ext[i] = sign;
}
return ext;
}
/**
* Performs non-restoring signed division of this and the given integer. Returns
* the this.factory.bitwidth low-order bits of the quotient if the quotient flag
* is true; otherwise returns the this.factory.bitwidth low-order bits of the remainder.
* Both the quotionent and the remainder are given in little endian format.
* @see Behrooz Parhami, Computer Arithmetic: Algorithms and Hardware Designs,
* Oxford University Press, 2000, pp. 218-221.
* @requires this.factory = d.factory && d instanceof BinaryInt
* @return an array of boolean values, as described above
*/
private BooleanValue[] nonRestoringDivision(Int d, boolean quotient) {
final int width = factory.bitwidth, extended = width*2 + 1;
// extend the dividend to bitwidth*2 + 1 and store it in s; the quotient will have width digits
final BooleanValue[] s = this.extend(extended), q = new BooleanValue[width];
// detects if one of the intermediate remainders is zero
final BooleanValue[] svalues = new BooleanValue[width];
BooleanValue carry, sbit, qbit, dbit;
// the sign bit of the divisor
final BooleanValue dMSB = d.bit(width);
int sleft = 0; // the index which contains the LSB of s
for(int i = 0; i < width; i++) {
svalues[i] = factory.accumulate(BooleanAccumulator.treeGate(Operator.OR, s));
int sright = (sleft + extended - 1) % extended; // the index which contains the MSB of s
// q[width-i-1] is 1 if sign(s_(i)) = sign(d), otherwise it is 0
qbit = factory.iff(s[sright], dMSB);
q[width-i-1] = qbit;
// shift s to the left by 1 -- simulated by setting sright to FALSE and sleft to sright
s[sright] = FALSE;
sleft = sright;
// if sign(s_(i)) = sign(d), form s_(i+1) by subtracting (2^width)d from s_(i);
// otherwise, form s_(i+1) by adding (2^width)d to s_(i).
carry = qbit;
for(int di = 0, si = (sleft+width) % extended; di <= width; di++, si = (si+1) % extended) {
dbit = factory.xor(qbit, d.bit(di));
sbit = s[si];
s[si] = factory.sum(sbit, dbit, carry);
carry = factory.carry(sbit, dbit, carry);
}
}
// s[0..width] holds the width+1 high order bits of s
assert (sleft+width) % extended == 0 ;
// correction needed if one of the intermediate remainders is zero
// or s is non-zero and its sign differs from the sign of the dividend
final BooleanValue incorrect = factory.or(
factory.not(factory.accumulate(BooleanAccumulator.treeGate(Operator.AND, svalues))),
factory.and(factory.xor(s[width], this.bit(width)),
factory.accumulate(BooleanAccumulator.treeGate(Operator.OR, s))));
final BooleanValue corrector = factory.iff(s[width], d.bit(width));
if (quotient) { // convert q to 2's complement, correct it if s is nonzero, and return
// convert q to 2's complement: shift to the left by 1 and set LSB to TRUE
System.arraycopy(q, 0, q, 1, width-1);
q[0] = TRUE;
// correct if incorrect evaluates to true as follows: if corrector evaluates to true,
// increment q; otherwise decrement q.
final BooleanValue sign = factory.and(incorrect, factory.not(corrector));
carry = factory.and(incorrect, corrector);
for(int i = 0; i < width; i++) {
qbit = q[i];
q[i] = factory.sum(qbit, sign, carry);
carry = factory.carry(qbit, sign, carry);
}
return q;
} else { // correct s if non-zero and return
// correct if incorrect evaluates to true as follows: if corrector evaluates to true,
// subtract (2^width)d from s; otherwise add (2^width)d to s
carry = factory.and(incorrect, corrector);
for(int i = 0; i <= width; i++) {
dbit = factory.and(incorrect, factory.xor(corrector, d.bit(i)));
sbit = s[i];
s[i] = factory.sum(sbit, dbit, carry);
carry = factory.carry(sbit, dbit, carry);
}
final BooleanValue[] r = new BooleanValue[width];
System.arraycopy(s, 0, r, 0, width);
return r;
}
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#divide(kodkod.engine.bool.Int)
*/
@Override
public Int divide(Int other) {
validate(other);
return new TwosComplementInt(factory, nonRestoringDivision(other, true));
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#modulo(kodkod.engine.bool.Int)
*/
@Override
public Int modulo(Int other) {
validate(other);
return new TwosComplementInt(factory, nonRestoringDivision(other, false));
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#choice(kodkod.engine.bool.BooleanValue, kodkod.engine.bool.Int)
*/
@Override
public Int choice(BooleanValue condition, Int other) {
validate(other);
final int width = StrictMath.max(width(), other.width());
final BooleanValue[] choice = new BooleanValue[width];
for(int i = 0; i < width; i++) {
choice[i] = factory.ite(condition, bit(i), other.bit(i));
}
return new TwosComplementInt(factory, choice);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#and(kodkod.engine.bool.Int)
*/
@Override
public Int and(Int other) {
validate(other);
final int width = StrictMath.max(width(), other.width());
final BooleanValue[] and = new BooleanValue[width];
for(int i = 0; i < width; i++) {
and[i] = factory.and(bit(i), other.bit(i));
}
return new TwosComplementInt(factory, and);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#or(kodkod.engine.bool.Int)
*/
@Override
public Int or(Int other) {
validate(other);
final int width = StrictMath.max(width(), other.width());
final BooleanValue[] or = new BooleanValue[width];
for(int i = 0; i < width; i++) {
or[i] = factory.or(bit(i), other.bit(i));
}
return new TwosComplementInt(factory, or);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#xor(kodkod.engine.bool.Int)
*/
@Override
public Int xor(Int other) {
validate(other);
final int width = StrictMath.max(width(), other.width());
final BooleanValue[] xor = new BooleanValue[width];
for(int i = 0; i < width; i++) {
xor[i] = factory.xor(bit(i), other.bit(i));
}
return new TwosComplementInt(factory,xor);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#shl(kodkod.engine.bool.Int)
*/
@Override
public Int shl(Int other) {
validate(other);
final int width = factory.bitwidth;
final TwosComplementInt shifted = new TwosComplementInt(factory, extend(width));
for(int i = 0; i < width; i++) {
final long shift = 1L << i;
final BooleanValue bit = other.bit(i);
for(int j = width-1; j >= 0; j--) {
shifted.bits[j] = factory.ite(bit, j < shift ? FALSE : shifted.bit(j-shift), shifted.bits[j]);
}
}
return shifted;
}
/**
* Performs a right shift with the given extension.
*/
private Int shr(Int other, BooleanValue sign) {
validate(other);
final int width = factory.bitwidth;
final TwosComplementInt shifted = new TwosComplementInt(factory, extend(width));
for(int i = 0; i < width; i++) {
final long shift = 1L << i;
final long fill = width - shift;
BooleanValue bit = other.bit(i);
for(int j = 0; j < width; j++) {
shifted.bits[j] = factory.ite(bit, j < fill ? shifted.bit(j+shift) : sign, shifted.bits[j]);
}
}
return shifted;
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#shr(kodkod.engine.bool.Int)
*/
@Override
public Int shr(Int other) {
return shr(other, FALSE);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#sha(kodkod.engine.bool.Int)
*/
@Override
public Int sha(Int other) {
return shr(other, bits[bits.length-1]);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#negate()
*/
@Override
public Int negate() {
return (new TwosComplementInt(factory, new BooleanValue[]{FALSE})).minus(this);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#not()
*/
@Override
public Int not() {
final int width = width();
final BooleanValue[] inverse = new BooleanValue[width];
for(int i = 0 ; i < width; i++) {
inverse[i] = factory.not(bits[i]);
}
return new TwosComplementInt(factory, inverse);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#abs()
*/
@Override
public Int abs() {
return choice(factory.not(bits[bits.length-1]), negate());
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#sgn()
*/
@Override
public Int sgn() {
final BooleanValue[] sgn = new BooleanValue[2];
sgn[0] = factory.accumulate(BooleanAccumulator.treeGate(Operator.OR, bits));
sgn[1] = bits[bits.length-1];
return new TwosComplementInt(factory, sgn);
}
/**
* {@inheritDoc}
* @see java.lang.Object#toString()
*/
public String toString() {
return "b" + Arrays.toString(bits);
}
/**
* If the plus flag is true, returns a sum of this and other ints,
* with a cascade of adders or logarithmic depth. If the plus flag
* is false, returns a product of this and other ints, with a cascade
* of multipliers of logarithmic depth.
* @return plus => PLUS(this, others) else MULTIPLY(this, others)
*/
private Int apply(boolean plus, Int...others) {
final Int[] ints = Containers.copy(others, 0, new Int[others.length+1], 1, others.length);
ints[0] = this;
for(int part = ints.length; part > 1; part -= part/2) {
final int max = part-1;
for(int i = 0; i < max; i += 2) {
ints[i/2] = plus ? ints[i].plus(ints[i+1]) : ints[i].multiply(ints[i+1]);
}
if (max%2==0) { // even max => odd number of entries
ints[max/2] = ints[max];
}
}
return ints[0];
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#plus(kodkod.engine.bool.Int[])
*/
@Override
public Int plus(Int... others) { return apply(true, others); }
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#multiply(kodkod.engine.bool.Int[])
*/
@Override
public Int multiply(Int... others) { return apply(false, others); }
/**
* Applies the given nary operator to this and the given ints.
* @return op(this, others)
*/
private Int apply(Operator.Nary op, Int...others) {
int width = width();
for(Int other : others) {
validate(other);
width = Math.max(width, other.width());
}
final BooleanValue[] bits = new BooleanValue[width];
final BooleanValue shortCircuit = op.shortCircuit();
for(int i = 0; i < width; i++) {
final BooleanAccumulator acc = BooleanAccumulator.treeGate(op, bit(i));
for(Int other : others) {
if (acc.add(other.bit(i))==shortCircuit) break;
}
bits[i] = factory.accumulate(acc);
}
return new TwosComplementInt(factory, bits);
}
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#and(kodkod.engine.bool.Int[])
*/
@Override
public Int and(Int... others) { return apply(AND, others); }
/**
* {@inheritDoc}
* @see kodkod.engine.bool.Int#or(kodkod.engine.bool.Int[])
*/
@Override
public Int or(Int... others) { return apply(OR, others); }
}