Class: DecisionAgent::Dmn::DecisionGraph
- Inherits:
-
Object
- Object
- DecisionAgent::Dmn::DecisionGraph
- Defined in:
- lib/decision_agent/dmn/decision_graph.rb
Overview
Represents and evaluates a decision graph (DMN model with multiple decisions)
Instance Attribute Summary collapse
-
#decisions ⇒ Object
readonly
Returns the value of attribute decisions.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Instance Method Summary collapse
- #add_decision(decision) ⇒ Object
-
#circular_dependencies? ⇒ Boolean
Detect circular dependencies.
-
#dependency_graph ⇒ Object
Get the dependency graph as a hash.
-
#evaluate(decision_id, context) ⇒ Object
Evaluate a specific decision (and all its dependencies).
-
#evaluate_all(context) ⇒ Object
Evaluate all decisions in the graph.
- #get_decision(decision_id) ⇒ Object
-
#initialize(id:, name:) ⇒ DecisionGraph
constructor
A new instance of DecisionGraph.
-
#leaf_decisions ⇒ Object
Get all leaf decisions (no other decisions depend on them).
-
#root_decisions ⇒ Object
Get all root decisions (don't depend on other decisions).
-
#to_h ⇒ Object
Export graph structure.
-
#topological_order ⇒ Object
Get decisions in topological order (respecting dependencies).
Constructor Details
#initialize(id:, name:) ⇒ DecisionGraph
Returns a new instance of DecisionGraph.
66 67 68 69 70 71 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 66 def initialize(id:, name:) @id = id @name = name @decisions = {} # decision_id => DecisionNode @feel_evaluator = Feel::Evaluator.new end |
Instance Attribute Details
#decisions ⇒ Object (readonly)
Returns the value of attribute decisions.
64 65 66 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 64 def decisions @decisions end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
64 65 66 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 64 def id @id end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
64 65 66 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 64 def name @name end |
Instance Method Details
#add_decision(decision) ⇒ Object
73 74 75 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 73 def add_decision(decision) @decisions[decision.id] = decision end |
#circular_dependencies? ⇒ Boolean
Detect circular dependencies
137 138 139 140 141 142 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 137 def circular_dependencies? topological_order false rescue DmnError => e e..include?("Circular dependency") end |
#dependency_graph ⇒ Object
Get the dependency graph as a hash
162 163 164 165 166 167 168 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 162 def dependency_graph graph = {} @decisions.each do |id, decision| graph[id] = decision.information_requirements.map { |req| req[:decision_id] } end graph end |
#evaluate(decision_id, context) ⇒ Object
Evaluate a specific decision (and all its dependencies)
82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 82 def evaluate(decision_id, context) decision = @decisions[decision_id] raise DmnError, "Decision '#{decision_id}' not found" unless decision # Reset all decision evaluations reset_all! # Build evaluation context eval_context = context.is_a?(Hash) ? context : context.to_h # Evaluate the requested decision (will recursively evaluate dependencies) evaluate_decision(decision, eval_context) end |
#evaluate_all(context) ⇒ Object
Evaluate all decisions in the graph
97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 97 def evaluate_all(context) reset_all! eval_context = context.is_a?(Hash) ? context : context.to_h results = {} @decisions.each do |decision_id, decision| results[decision_id] = evaluate_decision(decision, eval_context) unless decision.evaluated end results end |
#get_decision(decision_id) ⇒ Object
77 78 79 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 77 def get_decision(decision_id) @decisions[decision_id] end |
#leaf_decisions ⇒ Object
Get all leaf decisions (no other decisions depend on them)
145 146 147 148 149 150 151 152 153 154 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 145 def leaf_decisions dependent_decisions = Set.new @decisions.each_value do |decision| decision.information_requirements.each do |req| dependent_decisions.add(req[:decision_id]) end end @decisions.keys.reject { |id| dependent_decisions.include?(id) } end |
#root_decisions ⇒ Object
Get all root decisions (don't depend on other decisions)
157 158 159 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 157 def root_decisions @decisions.select { |_id, decision| decision.information_requirements.empty? }.keys end |
#to_h ⇒ Object
Export graph structure
171 172 173 174 175 176 177 178 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 171 def to_h { id: @id, name: @name, decisions: @decisions.transform_values(&:to_h), dependency_graph: dependency_graph } end |
#topological_order ⇒ Object
Get decisions in topological order (respecting dependencies)
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/decision_agent/dmn/decision_graph.rb', line 110 def topological_order order = [] visited = Set.new temp_mark = Set.new visit = lambda do |decision_id| return if visited.include?(decision_id) raise DmnError, "Circular dependency detected involving decision '#{decision_id}'" if temp_mark.include?(decision_id) temp_mark.add(decision_id) decision = @decisions[decision_id] decision.information_requirements.each do |req| visit.call(req[:decision_id]) if @decisions[req[:decision_id]] end temp_mark.delete(decision_id) visited.add(decision_id) order << decision_id end @decisions.each_key { |decision_id| visit.call(decision_id) } order end |