コード例 #1
0
        internal void Expand(Constraint violatedConstraint)
        {
            Debug_ClearDfDv(false /* forceFull */);

            // Calculate the derivative at the point of each constraint.
            // violatedConstraint's edge may be the minimum so pass null for variableDoneEval.
            // 
            // We also want to find the path along the active constraint tree from violatedConstraint.Left
            // to violatedConstraint.Right, and find the constraint on that path with the lowest Langragian
            // multiplier. The ActiveConstraints form a spanning tree so there will be no more than
            // one path. violatedConstraint is not yet active so it will not appear in this list.
            if (null == this.constraintPath)
            {
                this.constraintPath = new List<ConstraintDirectionPair>();
            }
            this.constraintPath.Clear();
            this.pathTargetVariable = violatedConstraint.Right;

#if VERBOSE
            Console.WriteLine("Before Block.Expand ComputeDfDv: {0}", this);
#endif // VERBOSE

            ComputeDfDv(violatedConstraint.Left);

#if VERBOSE
            Console.WriteLine("After Block.Expand ComputeDfDv: {0}", this);
            DumpState(null /* no prefix */);
#endif // VERBOSE

            // Now find the forward non-equality constraint on the path that has the minimal Lagrangina.
            // Both variables of the constraint are in the same block so a path should always be found.
            Constraint minLagrangianConstraint = null;
            if (this.constraintPath.Count > 0)
            {
                // We found an existing path so must remove an edge from our active list so that all 
                // connected variables from its varRight onward can move to the right; this will
                // make the "active" status false for that edge.  The active non-Equality constraint
                // with the minimal Lagrangian *that points rightward* is our split point (do *not*
                // split Equality constraints).
                foreach (ConstraintDirectionPair pathItem in this.constraintPath)
                {
#if VERBOSE
                    Console.WriteLine("ConstraintPath: {0} ({1})", pathItem.Constraint, pathItem.IsForward ? "forward" : "backward");
#endif // VERBOSE
                    if (pathItem.IsForward 
                            && ((null == minLagrangianConstraint) || (pathItem.Constraint.Lagrangian < minLagrangianConstraint.Lagrangian)))
                    {
                        if (!pathItem.Constraint.IsEquality)
                        {
                            minLagrangianConstraint = pathItem.Constraint;
                        }
                    }
                }
#if VERBOSE
                DumpPath("Expand path", minLagrangianConstraint);
#endif // VERBOSE
                if (null != minLagrangianConstraint)
                {
                    // Deactivate this constraint as we are splitting on it.
                    this.allConstraints.DeactivateConstraint(minLagrangianConstraint);
                }
            }

            this.constraintPath.Clear();
            this.pathTargetVariable = null;

            if (null == minLagrangianConstraint)
            {
                // If no forward non-equality edge was found, violatedConstraint would have created a cycle.
                Debug.Assert(!violatedConstraint.IsUnsatisfiable, "An already-unsatisfiable constraint should not have been attempted");
                violatedConstraint.IsUnsatisfiable = true;
                ++this.allConstraints.NumberOfUnsatisfiableConstraints;
#if VERBOSE
                Console.WriteLine("  -- Expand: No forward non-equality edge (minLagrangianConstraint) found, therefore the constraint is unsatisfiable -- ");
                Console.WriteLine("     Unsatisfiable constraint: {0}", violatedConstraint);
#endif // VERBOSE
                return;
            }

            // Note: for perf, expand in-place (as in Ipsep) rather than Split/Merge (as in the Scaling paper).

            // Adjust the offset of each variable at and past the right-hand side of violatedConstraint in the
            // active spanning tree.  Because we've removed minLagrangianConstraint, this will widen the
            // gap between minLagrangianConstraint.Left and .Right.  Note that this must include not only
            // violatedConstraint.Right and those to its right, but also those to its left that are connected
            // to it by active constraints - because the definition of an active constraint is that the
            // gap matches exactly with the actual position, so all will move as a unit.
            var lstConnectedVars = new List<Variable>();

            // We consider .Left "already evaluated" because we don't want the path evaluation to back
            // up to it (because we're splitting .Right off from it by deactivating the constraint).
            GetConnectedVariables(lstConnectedVars, violatedConstraint.Right, violatedConstraint.Left);
            double violation = violatedConstraint.Violation;
            int cConnectedVars = lstConnectedVars.Count;
            for (int ii = 0; ii < cConnectedVars; ++ii)
            {
                lstConnectedVars[ii].OffsetInBlock += violation;
            }

            // Now make the (no-longer-) violated constraint active.
            this.allConstraints.ActivateConstraint(violatedConstraint);

            // Clear the DfDv values.  For DEBUG, the new constraint came in from outside this block 
            // so this will make sure it doesn't have a stale cycle-detection flag.
            violatedConstraint.ClearDfDv();

            // Update this block's reference position.
            this.UpdateReferencePos();

#if VERBOSE
            Console.WriteLine("Block.Expand result: {0}", this);
            DumpState(null /* no prefix */);
#endif // VERBOSE
        } // end Expand()