Ejemplo n.º 1
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;
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Wires a flow individually meaning all steps inside. Basically the method <see cref="SetEdgesInStepBlock(IReadOnlyList{Node}, out Matrix{bool}, out List{ExternalEdge}, out List{InternalEdge}, out List{int})"/>
        /// is called for the flow.
        /// </summary>
        /// <param name="flow">The flow to wire.</param>
        /// <param name="flowOffset">The offset of the flows nodes. Later used to identify its edges in the edge matrix.</param>
        /// <returns>A tuple containing the offset as item 1, the flow as item 2 and then all the out parameters of <see cref="SetEdgesInStepBlock(IReadOnlyList{Node}, out Matrix{bool}, out List{ExternalEdge}, out List{InternalEdge}, out List{int})"/>.</returns>
        public static Tuple <int, Flow, Matrix <bool>, List <ExternalEdge>, List <InternalEdge>, List <Tuple <int, Condition?> >, Matrix <Condition?> > WireFlowIndividually(Flow flow, int flowOffset)
        {
            IReadOnlyList <Node>            steps = flow.Nodes;
            Matrix <bool>                   edgeMatrix;
            List <ExternalEdge>             externalEdges;
            List <InternalEdge>             possibleInvalidIfEdges;
            List <Tuple <int, Condition?> > exitSteps;
            Matrix <Condition?>             conditionMatrix;

            GraphBuilder.SetEdgesInStepBlock(steps, out edgeMatrix, out externalEdges, out possibleInvalidIfEdges, out exitSteps, out conditionMatrix);
            return(new Tuple <int, Flow, Matrix <bool>, List <ExternalEdge>, List <InternalEdge>, List <Tuple <int, Condition?> >, Matrix <Condition?> >(
                       flowOffset,
                       flow,
                       edgeMatrix,
                       externalEdges,
                       possibleInvalidIfEdges,
                       exitSteps,
                       conditionMatrix));
        }