/// <summary> /// Add a guard to this collection. /// </summary> /// <param name="tg">The trigger guard to add.</param> public void AddGuard(IElementaryTriggerCondition c0, TriggerGuard tg) { var name = tg.Guard.Name; Entry entry; if (!_map.TryGetValue(name, out entry)) { _map[name] = entry = new Entry(tg.Guard); } // calculate effective conditions for the guard var c = new TriggerConditions(c0); switch (tg.Guard.Type) { case GuardType.LEAVE: c.PreCondition = Gate.ComposeAND(c.PreCondition, tg.PreCondition); c.PostCondition = Gate.ComposeAND(c.PostCondition, tg.PostCondition); break; case GuardType.TRANSITION: c.PreCondition = Gate.ComposeAND(c.PreCondition, tg.PreCondition); c.PostCondition = Gate.ComposeAND(c.PostCondition, tg.PostCondition); break; case GuardType.ENTER: c.PostCondition = Gate.ComposeAND(c.PostCondition, tg.PostCondition); break; default: throw new ArgumentException("invalid guard type."); } Log.TraceGuard(c.PreCondition, c.PostCondition, "before join"); if (!TraceFlags.DisableTriggerJoin) { // express postconditions by preconditions c.JoinTrigger(tg.Trigger); } Log.TraceGuard(c.PreCondition, c.PostCondition, "add guard"); // and add to entry entry.Add(c); }
/// <summary> /// Associates a trigger with corresponding guards. /// </summary> /// <param name="trigger">The trigger to associate.</param> private void CalculateTriggerDependencies(ProductTrigger trigger) { var ct = trigger.PreCondition; var gtpost = trigger.PostCondition; var gtpre = ct; TraceDependencies("trigger '{0}' conditions [{1}, {2}] ...", trigger.Name, gtpre, gtpost); if (!trigger.ModifiedVariables.Any()) { TraceDependencies(" does not modify state."); return; } foreach (var guard in Guards) { var gg = guard.PreCondition; TraceDependencies(" guard '{0}' precondition [{1}] ...", guard.Name, gg); var tg = new TriggerGuard(trigger, guard); if (guard.Transitions.Any()) { TraceDependencies(" state change guard ..."); if (!guard.ModifiedVariables.Intersect(trigger.ModifiedVariables).Any()) { TraceDependencies(" no affected variable."); continue; } var gatepre = Gate.ComposeAND(gtpre, gg); if (gatepre.Type == GateType.Fixed) { TraceDependencies(" precondition does not match."); continue; } var gatepost = Gate.ComposeAND(gtpost, guard.PostCondition); if (gatepost.Type == GateType.Fixed) { TraceDependencies(" postcondition does not match."); continue; } TraceDependencies(" combination ({0}, {1}) handler.", gatepre, gatepost); tg.PreCondition = gatepre; tg.PostCondition = gatepost; } else { TraceDependencies(" static condition [{0}] ...", gg); Debug.Assert(guard.PreCondition.ID == guard.PostCondition.ID); IGate genter, gleave; if (guard.Type == GuardType.ENTER) { // PRE[trigger] AND NOT POST[guard] // trigger condition met, guard condition not met genter = Gate.ComposeAND(trigger.PreCondition, Gate.Invert(guard.PreCondition)); // PRE[trigger] AND PRE[guard] // trigger condition met, guard conditon not met gleave = Gate.ComposeAND(trigger.PostCondition, guard.PostCondition); } else { genter = Gate.ComposeAND(trigger.PreCondition, guard.PreCondition); gleave = Gate.ComposeAND(trigger.PostCondition, Gate.Invert(guard.PostCondition)); } var tgenter = genter; var tgleave = gleave; Gate.TraceDependencies(genter, gleave, "guard product"); // set all factors not appearing in the trigger to 1 genter = ReplaceTransitionVariables(trigger.Transitions, genter, true); gleave = ReplaceTransitionVariables(trigger.Transitions, gleave, true); Gate.TraceDependencies(genter, gleave, "inter product"); // set all factors not appearing in the guard to 1 genter = ReplaceNonGuardVariables(genter, guard); gleave = ReplaceNonGuardVariables(gleave, guard); /*genter = ReplaceTransitionVariables(guard.Transitions, genter, true); gleave = ReplaceTransitionVariables(guard.Transitions, gleave, true);*/ Gate.TraceDependencies(genter, gleave, "guard match"); //if (genter is FalseGate || gleave is FalseGate) if (genter.Type.IsFixed() || gleave.Type.IsFixed()) { TraceDependencies(" condition does not match."); continue; } /*tg.PreCondition = guard.PreCondition; tg.PostCondition = guard.PostCondition;*/ tg.PreCondition = tgenter; tg.PostCondition = tgleave; Gate.TraceDependencies(tgenter, tgleave, "guard conditions"); // see if the transition set is non-empty var transx = trigger.Transitions.Match(genter, gleave).ToArray(); if (transx.Length > 0) { if (guard.Type == GuardType.ENTER) { TraceDependencies(" entry handler."); } else if (guard.Type == GuardType.LEAVE) { TraceDependencies(" exit handler."); } else { throw new InvalidOperationException("unexpected guard type."); } } else { TraceDependencies(" transition does not match."); continue; } } // associate the trigger with the guard and vice versa trigger.AddGuard(tg); } }
/// <summary> /// Associates a guard object with this trigger. /// </summary> /// <param name="g"></param> public void AddGuard(TriggerGuard g) { _guards.Add(g); }
/// <summary> /// Associates a guard object with this trigger. /// </summary> /// <param name="g"></param> public void AddGuard(TriggerGuard g) { _guards.Add(g); }