private void stepComplete(KpSimulationStep step) { owt.WriteLine(); owt.WriteLine("Configuration #{0}", step.Step); owt.WriteLine("-------------------------------------------------"); writeKPsystem(step.KPsystem); owt.WriteLine("-------------------------------------------------"); }
public KPsystem Run() { KpSimulationStep simStep = new KpSimulationStep() { KPsystem = kp, Step = step }; if (SimulationStarted != null) { SimulationStarted(kp); } List <ActiveInstance> activeInstances = new List <ActiveInstance>(); List <ActiveInstance> targetSelections = new List <ActiveInstance>(); HashSet <ActiveInstance> deadCells = new HashSet <ActiveInstance>(); while (!isHalted && step <= endStep) { rulesApplied = 0; bool advanceStrategyBlock = false; bool endStepForInstance = false; bool dissolutionRuleApplied = false; bool divisionRuleApplied = false; bool linkRuleApplied = false; activeInstances.AddRange(allOperationalInstances); int aiCount = activeInstances.Count; while (aiCount > 0) { //reset instance flags advanceStrategyBlock = false; endStepForInstance = false; //select an instance ActiveInstance selectedInstance = activeInstances[rand.Next(aiCount)]; ExecutionStrategy ex = selectedInstance.CurrentStrategySegment; //this can only happen if the rule set was set to empty if (selectedInstance.ApplicableRules.Count > 0) { Rule selectedRule = null; bool isRuleApplicable = true; if (ex.Operator == StrategyOperator.SEQUENCE) { selectedRule = selectedInstance.ApplicableRules.First(); if (selectedRule.IsGuarded) { if (!selectedRule.Guard.IsSatisfiedBy(selectedInstance.Instance.Multiset)) { isRuleApplicable = false; } else if (selectedInstance.FlagStructureRuleApplied) { if (selectedRule.IsStructureChangingRule()) { isRuleApplicable = false; } } } } else { int selectedIndex = 0; int arCount = selectedInstance.ApplicableRules.Count; if (ex.Operator == StrategyOperator.ARBITRARY) { selectedIndex = rand.Next(arCount + 1); } else { selectedIndex = rand.Next(arCount); } if (selectedIndex == arCount) { //this essentially means "skip this block" - always in an arbitrary block, never elsewhere selectedRule = null; isRuleApplicable = false; } else { selectedRule = selectedInstance.ApplicableRules[selectedIndex]; if (selectedInstance.FlagStructureRuleApplied) { if (selectedRule.IsStructureChangingRule()) { isRuleApplicable = false; } } } } if (isRuleApplicable) { if (selectedRule is ConsumerRule) { if ((selectedRule as ConsumerRule).Lhs > selectedInstance.Instance.Multiset) { isRuleApplicable = false; } } } //At this point, the isRuleApplicable basically confirms that no structure rule has been applied thus far //if the selected rule requires this, if guarded, the guard of the selected rule holds and //the left hand multiset is contained in the instance multiset if (isRuleApplicable) { switch (selectedRule.Type) { case RuleType.REWRITE_COMMUNICATION: { RewriteCommunicationRule rcr = selectedRule as RewriteCommunicationRule; foreach (KeyValuePair <IInstanceIdentifier, TargetedMultiset> kv in rcr.TargetRhs) { if (kv.Key is InstanceIdentifier) { InstanceIdentifier iid = kv.Key as InstanceIdentifier; if (iid.Indicator == InstanceIndicator.TYPE) { IndexedMType targetType = indexedTypesByName[iid.Value]; int cCount = selectedInstance.ConnectionCount(targetType); if (cCount > 0) { ActiveInstance selectedTarget = selectedInstance.GetTargetAtIndex(rand.Next(cCount), targetType); selectedTarget.CommunicatedMultiset = kv.Value.Multiset; targetSelections.Add(selectedTarget); } else { isRuleApplicable = false; break; } } } } if (isRuleApplicable) { selectedInstance.Instance.Multiset.Subtract(rcr.Lhs); selectedInstance.Buffer.Add(rcr.Rhs); ruleApplied(selectedRule, selectedInstance.Instance); foreach (ActiveInstance ai in targetSelections) { if (step >= startStep) { if (recordTargetSelection) { if (TargetSelected != null) { TargetSelected(ai.Instance, ai.Type, selectedRule); } } } ai.CommitCommunication(); } } else { foreach (ActiveInstance ai in targetSelections) { ai.ResetCommunication(); } } targetSelections.Clear(); } break; case RuleType.MULTISET_REWRITING: { ruleApplied(selectedRule, selectedInstance.Instance); selectedInstance.Instance.Multiset.Subtract((selectedRule as ConsumerRule).Lhs); selectedInstance.Buffer.Add((selectedRule as RewritingRule).Rhs); } break; case RuleType.MEMBRANE_DISSOLUTION: { ruleApplied(selectedRule, selectedInstance.Instance); dissolutionRuleApplied = true; selectedInstance.FlagDissolved = true; selectedInstance.Instance.Multiset.Subtract((selectedRule as ConsumerRule).Lhs); } break; case RuleType.LINK_CREATION: { LinkRule lr = selectedRule as LinkRule; if (lr.Target is InstanceIdentifier) { string typeName = (lr.Target as InstanceIdentifier).Value; IndexedMType targetType = indexedTypesByName[typeName]; ActiveInstance selectedTarget = null; //check if there is a link-free instance we can connect to int freeLinkCount = targetType.Instances.Count - selectedInstance.ConnectionCount(targetType); if (freeLinkCount > 0) { int selection = rand.Next(freeLinkCount); int i = 0; foreach (ActiveInstance ai in targetType.Instances) { if (!selectedInstance.IsConnectedTo(ai)) { if (i++ == selection) { selectedTarget = ai; } } } selectedInstance.Instance.Multiset.Subtract(lr.Lhs); ruleApplied(selectedRule, selectedInstance.Instance); linkRuleApplied = true; //selected target can't be null here selectedInstance.ConnectionToCreate = selectedTarget; selectedInstance.FlagLinkRuleApplied = true; if (step >= startStep) { if (recordTargetSelection) { if (TargetSelected != null) { TargetSelected(selectedTarget.Instance, selectedTarget.Type, selectedRule); } } } //a structure rule can only be applied once per step so remove it selectedInstance.ApplicableRules.Remove(selectedRule); } else { isRuleApplicable = false; } } } break; case RuleType.LINK_DESTRUCTION: { LinkRule lr = selectedRule as LinkRule; if (lr.Target is InstanceIdentifier) { string typeName = (lr.Target as InstanceIdentifier).Value; IndexedMType targetType = indexedTypesByName[typeName]; int cCount = selectedInstance.ConnectionCount(targetType); if (cCount > 0) { ActiveInstance selectedTarget = selectedInstance.GetTargetAtIndex(rand.Next(cCount), targetType); selectedInstance.Instance.Multiset.Subtract(lr.Lhs); ruleApplied(selectedRule, selectedInstance.Instance); linkRuleApplied = true; //selected target can't be null here selectedInstance.ConnectionToDestroy = selectedTarget; selectedInstance.FlagLinkRuleApplied = true; if (step >= startStep) { if (recordTargetSelection) { if (TargetSelected != null) { TargetSelected(selectedTarget.Instance, selectedTarget.Type, selectedRule); } } } //a structure rule can only be applied once per step so remove it selectedInstance.ApplicableRules.Remove(selectedRule); } else { isRuleApplicable = false; } } } break; case RuleType.MEMBRANE_DIVISION: { DivisionRule dr = selectedRule as DivisionRule; selectedInstance.Instance.Multiset.Subtract(dr.Lhs); foreach (InstanceBlueprint ib in dr.Rhs) { selectedInstance.AddInstanceBlueprint(ib, indexedTypesByName[ib.Type.Name]); } selectedInstance.FlagDivided = true; ruleApplied(selectedRule, selectedInstance.Instance); divisionRuleApplied = true; } break; } } if (selectedInstance.FlagDissolved || selectedInstance.FlagDivided) { allOperationalInstances.Remove(selectedInstance); endStepForInstance = true; } else { switch (ex.Operator) { case StrategyOperator.SEQUENCE: { if (isRuleApplicable) { selectedInstance.ApplicableRules.Remove(selectedRule); } else { endStepForInstance = true; } } break; case StrategyOperator.MAX: { if (!isRuleApplicable) { selectedInstance.ApplicableRules.Remove(selectedRule); } } break; case StrategyOperator.CHOICE: { if (isRuleApplicable) { advanceStrategyBlock = true; } else { selectedInstance.ApplicableRules.Remove(selectedRule); } } break; case StrategyOperator.ARBITRARY: { if (!isRuleApplicable) { if (selectedRule == null) { advanceStrategyBlock = true; } else { selectedInstance.ApplicableRules.Remove(selectedRule); } } } break; } } } if (endStepForInstance) { activeInstances.Remove(selectedInstance); } else { if (selectedInstance.ApplicableRules.Count == 0) { advanceStrategyBlock = true; } if (advanceStrategyBlock) { ex = ex.Next; //if the next execution block is null, then remove this compartment from the active instance array if (ex == null) { activeInstances.Remove(selectedInstance); } else { selectedInstance.CurrentStrategySegment = ex; } } } aiCount = activeInstances.Count; } if (rulesApplied == 0) { isHalted = true; } else { //Clear buffer for all instances; foreach (ActiveInstance instance in allInstances) { instance.CommitBuffer(); if (linkRuleApplied) { if (instance.FlagLinkRuleApplied) { instance.CommitConnectionUpdates(); } } } if (dissolutionRuleApplied || divisionRuleApplied) { foreach (ActiveInstance instance in allInstances) { if (instance.FlagDissolved) { instance.Instance.IsDissolved = true; deadCells.Add(instance); instance.CommitDissolution(); } else if (instance.FlagDivided) { instance.Instance.IsDivided = true; deadCells.Add(instance); instance.CommitNewInstances(onNewInstanceCreated); } } if (divisionRuleApplied) { foreach (ActiveInstance ai in newInstanceSet) { allInstances.Add(ai); } newInstanceSet.Clear(); } } foreach (ActiveInstance instance in deadCells) { //remove from allInstances collection such that a dead instance will never be //considered for updates or any sort of operations allInstances.Remove(instance); //remove this instance from the set of instances associated to its type so //it will never be considered for link creation or destruction instance.IndexedMType.Instances.Remove(instance); } if (deadCells.Count > 0) { deadCells.Clear(); } //reset execution strategy to begining //it's important this is done after everthing has been commited, because the guards must be evaluated on the updated multiset //in the instance foreach (ActiveInstance ai in allOperationalInstances) { ai.ResetCurrentStrategySegment(); } if (step >= startStep) { if (SimulationParams.RecordConfigurations) { if (StepComplete != null) { simStep.Step = step; StepComplete(simStep); } } } ++step; } } --step; if (IsHalted() && SystemHalted != null) { SystemHalted(step); } if (SimulationComplete != null) { SimulationComplete(step); } return(kp); }