// topologically sort the graph to work out calculation order public Dictionary <string, int> CalculateWeights() { var remainingNodes = new SortedSet <int>(Nodes.Select(n => n.ID).Union(KeyNodes.Select(k => k.Value.ID))); var markedNodes = new SortedSet <int>(); var processors = Nodes.ToDictionary(n => n.ID, n => RFGraphDefinition.GetFullName(n.GraphName, n.Label)); var visitOrder = new List <int>(); while (remainingNodes.Any()) { var remainingNode = remainingNodes.First(); Visit(remainingNode, markedNodes, remainingNodes, visitOrder); } var weights = new Dictionary <string, int>(); int idx = 1; visitOrder.Reverse(); foreach (var node in visitOrder) { if (processors.ContainsKey(node)) { weights.Add(processors[node], idx++); } } return(weights); }
public Dictionary <string, SortedSet <string> > CalculateDependencies() { // for each node list nodes it depends on (i.e. reverse traverse) var processors = Nodes.ToDictionary(n => n.ID, n => RFGraphDefinition.GetFullName(n.GraphName, n.Label)); var dependencies = new Dictionary <string, SortedSet <string> >(); foreach (var node in Nodes) { var visited = new SortedSet <int>(); var toVisit = new SortedSet <int>(Edges.Where(e => e.DestinationNode == node.ID).Select(e => e.SourceNode)); while (toVisit.Any()) { var next = toVisit.First(); toVisit.Remove(next); if (!visited.Contains(next)) { visited.Add(next); foreach (var source in Edges.Where(e => e.DestinationNode == next).Select(e => e.SourceNode)) { if (!visited.Contains(source)) { toVisit.Add(source); } } } } dependencies.Add(processors[node.ID], new SortedSet <string>(visited.Where(v => processors.ContainsKey(v)).Select(v => processors[v]))); } return(dependencies); }
/// <summary> /// Create and add a new graph to the ending to run graph processes. /// </summary> /// <param name="graphName">Unique user-friendly name for the graph.</param> /// <returns>Use methods on the returned object to create graph processes.</returns> public RFGraphDefinition CreateGraph(string graphName) { var newGraph = new RFGraphDefinition(graphName, this); Graphs.Add(graphName, newGraph); return(newGraph); }
protected void AddGraph(RFGraphDefinition graphConfig) { foreach (var graphProcess in graphConfig.Processes.Values) { var graphProcessName = RFGraphDefinition.GetFullName(graphConfig.GraphName, graphProcess.Name); _processes.Add(graphProcessName, new RFEngineProcess(graphProcessName, new RFEngineProcessDefinition { InstanceParams = i => i.ExtractParam().ConvertTo <RFEngineProcessorGraphInstanceParam>(), Name = graphProcessName, Description = graphProcess.Description, Processor = () => new RFGraphProcess(graphProcess) }, _config.KeyDomain)); // check for missing inputs foreach (var p in graphProcess.Processor().CreateDomain().GetType().GetProperties()) { if (RFReflectionHelpers.IsMandatory(p) && graphProcess.IOMappings.SingleOrDefault(m => m.Property.FullName() == p.FullName()) == null) { throw new RFSystemException(this, "Unmapped mandatory property {0} on processor {1}", p.FullName(), graphProcessName); } } // auto-react to inputs foreach (var ioMapping in graphProcess.IOMappings) { var ioBehaviour = ioMapping.Property.GetCustomAttributes(typeof(RFIOBehaviourAttribute), true).FirstOrDefault() as RFIOBehaviourAttribute; var dateBehaviour = ioMapping.DateBehaviour; if (ioBehaviour != null && ioBehaviour.IOBehaviour == RFIOBehaviour.Input) { switch (dateBehaviour) { case RFDateBehaviour.Range: _reactors.Add(RFGraphReactor.RangeReactor(ioMapping.Key, graphProcessName, _context.GetReadingContext(), ioMapping.RangeUpdateFunc, graphProcess.Processor().MaxInstance)); break; case RFDateBehaviour.Exact: case RFDateBehaviour.Latest: case RFDateBehaviour.Previous: _reactors.Add(RFGraphReactor.SimpleReactor(ioMapping.Key, dateBehaviour, graphProcessName, _context.GetReadingContext(), graphProcess.Processor().MaxInstance)); break; } } } } }
protected RFGraphProcessDefinition AddIOMapping <S>(Expression <Func <S, object> > property, RFCatalogKey key, RFIOBehaviour expectedBehvaiour, Func <RFGraphInstance, List <RFDate> > rangeRequestFunc = null, Func <RFGraphInstance, RFDate> rangeUpdateFunc = null) where S : RFGraphProcessorDomain { var processor = Processor(); var domain = processor.CreateDomain(); if (domain.GetType() != typeof(S)) { throw new RFLogicException(this, "IO Domain Type mismatch on processor {0}: {1} vs {2}", RFGraphDefinition.GetFullName(GraphName, Name), domain.GetType().Name, typeof(S).Name); } var propertyInfo = property.GetProperty <S>(); var ioBehaviour = RFReflectionHelpers.GetIOBehaviour(propertyInfo); if (ioBehaviour != expectedBehvaiour) { throw new RFLogicException(this, "Inconsistent IO direction {0} on property {1}, expected {2}.", ioBehaviour, propertyInfo.FullName(), expectedBehvaiour); } var dateBehaviour = RFReflectionHelpers.GetDateBehaviour(propertyInfo); if (dateBehaviour == RFDateBehaviour.Range && (rangeRequestFunc == null || rangeUpdateFunc == null)) { throw new RFLogicException(this, "Range input doesn't have range functions specified on property {0}.", propertyInfo.FullName()); } IOMappings.Add(new RFGraphIOMapping { Key = key, Property = propertyInfo, RangeRequestFunc = rangeRequestFunc, RangeUpdateFunc = rangeUpdateFunc, DateBehaviour = dateBehaviour }); return(this); }
public static RFGraphMap MapGraphs(IEnumerable <RFGraphDefinition> graphs, bool forPresentation = true) { var map = new RFGraphMap(); foreach (var graph in graphs) { foreach (var process in graph.Processes) { var name = RFGraphDefinition.GetFullName(graph.GraphName, process.Value.Name); var processNode = new RFGraphMapNode(map) { Label = process.Value.Name, GraphName = graph.GraphName, NodeType = RFGraphMapNodeType.Processor, FullType = process.Value.Processor().GetType().Name, Description = process.Value.Description }; map.Nodes.Add(processNode); foreach (var ioMapping in process.Value.IOMappings) { if (ioMapping.PropertyName == "Status") { continue; } var ioBehaviour = RFReflectionHelpers.GetIOBehaviour(ioMapping.Property); var dateBehaviour = ioMapping.DateBehaviour; //RFReflectionHelpers.GetDateBehaviour(ioMapping.Property); if (!forPresentation) { // for graph sort we are only interested in exact date inputs and // outputs, which should result in acycylical graph if (ioBehaviour == RFIOBehaviour.State) { continue; } if (dateBehaviour != RFDateBehaviour.Exact && dateBehaviour != RFDateBehaviour.Range && dateBehaviour != RFDateBehaviour.Latest) { continue; } } if (ioMapping.Key != null) { var rawKeyString = KeyLabel(ioMapping.Key.CreateForInstance(null)); var keyLabel = forPresentation ? graph.GraphName + rawKeyString : rawKeyString; if (!map.KeyNodes.ContainsKey(keyLabel)) { map.KeyNodes.Add(keyLabel, new RFGraphMapNode(map) { Label = rawKeyString, RawKey = rawKeyString, NodeType = RFGraphMapNodeType.Key, GraphName = graph.GraphName, FullType = ioMapping.Key.CreateForInstance(null).GetType().Name, Description = "" }); } var keyNode = map.KeyNodes[keyLabel]; if (ioBehaviour == RFIOBehaviour.Input || ioBehaviour == RFIOBehaviour.State) { map.Edges.Add(new RFGraphMapEdge { SourceNode = keyNode.ID, DestinationNode = processNode.ID, Label = ioMapping.PropertyName, EdgeType = ioBehaviour == RFIOBehaviour.Input ? RFGraphMapEdgeType.Input : RFGraphMapEdgeType.State }); keyNode.Description += string.Format("{0} to {1} ({2})<br/>", ioBehaviour, processNode.Label, ioMapping.PropertyName); } if (ioBehaviour == RFIOBehaviour.Output) { map.Edges.Add(new RFGraphMapEdge { SourceNode = processNode.ID, DestinationNode = keyNode.ID, Label = ioMapping.PropertyName, EdgeType = RFGraphMapEdgeType.Output }); keyNode.Description += string.Format("{0} of {1} ({2})<br/>", ioBehaviour, processNode.Label, ioMapping.PropertyName); } } else { // unbound item? check for other domain properties? } } } } return(map); }
public override string FriendlyString() { return(RFGraphDefinition.GetFullName(GraphName, ProcessName)); }