Esempio n. 1
0
        /// <summary>
        /// Handles a nested block. A nested block is explained with an if statement as example.
        /// The given lists/matrices are correctly updated.
        /// <para/>
        /// Consider the following block. Only the first block is shown. The texts in [] describe the role of the important steps for that statement.
        /// <para/>
        /// IF George can fly THEN [block start]
        /// <para/>
        /// Go fly George. [nested block step]
        /// <para/>
        /// And don't come back. [nested block step]
        /// <para/>
        /// ELSE [block end]
        /// <para/>
        /// You're trapped to this world. :(
        /// <para/>
        /// ENDIF [exit target step]
        /// </summary>
        /// <param name="steps">The steps containing the block.</param>
        /// <param name="edgeMatrix">The edge matrix.</param>
        /// <param name="externalEdges">The external edges list.</param>
        /// <param name="possibleInvalidIfEdges">The possible invalid if edge list.</param>
        /// <param name="conditionMatrix">The condition matrix.</param>
        /// <param name="blockStartIndex">The index of the block start. (The step before the nested block begins)</param>
        /// <param name="blockEndIndex">The index of the block end. (The step after the nested block ends)</param>
        /// <param name="exitStepsTargetStep">The step to where create the edges if the nested block has exit steps.</param>
        /// <param name="blockEntryCondition">The condition to be fulfilled to enter the nested block.</param>
        public static void SetEdgesInNestedBlock(
            IReadOnlyList <Node> steps,
            ref Matrix <bool> edgeMatrix,
            ref List <ExternalEdge> externalEdges,
            ref List <InternalEdge> possibleInvalidIfEdges,
            ref Matrix <Condition?> conditionMatrix,
            int blockStartIndex,
            int blockEndIndex,
            int exitStepsTargetStep,
            Condition?blockEntryCondition)
        {
            int blockSize = blockEndIndex - blockStartIndex - 1;

            // Set edge into the nested block
            edgeMatrix[blockStartIndex, blockStartIndex + 1]      = true;
            conditionMatrix[blockStartIndex, blockStartIndex + 1] = blockEntryCondition;

            List <Node> nestedSteps = steps.Skip(blockStartIndex + 1).Take(blockSize).ToList();

            Matrix <bool>                   nestedEdgeMatrix;
            List <ExternalEdge>             nestedExternalEdges;
            List <InternalEdge>             nestedPossibleInvalidIfEdges;
            List <Tuple <int, Condition?> > nestedExitSteps;
            Matrix <Condition?>             nestedConditionMatrix;

            GraphBuilder.SetEdgesInStepBlock(nestedSteps, out nestedEdgeMatrix, out nestedExternalEdges, out nestedPossibleInvalidIfEdges, out nestedExitSteps, out nestedConditionMatrix);

            // Unite matrices
            GraphBuilder.InsertMatrix(ref edgeMatrix, blockStartIndex + 1, blockStartIndex + 1, nestedEdgeMatrix);
            GraphBuilder.InsertMatrix(ref conditionMatrix, blockStartIndex + 1, blockStartIndex + 1, nestedConditionMatrix);

            // Unite externalEdges
            externalEdges.AddRange(nestedExternalEdges.ConvertAll((edge) => edge.NewWithIncreasedSourceStepNumber(blockStartIndex + 1)));

            // Unite possible invalid if edges
            possibleInvalidIfEdges.AddRange(nestedPossibleInvalidIfEdges.ConvertAll((edge) => edge.NewWithIncreasedSourceTargetStep(blockStartIndex + 1)));

            // Wire exit steps to end if step
            foreach (Tuple <int, Condition?> exitStep in nestedExitSteps)
            {
                edgeMatrix[exitStep.Item1 + blockStartIndex + 1, exitStepsTargetStep]      = true;
                conditionMatrix[exitStep.Item1 + blockStartIndex + 1, exitStepsTargetStep] = exitStep.Item2;
            }
        }
Esempio n. 2
0
        /// <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;
                }
            }
        }