/// <summary> /// Initializes a new instance of the <see cref="Flow"/> struct. /// </summary> /// <param name="identifier">The identifier of the flow.</param> /// <param name="postcondition">The postcondition of the flow.</param> /// <param name="nodes">The nodes of the flow</param> /// <param name="referenceSteps">The reference steps of the flow.</param> public Flow(FlowIdentifier identifier, string postcondition, IReadOnlyList <Node> nodes, IReadOnlyList <ReferenceStep> referenceSteps) { this.Identifier = identifier; this.Postcondition = postcondition; this.Nodes = nodes; this.ReferenceSteps = referenceSteps; }
/// <summary> /// Builds the graph. /// </summary> /// <param name="basicFlow">The basic flow. It will be extended with a step, with an empty description, if the last step is a validates that or until step so that the condition does not get lost.</param> /// <param name="specificAlternativeFlowsUnnormalized">The specific alternative flows. Reference steps starting with 1.</param> /// <param name="globalAlternativeFlows">The global alternative flows.</param> /// <param name="boundedAlternativeFlowsUnnormalized">The bounded alternative flows. Reference steps starting with 1.</param> /// <param name="steps">The steps of all flows.</param> /// <param name="edgeMatrix">The edge matrix for the steps.</param> /// <param name="conditionMatrix">The condition matrix for the flows.</param> public static void BuildGraph( ref Flow basicFlow, IReadOnlyList <Flow> specificAlternativeFlowsUnnormalized, IReadOnlyList <Flow> globalAlternativeFlows, IReadOnlyList <Flow> boundedAlternativeFlowsUnnormalized, out List <Node> steps, out Matrix <bool> edgeMatrix, out Matrix <Condition?> conditionMatrix) { basicFlow = GraphBuilder.ExtendBasicFlowIfNecessary(basicFlow); IReadOnlyList <Flow> specificAlternativeFlows = GraphBuilder.NormalizeReferenceSteps(specificAlternativeFlowsUnnormalized); IReadOnlyList <Flow> boundedAlternativeFlows = GraphBuilder.NormalizeReferenceSteps(boundedAlternativeFlowsUnnormalized); steps = new List <Node>(); List <Flow> allFlows = new List <Flow>(); allFlows.Add(basicFlow); allFlows.AddRange(specificAlternativeFlows); allFlows.AddRange(globalAlternativeFlows); allFlows.AddRange(boundedAlternativeFlows); // Wire all flows individually. The tuples have as item 1 the offset for the steps list and edge matrix and then all out parameters of SetEdgesInStepBlock. List <Tuple <int, Flow, Matrix <bool>, List <ExternalEdge>, List <InternalEdge>, List <Tuple <int, Condition?> >, Matrix <Condition?> > > individuallyWiredFlows = GraphBuilder.WireFlowListIndividually(allFlows, 0); // Collect all steps in the steps list foreach (Flow flow in allFlows) { steps.AddRange(flow.Nodes); } // Copy each flows edge/condition matrix into the global one edgeMatrix = new Matrix <bool>(steps.Count, false); conditionMatrix = new Matrix <Condition?>(steps.Count, null); foreach (Tuple <int, Flow, Matrix <bool>, List <ExternalEdge>, List <InternalEdge>, List <Tuple <int, Condition?> >, Matrix <Condition?> > individuallyWiredFlow in individuallyWiredFlows) { GraphBuilder.InsertMatrix(ref edgeMatrix, individuallyWiredFlow.Item1, individuallyWiredFlow.Item1, individuallyWiredFlow.Item3); GraphBuilder.InsertMatrix(ref conditionMatrix, individuallyWiredFlow.Item1, individuallyWiredFlow.Item1, individuallyWiredFlow.Item7); } // Wire external edges. foreach (Tuple <int, Flow, Matrix <bool>, List <ExternalEdge>, List <InternalEdge>, List <Tuple <int, Condition?> >, Matrix <Condition?> > individuallyWiredFlow in individuallyWiredFlows) { List <ExternalEdge> externalEdges = individuallyWiredFlow.Item4; foreach (ExternalEdge externalEdge in externalEdges) { // Get offset of target flow. FlowIdentifier targetIdentifier = externalEdge.TargetStep.Identifier; List <Tuple <int, Flow, Matrix <bool>, List <ExternalEdge>, List <InternalEdge>, List <Tuple <int, Condition?> >, Matrix <Condition?> > > targetFlow = individuallyWiredFlows.Where((iwf) => iwf.Item2.Identifier.Equals(targetIdentifier)).ToList(); int targetFlowOffset = targetFlow[0].Item1, targetStep = targetFlowOffset + externalEdge.TargetStep.Step, sourceStep = individuallyWiredFlow.Item1 + externalEdge.SourceStepNumber; edgeMatrix[sourceStep, targetStep] = true; } } // Wire alternative flows reference steps foreach (Tuple <int, Flow, Matrix <bool>, List <ExternalEdge>, List <InternalEdge>, List <Tuple <int, Condition?> >, Matrix <Condition?> > individuallyWiredFlow in individuallyWiredFlows) { Flow flow = individuallyWiredFlow.Item2; FlowType flowType = flow.Identifier.Type; int flowOffset = individuallyWiredFlow.Item1; switch (flowType) { case FlowType.Basic: // Does not have reference steps. break; case FlowType.SpecificAlternative: case FlowType.BoundedAlternative: // The flow can be entered only at the first step or at multiple ones if it is an outsourced elseif-else statement. int targetStep = flowOffset; foreach (ReferenceStep referenceStep in flow.ReferenceSteps) { FlowIdentifier sourceIdentifier = referenceStep.Identifier; List <Tuple <int, Flow, Matrix <bool>, List <ExternalEdge>, List <InternalEdge>, List <Tuple <int, Condition?> >, Matrix <Condition?> > > sourceFlow = individuallyWiredFlows.Where((iwf) => iwf.Item2.Identifier.Equals(sourceIdentifier)).ToList(); int sourceFlowOffset = sourceFlow[0].Item1; int sourceStep = sourceFlowOffset + referenceStep.Step; // Remove possible invalid if edge if present List <InternalEdge> invalidIfEdges = sourceFlow[0].Item5.Where((piie) => piie.SourceStep == referenceStep.Step).ToList(); foreach (InternalEdge invalidIfEdge in invalidIfEdges) { int invalidTargetStep = sourceFlowOffset + invalidIfEdge.TargetStep; // If the block is empty than the edges for fulfilled and not fulfilled condition are the same. // In that case the invalid edge does not have a condition and thus its condition must be set to the fulfilled condition of the if/else if statement step. if (conditionMatrix[sourceStep, invalidTargetStep] != null) { conditionMatrix[sourceStep, invalidTargetStep] = null; edgeMatrix[sourceStep, invalidTargetStep] = false; } else { conditionMatrix[sourceStep, invalidTargetStep] = new Condition(steps[sourceStep].StepDescription, true); } } edgeMatrix[sourceStep, targetStep] = true; conditionMatrix[sourceStep, targetStep] = new Condition(steps[sourceStep].StepDescription, false); } break; case FlowType.GlobalAlternative: // Gets an edge from every step of the basic flow. // Basic flow is always at offset 0. for (int sourceStep = 0; sourceStep < basicFlow.Nodes.Count; sourceStep++) { edgeMatrix[sourceStep, flowOffset] = true; conditionMatrix[sourceStep, flowOffset] = new Condition(individuallyWiredFlow.Item2.Nodes[0].StepDescription, true); } break; } } }