/// <summary> /// Reduction rules for a BDD. /// </summary> /// <param name="node">The node to reduce.</param> /// <param name="result">The modified node.</param> /// <returns>If there was a reduction.</returns> public virtual bool Reduce(CBDDNode node, out DDIndex result) { result = DDIndex.False; if (node.Low.Equals(node.High)) { result = node.Low; return(true); } if (node.Low.IsConstant()) { return(false); } var lo = this.Manager.LookupNodeByIndex(node.Low); if (lo.Variable == node.NextVariable && lo.High.Equals(node.High)) { var reduced = new CBDDNode(node.Variable, lo.NextVariable, lo.Low, node.High); result = this.Manager.Allocate(reduced); return(true); } return(false); }
/// <summary> /// Remove all elements matching a predicate. /// </summary> /// <param name="forwardingAddresses">The forwarding addresses.</param> /// <returns>A new handle table after garbage collection.</returns> public HandleTable <T> Rebuild(int[] forwardingAddresses) { var table = new HandleTable <T>(this.manager, this.Count); for (int bucket = 0; bucket < this.buckets.Length; bucket++) { int i = this.buckets[bucket]; while (i >= 0) { var entry = this.entries[i]; var index = entry.Key; var wref = entry.Value; var position = index.GetPosition(); var newPosition = forwardingAddresses[position]; if (newPosition != 0 || index.IsConstant()) { var newIndex = new DDIndex(newPosition, index.IsComplemented()); if (wref.TryGetTarget(out DD target)) { target.Index = newIndex; } table.AddUnique(newIndex, wref); } i = entry.Next; } } return(table); }
/// <summary> /// Rebuild the unique table. /// </summary> /// <param name="newSize">The new number of nodes in use after a GC.</param> /// <param name="forwardingAddresses">The index forwarding addresses.</param> /// <returns>A new table with valid indicies.</returns> public UniqueTable <T> Rebuild(int newSize, int[] forwardingAddresses) { var values = new DDIndex[newSize]; var table = new UniqueTable <T>(this.manager, this.Count); for (int bucket = 0; bucket < this.buckets.Length; bucket++) { int i = this.buckets[bucket]; while (i >= 0) { var entry = this.entries[i]; var ddindex = entry.Value; var newPosition = forwardingAddresses[ddindex.GetPosition()]; if (newPosition != 0 || ddindex.IsConstant()) { values[newPosition] = new DDIndex(newPosition, ddindex.IsComplemented()); } i = entry.Next; } } for (int i = 0; i < values.Length; i++) { table.AddUnchecked(this.manager.MemoryPool[i], values[i]); } return(table); }
/// <summary> /// Returns a new formula that repairs the order after a substitution. /// </summary> /// <param name="level">Variable level of the new node.</param> /// <param name="lo">The node's lo branch.</param> /// <param name="hi">The node's hi branch.</param> /// <returns></returns> private DDIndex RepairOrder(int level, DDIndex lo, DDIndex hi) { var loNode = this.Manager.MemoryPool[lo.GetPosition()]; var hiNode = this.Manager.MemoryPool[hi.GetPosition()]; loNode = lo.IsComplemented() ? Flip(loNode) : loNode; hiNode = hi.IsComplemented() ? Flip(hiNode) : hiNode; var loLevel = Level(lo, loNode); var hiLevel = Level(hi, hiNode); if (level < loLevel && level < hiLevel) { return(this.Manager.Allocate(new BDDNode(level, lo, hi))); } else if (loLevel < hiLevel) { var l = RepairOrder(level, loNode.Low, hi); var h = RepairOrder(level, loNode.High, hi); return(this.Manager.Allocate(new BDDNode(loNode.Variable, l, h))); } else if (loLevel > hiLevel) { var l = RepairOrder(level, lo, hiNode.Low); var h = RepairOrder(level, lo, hiNode.High); return(this.Manager.Allocate(new BDDNode(hiNode.Variable, l, h))); } else { var l = RepairOrder(level, loNode.Low, hiNode.Low); var h = RepairOrder(level, loNode.High, hiNode.High); return(this.Manager.Allocate(new BDDNode(loNode.Variable, l, h))); } }
/// <summary> /// The logical conjunction of two BDDs as the /// standard BDD "apply" operation. /// </summary> /// <param name="xid">The left operand index.</param> /// <param name="x">The left operand node.</param> /// <param name="yid">The right operand index.</param> /// <param name="y">The right operand node.</param> /// <returns>A new node representing the "And".</returns> public DDIndex And(DDIndex xid, CBDDNode x, DDIndex yid, CBDDNode y) { if (x.Variable < y.Variable) { if (x.NextVariable <= y.Variable) { var xlow = this.Manager.And(x.Low, yid); var xhigh = this.Manager.And(x.High, yid); return(this.Manager.Allocate(new CBDDNode(x.Variable, x.NextVariable, xlow, xhigh))); } else { var child = this.Manager.Allocate(new CBDDNode(y.Variable, x.NextVariable, x.Low, x.High)); var xlow = this.Manager.And(child, yid); var xhigh = this.Manager.And(x.High, yid); return(this.Manager.Allocate(new CBDDNode(x.Variable, y.Variable, xlow, xhigh))); } } else if (y.Variable < x.Variable) { if (y.NextVariable <= x.Variable) { var ylow = this.Manager.And(y.Low, xid); var yhigh = this.Manager.And(y.High, xid); return(this.Manager.Allocate(new CBDDNode(y.Variable, y.NextVariable, ylow, yhigh))); } else { var child = this.Manager.Allocate(new CBDDNode(x.Variable, y.NextVariable, y.Low, y.High)); var ylow = this.Manager.And(child, xid); var yhigh = this.Manager.And(y.High, xid); return(this.Manager.Allocate(new CBDDNode(y.Variable, x.Variable, ylow, yhigh))); } } else { if (x.NextVariable == y.NextVariable) { var lo = this.Manager.And(x.Low, y.Low); var hi = this.Manager.And(x.High, y.High); return(this.Manager.Allocate(new CBDDNode(x.Variable, x.NextVariable, lo, hi))); } else if (x.NextVariable < y.NextVariable) { var ychild = this.Manager.Allocate(new CBDDNode(x.NextVariable, y.NextVariable, y.Low, y.High)); var lo = this.Manager.And(x.Low, ychild); var hi = this.Manager.And(x.High, y.High); return(this.Manager.Allocate(new CBDDNode(x.Variable, x.NextVariable, lo, hi))); } else { var xchild = this.Manager.Allocate(new CBDDNode(y.NextVariable, x.NextVariable, x.Low, x.High)); var lo = this.Manager.And(y.Low, xchild); var hi = this.Manager.And(y.High, x.High); return(this.Manager.Allocate(new CBDDNode(y.Variable, y.NextVariable, lo, hi))); } } }
/// <summary> /// Reduction rules for a BDD. /// </summary> /// <param name="node">The node to reduce.</param> /// <param name="result">The modified node.</param> /// <returns>If there was a reduction.</returns> public virtual bool Reduce(BDDNode node, out DDIndex result) { result = DDIndex.False; if (node.Low.Equals(node.High)) { result = node.Low; return(true); } return(false); }
/// <summary> /// Either get the existing value or create a /// new one in a single operation. /// </summary> /// <param name="key">The key.</param> /// <param name="value">The value.</param> private void AddUnique(DDIndex key, WeakReference <DD> value) { int hashCode = key.GetHashCode() & 0x7FFFFFFF; int targetBucket = hashCode & this.mask; int index = this.Count; this.Count++; this.entries[index] = new Entry { Next = this.buckets[targetBucket], Key = key, Value = value }; this.buckets[targetBucket] = index; }
/// <summary> /// Either get the existing value or create a /// new one in a single operation. /// </summary> /// <param name="key">The key.</param> /// <param name="value">The value.</param> public void AddUnchecked(T key, DDIndex value) { int hashCode = key.GetHashCode() & 0x7FFFFFFF; int targetBucket = hashCode & this.mask; int index = this.count; this.count++; this.entries[index] = new Entry { Next = this.buckets[targetBucket], Value = value }; this.buckets[targetBucket] = index; }
/// <summary> /// Implement the logical "exists" operation, /// recursively calling the manager if necessary. /// </summary> /// <param name="xid">The left index.</param> /// <param name="x">The left node.</param> /// <param name="variables">The variable set.</param> /// <returns>The resulting function.</returns> public DDIndex Exists(DDIndex xid, BDDNode x, VariableSet <BDDNode> variables) { var lo = this.Manager.Exists(x.Low, variables); var hi = this.Manager.Exists(x.High, variables); if (variables.Contains(x.Variable)) { return(this.Manager.Or(lo, hi)); } return(this.Manager.Allocate(new BDDNode(x.Variable, lo, hi))); }
/// <summary> /// Implement a replacement operation that substitutes /// variables for other variables. /// </summary> /// <param name="xid">The left index.</param> /// <param name="x">The left node.</param> /// <param name="variableMap">The variable set.</param> /// <returns>A new formula with the susbtitution.</returns> public DDIndex Replace(DDIndex xid, BDDNode x, VariableMap <BDDNode> variableMap) { if (x.Variable > variableMap.MaxIndex) { return(xid); } var lo = this.Manager.Replace(x.Low, variableMap); var hi = this.Manager.Replace(x.High, variableMap); var level = variableMap.Get(x.Variable); level = level < 0 ? x.Variable : level; return(RepairOrder(level, lo, hi)); }
/// <summary> /// The logical conjunction of two BDDs as the /// standard BDD "apply" operation. /// </summary> /// <param name="xid">The left operand index.</param> /// <param name="x">The left operand node.</param> /// <param name="yid">The right operand index.</param> /// <param name="y">The right operand node.</param> /// <returns>A new node representing the "And".</returns> public DDIndex And(DDIndex xid, BDDNode x, DDIndex yid, BDDNode y) { if (x.Variable < y.Variable) { var xlow = this.Manager.And(x.Low, yid); var xhigh = this.Manager.And(x.High, yid); return(this.Manager.Allocate(new BDDNode(x.Variable, xlow, xhigh))); } else if (y.Variable < x.Variable) { var ylow = this.Manager.And(y.Low, xid); var yhigh = this.Manager.And(y.High, xid); return(this.Manager.Allocate(new BDDNode(y.Variable, ylow, yhigh))); } else { var low = this.Manager.And(x.Low, y.Low); var high = this.Manager.And(x.High, y.High); return(this.Manager.Allocate(new BDDNode(x.Variable, low, high))); } }
/// <summary> /// Either get the existing value or create a /// new one in a single operation. /// </summary> /// <param name="key">The key.</param> /// <returns>The value, possibly freshly created.</returns> public DD GetOrAdd(DDIndex key) { int hashCode = key.GetHashCode() & 0x7FFFFFFF; int targetBucket = hashCode & this.mask; for (int i = this.buckets[targetBucket]; i >= 0; i = this.entries[i].Next) { if (this.entries[i].Key.Equals(key)) { var wref = this.entries[i].Value; if (!wref.TryGetTarget(out DD target)) { target = new DD(this.manager.Uid, key); wref.SetTarget(target); } return(target); } } int index; if (this.Count == this.entries.Length) { this.Resize(); targetBucket = hashCode & this.mask; } index = this.Count; this.Count++; var dd = new DD(this.manager.Uid, key); var value = new WeakReference <DD>(dd); this.entries[index] = new Entry { Next = this.buckets[targetBucket], Key = key, Value = value }; this.buckets[targetBucket] = index; return(dd); }
/// <summary> /// Return a function capturing a variable being greater /// than or equal to a particular value. The value is /// represented as a byte array and should be have MSBs first. /// For example, the 32-bit value 300 would be represented as /// the byte array [0, 0, 1, 44]. /// </summary> /// <param name="value">The value.</param> /// <returns>The function representing the inequality.</returns> public DD GreaterOrEqual(byte[] value) { var len = this.Indices.Length; var eq = new DDIndex[len]; var greater = new DDIndex[len]; for (int v = len - 1; v >= 0; v--) { var variable = this.Indices[v]; var i = this.GetBitPositionForVariableIndex(variable); var whichByte = i / 8; var whichIndex = i % 8; var set = GetBit(value[whichByte], whichIndex, 8); if (set) { var node = this.Manager.IdIdx(variable); eq[i] = node; greater[i] = DDIndex.False; } else { var node = this.Manager.IdIdx(variable); eq[i] = this.Manager.Not(node); greater[i] = node; } } var acc = DDIndex.True; for (int i = len - 1; i >= 0; i--) { acc = this.Manager.Or(greater[i], this.Manager.And(acc, eq[i])); } return(this.Manager.FromIndex(acc)); }
/// <summary> /// Initializes a new instance of the <see cref="DD"/> class. /// </summary> /// <param name="managerId">Id of the manager that created this node.</param> /// <param name="index">Index of the underlying IDDNode.</param> internal DD(ushort managerId, DDIndex index) { this.ManagerId = managerId; this.Index = index; }
/// <summary> /// Implement the logical "exists" operation, /// recursively calling the manager if necessary. /// </summary> /// <param name="xid">The left index.</param> /// <param name="x">The left node.</param> /// <param name="variables">The variable set.</param> /// <returns>The resulting function.</returns> public DDIndex Exists(DDIndex xid, CBDDNode x, VariableSet <CBDDNode> variables) { throw new System.NotImplementedException(); }
/// <summary> /// Initializes a new instance of the <see cref="CBDDNode"/> struct. /// </summary> /// <param name="variable">The variable index.</param> /// <param name="nextVariable">The next index.</param> /// <param name="lo">The low (false) child.</param> /// <param name="hi">The high (true) child.</param> public CBDDNode(int variable, int nextVariable, DDIndex lo, DDIndex hi) { this.data = new NodeData32Packed(variable, false, nextVariable); this.Low = lo; this.High = hi; }
public DDIndex Ite(DDIndex fid, CBDDNode f, DDIndex gid, CBDDNode g, DDIndex hid, CBDDNode h) { throw new System.NotSupportedException(); }
/// <summary> /// Gets the "level" for the node, where the maximum /// value is used for constants. /// </summary> /// <param name="idx">The node index.</param> /// <param name="node">The node.</param> /// <returns></returns> private int Level(DDIndex idx, BDDNode node) { return(idx.IsConstant() ? int.MaxValue : node.Variable); }
/// <summary> /// Initializes a new instance of the <see cref="BDDNode"/> struct. /// </summary> /// <param name="variable">The variable index.</param> /// <param name="lo">The low (false) child.</param> /// <param name="hi">The high (true) child.</param> public BDDNode(int variable, DDIndex lo, DDIndex hi) { this.data = new NodeData32(variable, false); this.Low = lo; this.High = hi; }
/// <summary> /// Implement the logical "ite" operation, /// recursively calling the manager if necessary. /// </summary> /// <param name="fid">The f index.</param> /// <param name="f">The f node.</param> /// <param name="gid">The g index.</param> /// <param name="g">The g node.</param> /// <param name="hid">The h index.</param> /// <param name="h">The h node.</param> /// <returns>The ite of the three nodes.</returns> public DDIndex Ite(DDIndex fid, BDDNode f, DDIndex gid, BDDNode g, DDIndex hid, BDDNode h) { var flevel = Level(fid, f); var glevel = Level(gid, g); var hlevel = Level(hid, h); if (flevel == glevel) { if (flevel == hlevel) { var x = this.Manager.IteRecursive(f.Low, g.Low, h.Low); var y = this.Manager.IteRecursive(f.High, g.High, h.High); return(this.Manager.Allocate(new BDDNode(f.Variable, x, y))); } else if (flevel < hlevel) { var x = this.Manager.IteRecursive(f.Low, g.Low, hid); var y = this.Manager.IteRecursive(f.High, g.High, hid); return(this.Manager.Allocate(new BDDNode(f.Variable, x, y))); } else { var x = this.Manager.IteRecursive(fid, gid, h.Low); var y = this.Manager.IteRecursive(fid, gid, h.High); return(this.Manager.Allocate(new BDDNode(h.Variable, x, y))); } } else if (flevel < glevel) { if (flevel == hlevel) { var x = this.Manager.IteRecursive(f.Low, gid, h.Low); var y = this.Manager.IteRecursive(f.High, gid, h.High); return(this.Manager.Allocate(new BDDNode(f.Variable, x, y))); } else if (flevel < hlevel) { var x = this.Manager.IteRecursive(f.Low, gid, hid); var y = this.Manager.IteRecursive(f.High, gid, hid); return(this.Manager.Allocate(new BDDNode(f.Variable, x, y))); } else { var x = this.Manager.IteRecursive(fid, gid, h.Low); var y = this.Manager.IteRecursive(fid, gid, h.High); return(this.Manager.Allocate(new BDDNode(h.Variable, x, y))); } } else { if (glevel == hlevel) { var x = this.Manager.IteRecursive(fid, g.Low, h.Low); var y = this.Manager.IteRecursive(fid, g.High, h.High); return(this.Manager.Allocate(new BDDNode(g.Variable, x, y))); } else if (glevel < hlevel) { var x = this.Manager.IteRecursive(fid, g.Low, hid); var y = this.Manager.IteRecursive(fid, g.High, hid); return(this.Manager.Allocate(new BDDNode(g.Variable, x, y))); } else { var x = this.Manager.IteRecursive(fid, gid, h.Low); var y = this.Manager.IteRecursive(fid, gid, h.High); return(this.Manager.Allocate(new BDDNode(h.Variable, x, y))); } } }
/// <summary> /// Implement a replacement operation that substitutes /// variables for other variables. /// </summary> /// <param name="xid">The left index.</param> /// <param name="x">The left node.</param> /// <param name="variableMap">The variable set.</param> /// <returns>A new formula with the susbtitution.</returns> public DDIndex Replace(DDIndex xid, CBDDNode x, VariableMap <CBDDNode> variableMap) { throw new System.NotSupportedException(); }