/* * Kodkod -- Copyright (c) 2005-2011, 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.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import kodkod.ast.Variable; import kodkod.engine.bool.Operator.Nary; import kodkod.engine.fol2sat.Environment; 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 */ @SuppressWarnings("rawtypes") 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, BooleanValue overflow, BooleanValue accumOverflow) { this(factory, bits, Collections.<Variable>emptySet(), overflow, accumOverflow); } private TwosComplementInt(BooleanFactory factory, BooleanValue[] bits, Collection<Variable> vars, BooleanValue overflow, BooleanValue accumOverflow) { super(factory, vars); this.bits = bits; defCond().setOverflows(overflow, accumOverflow); } /** * 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, Collections.<Variable>emptySet()); 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; } if (factory.noOverflow && !checkBounds(number)) { defCond().setOverflows(TRUE, TRUE); } } /** * Checks whether a given integer literal is representable using * only <code>this.factory.bitwidth</code> bits. */ private boolean checkBounds(int num) { return num >= minInt() && num <= maxInt(); } /** * Returns the min int representable using only <code>this.factory.bitwidth</code> bits. */ private int minInt() { return -(1 << (factory.bitwidth - 1)); } /** * Returns the max int representable using only <code>this.factory.bitwidth</code> bits. */ private int maxInt() { return (1 << (factory.bitwidth - 1)) - 1; } /** * ORs overflow circuits of <code>this</code> object ( * <code>this.mergedOverflow</code>), a given <code>other</code> object ( * <code>other.mergedOverflow</code>), and a given overflow circuit ( * <code>of</code>) */ private BooleanValue mergeOverflows(Int other, BooleanValue of) { return DefCond.merge(factory, of, defCond(), other.defCond()); } /** * 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(int i) { return bits[StrictMath.min(i, bits.length-1)]; } /** * {@inheritDoc} * @see kodkod.engine.bool.Int#msb(kodkod.engine.bool.Int) */ public final BooleanValue msb() { return bits[bits.length-1]; } /** * If overflow checking is disabled returns <code>value</code>. Otherwise, * returns a conjunction of <code>value</code>, <code>lhs.accumOverflow</code>, * and <code>rhs.accumOverflow</code>. * * ~~~ NOTE ~~~: Every time a BooleanValue is returned as a result of an operation * over Ints, one of the <code>ensureNoOverflow</code> methods * should be called. */ private BooleanValue ensureNoOverflow(Environment env, BooleanValue value, Int... ints) { DefCond[] dcs = new DefCond[ints.length]; for (int i = 0; i < ints.length; i++) dcs[i] = ints[i].defCond(); return DefCond.ensureDef(factory, env, value, dcs); } /** * {@inheritDoc} * @see kodkod.engine.bool.Int#eq(kodkod.engine.bool.Int) */ public final BooleanValue eq(Int other, Environment env) { BooleanValue ret = eqWithoutOverflow(other); return ensureNoOverflow(env, ret, this, other); } public final BooleanValue neq(Int other, Environment env) { BooleanValue ret = factory.not(eqWithoutOverflow(other)); return ensureNoOverflow(env, ret, this, other); } private BooleanValue eqWithoutOverflow(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; } BooleanValue ret = factory.accumulate(cmp); return ret; } /** * {@inheritDoc} * @see kodkod.engine.bool.Int#lt(kodkod.engine.bool.Int) */ public final BooleanValue lt(Int other, Environment env) { 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))); } BooleanValue ret = factory.and(leq, factory.accumulate(acc)); return ensureNoOverflow(env, ret, this, other); } /** * {@inheritDoc} * @see kodkod.engine.bool.Int#lte(kodkod.engine.bool.Int) */ @Override public BooleanValue lte(Int other, Environment env) { 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)); } BooleanValue ret = factory.accumulate(cmp); return ensureNoOverflow(env, ret, this, other); } /** * {@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; BooleanValue c1 = FALSE; BooleanValue c2 = 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); if (i == width-2) c2 = carry; else if (i == width-1) c1 = carry; } BooleanValue overflow = FALSE; if (width == factory.bitwidth) { overflow = factory.xor(c1, c2); } BooleanValue accumOF = mergeOverflows(other, overflow); return new TwosComplementInt(factory, plus, unionVars(this, other), overflow, accumOF); } /** * {@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; BooleanValue c1 = FALSE; BooleanValue c2 = FALSE; 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); if (i == width-2) c2 = carry; else if (i == width-1) c1 = carry; } BooleanValue overflow = FALSE; if (width == factory.bitwidth) { overflow = factory.xor(c1, c2); } BooleanValue accumOF = mergeOverflows(other, overflow); return new TwosComplementInt(factory, minus, unionVars(this, other), overflow, accumOF); } /** * 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) */ //[AM] TODO: not optimal, uses double precision (too many bits)! @Override public Int multiply(Int other) { validate(other); final int retWidth = width() + other.width(); final BooleanValue[] mult = new BooleanValue[retWidth]; final Set<Variable> unionVars = unionVars(this, other); final TwosComplementInt ret = new TwosComplementInt(factory, mult, unionVars, FALSE, FALSE); /* first partial sum */ BooleanValue iBit = bit(0); for(int j = 0; j < retWidth; j++) { mult[j] = factory.and(iBit, other.bit(j)); } /* intermediate partial sums */ int last = retWidth - 1; for(int i = 1; i < last; i++) { iBit = this.bit(i); BooleanValue carry = FALSE; for (int j = 0; j < retWidth - i; j++) { BooleanValue bit = factory.and(iBit, other.bit(j)); carry = ret.addAndCarry(i + j, bit, carry); } } /* last partial sum is subtracted (see http://en.wikipedia.org/wiki/Multiplication_ALU) */ iBit = this.bit(last); BooleanValue carry = TRUE; for (int j = 0; j < retWidth - last; j++) { BooleanValue bit = factory.and(iBit, other.bit(j)).negation(); carry = ret.addAndCarry(last + j, bit, carry); } final int width = StrictMath.min(mult.length, factory.bitwidth); final BooleanValue[] multTrunc = new BooleanValue[width]; for (int i = 0; i < multTrunc.length; i++) multTrunc[i] = mult[i]; BooleanAccumulator acc = BooleanAccumulator.treeGate(Nary.OR); for (int i = multTrunc.length; i < mult.length; i++) { acc.add(factory.xor(mult[i - 1], mult[i])); } BooleanValue overflow = factory.accumulate(acc); BooleanValue accumOF = mergeOverflows(other, overflow); return new TwosComplementInt(factory, multTrunc, unionVars, overflow, accumOF); } //@Override public Int multiply_no_overflow_detection(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, unionVars(this, other), FALSE, FALSE); /* 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); 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); TwosComplementInt ret = new TwosComplementInt(factory, nonRestoringDivision(other, true), unionVars(this, other), FALSE, FALSE); BooleanValue divByZero = other.eq(factory.integer(0)); BooleanValue singleOverflowCase = factory.and(this.eq(factory.integer(-(1 << (factory.bitwidth-1)))), other.eq(factory.integer(-1))); BooleanValue overflow = factory.or(divByZero, singleOverflowCase); BooleanValue accumOF = mergeOverflows(other, overflow); ret.defCond().setOverflows(overflow, accumOF); return ret; } /** * {@inheritDoc} * @see kodkod.engine.bool.Int#modulo(kodkod.engine.bool.Int) */ @Override public Int modulo(Int other) { validate(other); TwosComplementInt ret = new TwosComplementInt(factory, nonRestoringDivision(other, false), unionVars(this, other), FALSE, FALSE); BooleanValue divByZero = other.eq(factory.integer(0)); BooleanValue accumOF = mergeOverflows(other, divByZero); ret.defCond().setOverflows(FALSE, accumOF); return ret; } /** * {@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)); } BooleanValue of = factory.ite(condition, defCond().getOverflow(), other.defCond().getOverflow()); BooleanValue accumOF = factory.ite(condition, defCond().getAccumOverflow(), other.defCond().getAccumOverflow()); return new TwosComplementInt(factory, choice, unionVars(this, other), of, accumOF); } /** * {@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)); } Set<Variable> unionVars = unionVars(this, other); return new TwosComplementInt(factory, and, unionVars, FALSE, mergeOverflows(other, FALSE)); } /** * {@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, unionVars(this, other), FALSE, mergeOverflows(other, FALSE)); } /** * {@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, unionVars(this, other), FALSE, mergeOverflows(other, FALSE)); } /** * {@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), unionVars(this, other), FALSE, FALSE); final int max = 32 - Integer.numberOfLeadingZeros(width - 1); BooleanAccumulator acc = BooleanAccumulator.treeGate(Nary.OR); for(int i = 0; i < width; i++) { int shift = 1 << i; BooleanValue bit = other.bit(i); // overflow: check if the bits being pushed out is different from the one immediately to the right of it for(int x = 0; x < shift; x++) { BooleanValue b1 = width-x-1 < 0 ? FALSE : shifted.bit(width-x-1); BooleanValue b2 = width-x-2 < 0 ? FALSE : shifted.bit(width-x-2); acc.add(factory.ite(bit, factory.xor(b1, b2), FALSE)); } if (i < max) { for(int j = width-1; j >= 0; j--) { shifted.bits[j] = factory.ite(bit, j < shift ? FALSE : shifted.bit(j-shift), shifted.bits[j]); } } } BooleanValue overflow = factory.accumulate(acc); BooleanValue accumOF = mergeOverflows(other, overflow); shifted.defCond().setOverflows(overflow, accumOF); 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), unionVars(this, other), FALSE, FALSE); final int max = 32 - Integer.numberOfLeadingZeros(width - 1); for(int i = 0; i < max; i++) { int shift = 1 << i; int 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]); } } shifted.defCond().setOverflows(FALSE, mergeOverflows(other, FALSE)); 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}, FALSE, 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, defCond().vars(), FALSE, defCond().getAccumOverflow()); } /** * {@inheritDoc} * @see kodkod.engine.bool.Int#abs() */ @Override public Int abs() { Int negated = negate(); return choice(factory.not(bits[bits.length-1]), negated); } /** * {@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, defCond().vars(), FALSE, defCond().getAccumOverflow()); } /** * {@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); } final BooleanValue[] allOverflows = new BooleanValue[others.length + 1]; final Set<Variable> allVars = new HashSet<Variable>(); allOverflows[0] = defCond().getAccumOverflow(); allVars.addAll(defCond().vars()); for (int i = 1; i < allOverflows.length; i++) { allOverflows[i] = others[i-1].defCond().getAccumOverflow(); allVars.addAll(others[i-1].defCond().vars()); } BooleanAccumulator overflowAcc = BooleanAccumulator.treeGate(op, allOverflows); return new TwosComplementInt(factory, bits, allVars, FALSE, factory.accumulate(overflowAcc)); } /** * {@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); } private static Set<Variable> unionVars(Int int1, Int int2) { Set<Variable> union = new HashSet<Variable>(); union.addAll(int1.defCond().vars()); union.addAll(int2.defCond().vars()); return union; } }