/// <summary> /// Adds to "lines" the lines implied by initial-variable columns not in basis /// (see section 3.4.2 of Cousot and Halbwachs), and adds to "constraints" the /// constraints to exclude those lines (see step 4.2 of section 3.4.3 of /// Cousot and Halbwachs). /// </summary> /// <param name="lines"></param> /// <param name="constraints"></param> public void ProduceLines(ArrayList /*FrameElement*//*!*/ lines, ArrayList /*LinearConstraint*//*!*/ constraints) { Contract.Requires(constraints != null); Contract.Requires(lines != null); // for every initial variable not in basis for (int i0 = 0; i0 < numInitialVars; i0++) { if (inBasis[i0] == -1) { FrameElement fe = new FrameElement(); LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); for (int i = 0; i < numInitialVars; i++) { if (i == i0) { fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), Rational.ONE); lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), Rational.ONE); } else if (inBasis[i] != -1) { // i is a basis column Contract.Assert(m[inBasis[i], i].HasValue(1)); Rational val = -m[inBasis[i], i0]; fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), val); } } lines.Add(fe); constraints.Add(lc); } } }
/// <summary> /// Worker method of TraverseVertices. /// This method has no net effect on the tableau. /// </summary> /// <param name="basesSeenSoFar"></param> /// <param name="vertices"></param> /// <param name="rays"></param> void TraverseBases(ArrayList /*bool[]*//*!*/ basesSeenSoFar, ArrayList /*FrameElement*//*!*/ vertices, ArrayList /*FrameElement*//*!*/ rays) { Contract.Requires(rays != null); Contract.Requires(vertices != null); Contract.Requires(basesSeenSoFar != null); CheckInvariant(); bool[] thisBasis = new bool[numSlackVars]; for (int i = numInitialVars; i < rhsColumn; i++) { if (inBasis[i] != -1) { thisBasis[i - numInitialVars] = true; } } foreach (bool[]/*!*/ basis in basesSeenSoFar) { Contract.Assert(basis != null); Contract.Assert(basis.Length == numSlackVars); for (int i = 0; i < numSlackVars; i++) { if (basis[i] != thisBasis[i]) { goto COMPARE_WITH_NEXT_BASIS; } } // thisBasis and basis are the same--that is, basisColumns has been visited before--so // we don't traverse anything from here return; COMPARE_WITH_NEXT_BASIS: { } } // basisColumns has not been seen before; record thisBasis and continue with the traversal here basesSeenSoFar.Add(thisBasis); #if DEBUG_PRINT Console.Write("TraverseBases, new basis: "); foreach (bool t in thisBasis) { Console.Write("{0}", t ? "*" : "."); } Console.WriteLine(); Dump(); #endif // Add vertex FrameElement v = new FrameElement(); for (int i = 0; i < rows; i++) { int j = basisColumns[i]; if (j < numInitialVars) { v.AddCoordinate((IVariable)cce.NonNull(dims[j]), m[i, rhsColumn]); } } #if DEBUG_PRINT Console.WriteLine(" Adding vertex: {0}", v); #endif vertices.Add(v); // Add rays. Traverse all columns corresponding to slack variables that // are not in basis (see second bullet of section 3.4.2 of Cousot and Halbwachs). for (int i0 = numInitialVars; i0 < rhsColumn; i0++) { if (inBasis[i0] != -1) { // skip those slack-variable columns that are in basis continue; } // check if slack-variable, non-basis column i corresponds to an extreme ray for (int row = 0; row < rows; row++) { if (m[row, i0].IsPositive) { for (int k = numInitialVars; k < rhsColumn; k++) { if (inBasis[k] != -1 && m[row, k].IsNonZero) { // does not correspond to an extreme ray goto CHECK_NEXT_SLACK_VAR; } } } } // corresponds to an extreme ray FrameElement ray = new FrameElement(); for (int i = 0; i < numInitialVars; i++) { int j0 = inBasis[i]; Rational val = -m[j0, i0]; ray.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); } #if DEBUG_PRINT Console.WriteLine(" Adding ray: {0}", ray); #endif rays.Add(ray); CHECK_NEXT_SLACK_VAR: { } } // Continue traversal for (int i = numInitialVars; i < rhsColumn; i++) { int j = inBasis[i]; if (j != -1) { // try moving i out of basis and some other slack-variable column into basis for (int k = numInitialVars; k < rhsColumn; k++) { if (inBasis[k] == -1 && m[j, k].IsPositive) { Rational[] undo = Pivot(j, k); // check if the new basis is feasible for (int p = 0; p < rows; p++) { int c = basisColumns[p]; if (numInitialVars <= c && c < rhsColumn && m[p, rhsColumn].IsNegative) { // not feasible goto AFTER_TRAVERSE; } } TraverseBases(basesSeenSoFar, vertices, rays); AFTER_TRAVERSE: UnPivot(j, k, undo); } } } } }
/// <summary> /// Worker method of TraverseVertices. /// This method has no net effect on the tableau. /// </summary> /// <param name="basesSeenSoFar"></param> /// <param name="vertices"></param> /// <param name="rays"></param> void TraverseBases(ArrayList /*bool[]*//*!*/ basesSeenSoFar, ArrayList /*FrameElement*//*!*/ vertices, ArrayList /*FrameElement*//*!*/ rays) { Contract.Requires(rays != null); Contract.Requires(vertices != null); Contract.Requires(basesSeenSoFar != null); CheckInvariant(); bool[] thisBasis = new bool[numSlackVars]; for (int i = numInitialVars; i < rhsColumn; i++) { if (inBasis[i] != -1) { thisBasis[i - numInitialVars] = true; } } foreach (bool[] /*!*/ basis in basesSeenSoFar) { Contract.Assert(basis != null); Contract.Assert(basis.Length == numSlackVars); for (int i = 0; i < numSlackVars; i++) { if (basis[i] != thisBasis[i]) { goto COMPARE_WITH_NEXT_BASIS; } } // thisBasis and basis are the same--that is, basisColumns has been visited before--so // we don't traverse anything from here return; COMPARE_WITH_NEXT_BASIS : { } } // basisColumns has not been seen before; record thisBasis and continue with the traversal here basesSeenSoFar.Add(thisBasis); #if DEBUG_PRINT Console.Write("TraverseBases, new basis: "); foreach (bool t in thisBasis) { Console.Write("{0}", t ? "*" : "."); } Console.WriteLine(); Dump(); #endif // Add vertex FrameElement v = new FrameElement(); for (int i = 0; i < rows; i++) { int j = basisColumns[i]; if (j < numInitialVars) { v.AddCoordinate((IVariable)cce.NonNull(dims[j]), m[i, rhsColumn]); } } #if DEBUG_PRINT Console.WriteLine(" Adding vertex: {0}", v); #endif vertices.Add(v); // Add rays. Traverse all columns corresponding to slack variables that // are not in basis (see second bullet of section 3.4.2 of Cousot and Halbwachs). for (int i0 = numInitialVars; i0 < rhsColumn; i0++) { if (inBasis[i0] != -1) { // skip those slack-variable columns that are in basis continue; } // check if slack-variable, non-basis column i corresponds to an extreme ray for (int row = 0; row < rows; row++) { if (m[row, i0].IsPositive) { for (int k = numInitialVars; k < rhsColumn; k++) { if (inBasis[k] != -1 && m[row, k].IsNonZero) { // does not correspond to an extreme ray goto CHECK_NEXT_SLACK_VAR; } } } } // corresponds to an extreme ray FrameElement ray = new FrameElement(); for (int i = 0; i < numInitialVars; i++) { int j0 = inBasis[i]; Rational val = -m[j0, i0]; ray.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); } #if DEBUG_PRINT Console.WriteLine(" Adding ray: {0}", ray); #endif rays.Add(ray); CHECK_NEXT_SLACK_VAR : { } } // Continue traversal for (int i = numInitialVars; i < rhsColumn; i++) { int j = inBasis[i]; if (j != -1) { // try moving i out of basis and some other slack-variable column into basis for (int k = numInitialVars; k < rhsColumn; k++) { if (inBasis[k] == -1 && m[j, k].IsPositive) { Rational[] undo = Pivot(j, k); // check if the new basis is feasible for (int p = 0; p < rows; p++) { int c = basisColumns[p]; if (numInitialVars <= c && c < rhsColumn && m[p, rhsColumn].IsNegative) { // not feasible goto AFTER_TRAVERSE; } } TraverseBases(basesSeenSoFar, vertices, rays); AFTER_TRAVERSE: UnPivot(j, k, undo); } } } } }
public LinearConstraintSystem/*!*/ Join(LinearConstraintSystem/*!*/ lcs) { Contract.Requires(lcs != null); Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null); #endif if (this.IsBottom()) { return cce.NonNull(lcs.Clone()); } else if (lcs.IsBottom()) { return cce.NonNull(this.Clone()); } else if (this.IsTop() || lcs.IsTop()) { return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ()); } else { LinearConstraintSystem/*!*/ z; // Start from the "larger" of the two frames (this is just a heuristic measure intended // to save work). Contract.Assume(this.FrameVertices != null); Contract.Assume(this.FrameRays != null); Contract.Assume(this.FrameLines != null); Contract.Assume(lcs.FrameVertices != null); Contract.Assume(lcs.FrameRays != null); Contract.Assume(lcs.FrameLines != null); if (this.FrameVertices.Count + this.FrameRays.Count + this.FrameLines.Count - this.FrameDimensions.Count < lcs.FrameVertices.Count + lcs.FrameRays.Count + lcs.FrameLines.Count - lcs.FrameDimensions.Count) { z = cce.NonNull(lcs.Clone()); lcs = this; } else { z = cce.NonNull(this.Clone()); } #if DEBUG_PRINT Console.WriteLine("DEBUG: LinearConstraintSystem.Join ---------------"); Console.WriteLine("z:"); z.Dump(); Console.WriteLine("lcs:"); lcs.Dump(); #endif // Start by explicating the implicit lines of z for the dimensions dims(lcs)-dims(z). foreach (IVariable/*!*/ dim in lcs.FrameDimensions) { Contract.Assert(dim != null); if (!z.FrameDimensions.Contains(dim)) { z.FrameDimensions.Add(dim); FrameElement line = new FrameElement(); line.AddCoordinate(dim, Rational.ONE); // Note: AddLine is not called (because the line already exists in z--it's just that // it was represented implicitly). Instead, just tack the explicit representation onto // FrameLines. Contract.Assume(z.FrameLines != null); z.FrameLines.Add(line); #if DEBUG_PRINT Console.WriteLine("Join: After explicating line: {0}", line); z.Dump(); #endif } } // Now, the vertices, rays, and lines can be added. foreach (FrameElement/*!*/ v in lcs.FrameVertices) { Contract.Assert(v != null); z.AddVertex(v); #if DEBUG_PRINT Console.WriteLine("Join: After adding vertex: {0}", v); z.Dump(); #endif } foreach (FrameElement/*!*/ r in lcs.FrameRays) { Contract.Assert(r != null); z.AddRay(r); #if DEBUG_PRINT Console.WriteLine("Join: After adding ray: {0}", r); z.Dump(); #endif } foreach (FrameElement/*!*/ l in lcs.FrameLines) { Contract.Assert(l != null); z.AddLine(l); #if DEBUG_PRINT Console.WriteLine("Join: After adding line: {0}", l); z.Dump(); #endif } // also add to z the implicit lines of lcs foreach (IVariable/*!*/ dim in z.FrameDimensions) { Contract.Assert(dim != null); if (!lcs.FrameDimensions.Contains(dim)) { // "dim" is a dimension that's explicit in "z" but implicit in "lcs" FrameElement line = new FrameElement(); line.AddCoordinate(dim, Rational.ONE); z.AddLine(line); #if DEBUG_PRINT Console.WriteLine("Join: After adding lcs's implicit line: {0}", line); z.Dump(); #endif } } z.SimplifyFrame(); z.SimplifyConstraints(); z.CheckInvariant(); #if DEBUG_PRINT Console.WriteLine("Join: Returning z:"); z.Dump(); Console.WriteLine("----------------------------------------"); #endif return z; } }
public static void RunValidationC() { // Run the example in section 3.4.3 of Cousot and Halbwachs backwards, that is, from // from to constraints. IVariable/*!*/ dim1 = new TestVariable("X"); IVariable/*!*/ dim2 = new TestVariable("Y"); IVariable/*!*/ dim3 = new TestVariable("Z"); Contract.Assert(dim1 != null); Contract.Assert(dim2 != null); Contract.Assert(dim3 != null); FrameElement s0 = new FrameElement(); s0.AddCoordinate(dim1, Rational.ONE); s0.AddCoordinate(dim2, Rational.FromInts(1, 2)); s0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); FrameElement s1 = new FrameElement(); s1.AddCoordinate(dim1, Rational.ONE); s1.AddCoordinate(dim2, Rational.FromInts(-1, 2)); s1.AddCoordinate(dim3, Rational.FromInts(1, 2)); FrameElement s2 = new FrameElement(); s2.AddCoordinate(dim1, Rational.FromInt(3)); s2.AddCoordinate(dim2, Rational.FromInts(-3, 2)); s2.AddCoordinate(dim3, Rational.FromInts(3, 2)); FrameElement r0 = new FrameElement(); r0.AddCoordinate(dim1, Rational.ONE); r0.AddCoordinate(dim2, Rational.FromInts(1, 2)); r0.AddCoordinate(dim3, Rational.FromInts(-1, 2)); FrameElement r1 = new FrameElement(); r1.AddCoordinate(dim1, Rational.ONE); r1.AddCoordinate(dim2, Rational.ZERO); r1.AddCoordinate(dim3, Rational.ZERO); FrameElement d0 = new FrameElement(); d0.AddCoordinate(dim1, Rational.ZERO); d0.AddCoordinate(dim2, Rational.ONE); d0.AddCoordinate(dim3, Rational.ONE); LinearConstraintSystem lcs = new LinearConstraintSystem(s0); lcs.Dump(); lcs.AddVertex(s1); lcs.Dump(); lcs.AddVertex(s2); lcs.Dump(); lcs.AddRay(r0); lcs.Dump(); lcs.AddRay(r1); lcs.Dump(); lcs.AddLine(d0); lcs.Dump(); lcs.SimplifyConstraints(); lcs.Dump(); #if LATER lcs.GenerateFrameFromConstraints(); // should give us back the original frame... #endif }
public static void RunValidationA() { IVariable/*!*/ dim1 = new TestVariable("X"); IVariable/*!*/ dim2 = new TestVariable("Y"); IVariable/*!*/ dim3 = new TestVariable("Z"); Contract.Assert(dim1 != null); Contract.Assert(dim2 != null); Contract.Assert(dim3 != null); FrameElement s1 = new FrameElement(); s1.AddCoordinate(dim1, Rational.ONE); s1.AddCoordinate(dim2, Rational.MINUS_ONE); s1.AddCoordinate(dim3, Rational.ZERO); FrameElement s2 = new FrameElement(); s2.AddCoordinate(dim1, Rational.MINUS_ONE); s2.AddCoordinate(dim2, Rational.ONE); s2.AddCoordinate(dim3, Rational.ZERO); FrameElement r1 = new FrameElement(); r1.AddCoordinate(dim1, Rational.ZERO); r1.AddCoordinate(dim2, Rational.ZERO); r1.AddCoordinate(dim3, Rational.ONE); FrameElement d1 = new FrameElement(); d1.AddCoordinate(dim1, Rational.ONE); d1.AddCoordinate(dim2, Rational.ONE); d1.AddCoordinate(dim3, Rational.ZERO); // create lcs from frame -- cf. Cousot/Halbwachs 1978, section 3.3.1.1 LinearConstraintSystem lcs = new LinearConstraintSystem(s1); lcs.Dump(); lcs.AddVertex(s2); lcs.Dump(); lcs.AddRay(r1); lcs.Dump(); lcs.AddLine(d1); lcs.Dump(); lcs.SimplifyConstraints(); lcs.Dump(); #if LATER lcs.GenerateFrameFromConstraints(); // should give us back the original frame... #endif Console.WriteLine("IsSubset? {0}", lcs.IsSubset(lcs.Clone())); lcs.Dump(); }