/// <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> /// Combines this trigger condition with the preconditions of a product trigger. /// </summary> /// <param name="trigger"></param> /// <remarks> /// <para>This eliminates the post-condition.</para></remarks> public void JoinTrigger(ProductTrigger trigger) { var tset = trigger.Transitions; Log.TraceGuard("join trigger: " + tset.ToDebugString()); // express the postcondition by precondition factors var postfrompre = PostCondition.Replace(e => { var vc = e as IVariableCondition; if (null != vc) { if (tset.Contains(vc.Variable)) { // express variable by preconditions e = tset.InferPostState(vc.Variable, vc.StateIndex); Log.TraceGuard(vc.Decompose(), e, "ss"); } else if (trigger.Event.Transitions.Contains(vc.Variable)) { // variable unchanged but affected by trigger, keep post condition e = Gate.Constant(true); } else { // if not in event tset, move to precondition } } return e; }).Simplify(); var postreduced = PostCondition.Replace(e => { var vc = e as IVariableCondition; if (null != vc) { if (tset.Contains(vc.Variable)) { // express variable by preconditions e = Gate.Constant(true); } else if (trigger.Event.Transitions.Contains(vc.Variable)) { // keep } else { // move before e = Gate.Constant(true); } } return e; }).Simplify(); Log.TraceGuard(PostCondition, postfrompre, "post from pre"); // move post condition into precondition for evalulation PreCondition = Gate.ComposeAND(PreCondition, postfrompre); Log.TraceGuard(PostCondition, postreduced, "reduced post"); // post condition void PostCondition = postreduced; }
public TriggerGuard(ProductTrigger t, Guard g) { Trigger = t; Guard = g; }