We look at the debugging output, and ... see a whopping 337 dead nodes—in words: Three hundred and thirty seven! It is definitely not possible to scan all of them to find the place where new rules are missing. What can we do?
Looking at the first few nodes, we see that they start with constraints like 0 = –10, 0 = –60, 0 = –50 and the like. If we did nothing wrong in our rules up to now, these nodes are definitely dead—whichever rules we add, these equations will never become true, and hence these nodes will never be on the path to a solution. So, for our debugging sanity, we must distinguish such nodes from the promising ones that can be eked towards a solution with new rules.
Here is a simple way to reach this goal: Before returning null from a node that cannot be expanded, we mark it with a flag as "definitely dead." For convenience, the marking method returns null so that we can use it as a return value in a rule. It is used, for example, in the last line of our first rule matching 0=C:
var z = new TypeMatchTemplate<Constant>();
new RuleAction<ScalarConstraintMatcher>("0=C",
new EqualsZeroConstraintTemplate(z).GetMatchDelegate(),
matcher => matcher != null,
...
(currNode, matcher, matchedConstraint) =>
matcher.Match(z).Value.Near(0)
? new SolverNode(...)
: currNode.MarkDefinitelyDead());
new RuleAction<ScalarConstraintMatcher>("0=C",
new EqualsZeroConstraintTemplate(z).GetMatchDelegate(),
matcher => matcher != null,
...
(currNode, matcher, matchedConstraint) =>
matcher.Match(z).Value.Near(0)
? new SolverNode(...)
: currNode.MarkDefinitelyDead());
In the debugging output, we first write out the promising dead nodes, i.e., the ones that are not definitely dead. Afterwards, we add the definitely dead ones (that we will be glad to see when we introduce a bug in our rules that closes nodes prematurely). With that change, we get now eight promising nodes (and 329 definitely dead ones). Here are the first two promising ones:
TestRotatingBar : Failed---- 8 Promising dead nodes ---- SolverNode 5148 < V->E-5147 < V->E-5145 < root*5143 < root*5141 < root... ! {EqualsZeroConstraint}0 = 200+-(--(200+10*x*0.923879532511287+0)+sqrt(10000+-((200+---(200+10*x*0.38268343236509+0))²+0))) ! {EqualsZeroConstraint}0 = 200+-(--(200+10*x*0.38268343236509+0)+sqrt(10000+-((200+---(200+10*x*0.923879532511287+0))²+0))) ! {EqualsZeroConstraint}0 = 0+-(0+sqrt(10000+-((200+---(200+10*x*0.923879532511287+0))²+(200+---(200+10*x*0.38268343236509+0))²))) ! {AtLeastZeroConstraint}0 <= 10000+-((200+---(200+10*x*0.38268343236509+0))²+0) ! {AtLeastZeroConstraint}0 <= 10000+-((200+---(200+10*x*0.923879532511287+0))²+0) ! {AtLeastZeroConstraint}0 <= 10000+-((200+---(200+10*x*0.923879532511287+0))²+(200+---(200+10*x*0.38268343236509+0))²) WH.C.X:=200 WH.C.Y:=200 WH.C.Z:=0 WH.P.Z:=0 ZERO:=0 WH.P.X:={UnaryExpression}--(200+10*x*0.923879532511287+0) WH.P.Y:={UnaryExpression}--(200+10*x*0.38268343236509+0) SolverNode 5150 < V->E-5149 < V->E-5146 < root*5143 < root*5141 < root... ! {EqualsZeroConstraint}0 = 200+-(--(200+10*x*0.923879532511287+0)+sqrt(10000+-((200+---(200+10*x*0.38268343236509+0))²+0))) ! {EqualsZeroConstraint}0 = 200+-(--(200+10*x*0.38268343236509+0)+sqrt(10000+-((200+---(200+10*x*0.923879532511287+0))²+0))) ! {EqualsZeroConstraint}0 = 0+-(0+-sqrt(10000+-((200+---(200+10*x*0.923879532511287+0))²+(200+---(200+10*x*0.38268343236509+0))²))) ! {AtLeastZeroConstraint}0 <= 10000+-((200+---(200+10*x*0.38268343236509+0))²+0) ! {AtLeastZeroConstraint}0 <= 10000+-((200+---(200+10*x*0.923879532511287+0))²+0) ! {AtLeastZeroConstraint}0 <= 10000+-((200+---(200+10*x*0.923879532511287+0))²+(200+---(200+10*x*0.38268343236509+0))²) WH.C.X:=200 WH.C.Y:=200 WH.C.Z:=0 WH.P.Z:=0 ZERO:=0 WH.P.X:={UnaryExpression}--(200+10*x*0.923879532511287+0) WH.P.Y:={UnaryExpression}--(200+10*x*0.38268343236509+0)
We will take a look at them in the next posting—and it will be a long look!
No comments:
Post a Comment