public static Workflow ScheduleWorkflowGlobal(string name, string description, List <Data> inputs, List <Data> outputs, List <WorkflowComponent> components, GlobalReversalMode mode) { List <WorkflowComponent> workflowComponents = components.GetAllComponents(); var allData = inputs.Concat(outputs).ToList(); // 0. Samity checks, check is not more than 1 output if (mode == GlobalReversalMode.NoReversedModels) { if (!AllSanityCheck(workflowComponents)) { mode = GlobalReversalMode.ReverseModelsWhenReversibleVariables; } } else if (mode == GlobalReversalMode.Global) { if (!AllSanityCheck(workflowComponents)) { throw new ArgumentException($"A default workflow does not exist. Therefore the gloabl workflow cannot be created"); } } if (mode == GlobalReversalMode.ReverseModelsWhenReversibleVariables) { NonReversibleSanityCheck(workflowComponents); } // 1. Find Model-Variable matching. Which variables are inputs, and wich are outputs for each model MatchingDictionary outputsDict = MatchModelsWithVariablesGlobal(allData, components, mode); // 2. Determine which models are reversed, and create reversed Workflows (Model or Global) to cater for them ReverseComponents(name, outputsDict, workflowComponents, out List <WorkflowComponent> matchedComponents, out List <WorkflowComponent> reversedComponents); // 4. Cluster Strongly Connected Components to get an acyclic graph List <WorkflowComponent> clusteredComponents = ClusterStronglyConnectedComponents(name, allData, matchedComponents); // 5. Schedule the acyclic graph to get the final order of the components List <WorkflowComponent> scheduledComponents = ScheduleAcyclic(allData, clusteredComponents); Workflow workflow = null; if (clusteredComponents.Count < matchedComponents.Count) { workflow = ScheduleWorkflowSCC(name.Split(':').First(), description, inputs, outputs, workflowComponents, matchedComponents); } else { workflow = new WorkflowGlobal(name, description, inputs, outputs, components, scheduledComponents, DeafaultSolvers(), mode != GlobalReversalMode.Global, mode.ToString()); } workflow.DependencyAnalysis = new GraphBasedDependencyAnalysis(matchedComponents); return(workflow); }
/// <summary> /// This function identifies the Modified models (from imMatrixi and imMatrif) in the modelObjects, then creates a 'modified model subprocess' for each modified model, /// and therafter combines it with other models in the modelObjects and return it in a object array /// </summary> /// <param name="IMi"></param> /// <param name="IMf"></param> /// <param name="components"></param> /// <param name="data"></param> /// <param name="clusters"></param> /// <param name="name"></param> /// <returns></returns> private static WorkflowComponent[] CreateReversedModels(IncidenceMatrix IMi, IncidenceMatrix IMf, List <WorkflowComponent> components, List <Data> data, List <Cluster> clusters, string name) { var processedComponents = new WorkflowComponent[IMf.RowCount]; for (int r = 0; r < IMi.RowCount; r++) { WorkflowComponent component = components[r]; Vector <double> row = IMi.Row(r); if (!IMf.Row(r).CompareAssigned(row)) { List <int> inputIndices = row.FindLocations(IN); List <int> outputIndices = row.FindLocations(OUT); var inputs = inputIndices.Select(i => data[i]).ToList(); var outputs = outputIndices.Select(i => data[i]).ToList(); if (component is Model model) { processedComponents[r] = model.Reverse(inputs, outputs); } else if (component is Workflow workflow) { var opts = new NewtonOptions() { MaxIterations = 20, DerivativeStep = new double[] { 0.01 } }; var solver = new NewtonSolver(opts); processedComponents[r] = new WorkflowGlobal($"{name}#GlobalWorkflow#{workflow.Name}", "", inputs, outputs, workflow.Components, workflow.Components, new List <ISolver>() { solver }); } } else { processedComponents[r] = components[r]; } } return(processedComponents); }
private static List <WorkflowComponent> ClusterReversedModel(string name, List <Data> allData, List <WorkflowComponent> matchedComponents, List <WorkflowComponent> reversedComponents, ReversalMode mode, List <WorkflowComponent> components) { //// Identify Reversed Components //foreach (var component in matchedComponents) // if (component is IReversableWorkflow reversable && reversable.ReversedInputs.Count > 0) // reversedComponents.Add(component); // 3.1. Graph only with reversed links of non-reversible variables only, both forward and backward (can be thought as undirected) var reversedLinksGraph = new Graph(); foreach (Data data in reversedComponents.GetAllData()) { reversedLinksGraph.AddVertex(data.Id); } foreach (WorkflowComponent component in reversedComponents) { AddComponentAndEdgesBoth(reversedLinksGraph, component, mode); } // 3.2. Forward graph - To trace forward dependencies var forwardGraph = new Graph(); foreach (Data data in allData) { forwardGraph.AddVertex(data.Id); } foreach (WorkflowComponent component in matchedComponents) { AddComponentAndEdgesForward(forwardGraph, component); } //forwardGraph = GraphBuilder.FromTwoSets(matchedComponents, allData, name1: c => CS(c.Id), from1to2: c => c.ModelDataOutputs, to1from2: c => c.ModelDataInputs); // 3.3. Reversed graph - To trace backward dependencies var reversedGraph = new Graph(); foreach (Data data in allData) { reversedGraph.AddVertex(data.Id); } foreach (WorkflowComponent component in matchedComponents) { AddComponentAndEdgesBackWard(reversedGraph, component); } // 3.4 Group reversed components var visitedComponents = new HashSet <string>(); var reversedComponentsHash = new HashSet <string>(reversedComponents.Select(c => CS(c.Id))); var componentsHash = new HashSet <string>(matchedComponents.Select(c => CS(c.Id))); var componentsUnderStudy = new Stack <string>(); var groups = new List <HashSet <string> >(); HashSet <string> groupForwardHash = null; // Used to reduce unnecesary visits, if node is visited for one component in the group it shouldn't be visited more HashSet <string> groupBackwardHash = null; // Used to reduce unnecesary visits, if node is visited for one component in the group it shouldn't be visited more foreach (WorkflowComponent component in reversedComponents) { // 3.4.1. If the component has not been studied start studie and prepare a gropup for the component if (!visitedComponents.Contains(CS(component.Id))) { groups.Add(new HashSet <string>()); groupForwardHash = new HashSet <string>(); groupBackwardHash = new HashSet <string>(); componentsUnderStudy.Push(CS(component.Id)); } while (componentsUnderStudy.Count > 0) { // 3.4.2. Get the component under study to investigate its dependencies string componentUnderStudy = componentsUnderStudy.Pop(); if (visitedComponents.Contains(componentUnderStudy)) { continue; } // 3.4.3. Group with adajacent reversed components HashSet <string> adjacent = reversedLinksGraph.DepthFirstSearch(componentUnderStudy); foreach (string adj in adjacent) { visitedComponents.Add(adj); } // If there is more than one component joint by non-reversible variables if (adjacent.Where(a => reversedComponentsHash.Contains(a)).Count() > 1) { // 3.4.4. Extend with others dependencies HashSet <string> affectedForward = forwardGraph.DepthFirstSearch(adjacent, groupForwardHash); HashSet <string> affectedBackward = reversedGraph.DepthFirstSearch(adjacent, groupBackwardHash); affectedForward.IntersectWith(affectedBackward); adjacent.UnionWith(affectedForward); } // 3.4.5. If dependencies include a new reversed model push to the stack to be studied foreach (string adj in adjacent) { // If a component is a reversed component and hasn't been added yet if (!visitedComponents.Contains(adj) && reversedComponentsHash.Contains(adj)) { componentsUnderStudy.Push(adj); } else { visitedComponents.Add(adj); } // Add to the group of dependent model from the first reversed model under study if (componentsHash.Contains(adj)) { groups.Last().Add(adj); } } } } // 3.5 Create Globally Reversed Workflows for each group var globalReversedComponents = new List <WorkflowComponent>(); var componentsDict = matchedComponents.ToDictionary(c => CS(c.Id)); foreach (HashSet <string> group in groups) { if (group.Count > 1) { var groupComponents = group.Select(c => componentsDict[c]).ToList(); // new List<WorkflowComponent>(); List <Data> groupData = groupComponents.GetAllData(); var(groupInputs, groupOutputs, _) = groupComponents.GetInputsOutputsStatus(groupData); GlobalReversalMode globalMode = (mode == ReversalMode.GroupNonReversibleOnly) ? GlobalReversalMode.ReverseModelsWhenReversibleVariables : GlobalReversalMode.NoReversedModels; string globalName = WorkflowGlobal.GetGlobalWorkflowName(name, components, groupComponents); Workflow globalWorkflow = ScheduleWorkflowGlobal(globalName, "", groupInputs, groupOutputs, groupComponents, globalMode); globalReversedComponents.Add(globalWorkflow); } else { // If the group consists of one component only, it is already a reversed model and does not have any unfeasible reversal globalReversedComponents.Add(componentsDict[group.First()]); } } // 3.6. Add the rest of components globalReversedComponents.AddRange(matchedComponents.Where(c => !visitedComponents.Contains(CS(c.Id)))); return(globalReversedComponents); }