Class: SuperInstance::Equipment::SwarmCoordinator::TaskDecomposer

Inherits:
Object
  • Object
show all
Defined in:
lib/equipment/swarm_coordinator/task_decomposer.rb

Overview

TaskDecomposer analyzes and decomposes complex tasks into manageable subtasks.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = {}) ⇒ TaskDecomposer

Creates a new TaskDecomposer

Parameters:

  • config (Hash) (defaults to: {})

    Configuration options



102
103
104
105
106
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 102

def initialize(config = {})
  @config = DecompositionConfig.new(**config)
  @decomposition_strategies = initialize_strategies
  @task_templates = {}
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



98
99
100
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 98

def config
  @config
end

Instance Method Details

#add_dependency(graph, task_id, depends_on) ⇒ Object

Add a dependency between tasks

Parameters:

  • graph (DependencyGraph)

    Dependency graph

  • task_id (String)

    Task ID

  • depends_on (String)

    Task it depends on



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 187

def add_dependency(graph, task_id, depends_on)
  unless graph.nodes.key?(task_id) && graph.nodes.key?(depends_on)
    raise Error, 'Both tasks must exist in the graph'
  end

  deps = graph.dependencies[task_id] || []
  deps << depends_on unless deps.include?(depends_on)
  graph.dependencies[task_id] = deps

  dependents = graph.dependents[depends_on] || []
  dependents << task_id unless dependents.include?(task_id)
  graph.dependents[depends_on] = dependents

  graph.layers = calculate_layers(graph)
end

#analyze_task(task, context = {}) ⇒ TaskAnalysis

Analyze a task to determine decomposition potential

Parameters:

  • task (String)

    Task description

  • context (Hash) (defaults to: {})

    Execution context

Returns:



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 138

def analyze_task(task, context = {})
  type = identify_task_type(task, context)
  complexity = estimate_complexity(task, context)
  capabilities = identify_required_capabilities(task, type)
  can_decompose = can_decompose(task, type, complexity)
  strategy = select_strategy(type, complexity)

  TaskAnalysis.new(
    type: type,
    complexity: complexity,
    required_capabilities: capabilities,
    can_decompose: can_decompose,
    suggested_strategy: strategy,
    estimated_duration: estimate_duration(complexity, type),
    dependencies: detect_dependencies(task, context)
  )
end

#decompose(task, context = {}) ⇒ DependencyGraph

Decompose a task into a dependency graph

Parameters:

  • task (String)

    Task description

  • context (Hash) (defaults to: {})

    Execution context

Returns:



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 112

def decompose(task, context = {})
  analysis = analyze_task(task, context)
  root_task = create_task_node(task, analysis, nil)

  graph = DependencyGraph.new(
    graph_id: generate_id,
    nodes: { root_task.task_id => root_task },
    dependencies: { root_task.task_id => [] },
    dependents: { root_task.task_id => [] },
    layers: [],
    root_task_id: root_task.task_id,
    created_at: DateTime.now
  )

  if analysis.can_decompose && analysis.complexity > @config.min_task_size
    decompose_recursive(root_task, graph, context, 0)
  end

  graph.layers = calculate_layers(graph)
  graph
end

#from_template(template_name, params) ⇒ TaskNode?

Create task from template

Parameters:

  • template_name (String)

    Template name

  • params (Hash)

    Template parameters

Returns:



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 274

def from_template(template_name, params)
  template = @task_templates[template_name]
  return nil unless template

  description = interpolate_template(template.description_template, params)
  analysis = TaskAnalysis.new(
    type: template.type,
    complexity: template.base_complexity,
    required_capabilities: template.required_capabilities,
    can_decompose: template.can_decompose,
    suggested_strategy: template.strategy,
    estimated_duration: template.estimated_duration,
    dependencies: []
  )

  create_task_node(description, analysis, nil)
end

#get_ready_tasks(graph, completed) ⇒ Array<TaskNode>

Get tasks ready for execution

Parameters:

  • graph (DependencyGraph)

    Dependency graph

  • completed (Set<String>)

    Set of completed task IDs

Returns:

  • (Array<TaskNode>)

    Tasks ready to execute



168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 168

def get_ready_tasks(graph, completed)
  ready = []

  graph.nodes.each do |task_id, task|
    next if completed.include?(task_id) || task.status != Types::ExecutionStatus::IDLE

    deps = graph.dependencies[task_id] || []
    all_deps_met = deps.all? { |dep| completed.include?(dep) }

    ready << task if all_deps_met
  end

  ready.sort_by { |t| -get_priority_value(t.priority) }
end

#get_statistics(graph) ⇒ Hash

Get task statistics

Parameters:

Returns:

  • (Hash)

    Statistics object



249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 249

def get_statistics(graph)
  nodes = graph.nodes.values

  GraphStatistics.new(
    total_tasks: nodes.size,
    by_status: group_by_status(nodes),
    by_type: group_by_type(nodes),
    by_priority: group_by_priority(nodes),
    max_depth: graph.layers.size,
    critical_path: find_critical_path(graph),
    parallelism_factor: calculate_parallelism_factor(graph)
  )
end

#get_task(graph, task_id) ⇒ TaskNode?

Get a task by ID from a graph

Parameters:

  • graph (DependencyGraph)

    Dependency graph

  • task_id (String)

    Task identifier

Returns:

  • (TaskNode, nil)

    Task node or undefined



160
161
162
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 160

def get_task(graph, task_id)
  graph.nodes[task_id]
end

#register_template(name, template) ⇒ Object

Register a task template

Parameters:

  • name (String)

    Template name

  • template (TaskTemplate)

    Task template



266
267
268
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 266

def register_template(name, template)
  @task_templates[name] = template
end

#remove_dependency(graph, task_id, depends_on) ⇒ Object

Remove a dependency

Parameters:

  • graph (DependencyGraph)

    Dependency graph

  • task_id (String)

    Task ID

  • depends_on (String)

    Task to remove dependency on



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 207

def remove_dependency(graph, task_id, depends_on)
  deps = graph.dependencies[task_id] || []
  dep_index = deps.index(depends_on)
  if dep_index
    deps.delete_at(dep_index)
    graph.dependencies[task_id] = deps
  end

  dependents = graph.dependents[depends_on] || []
  dependent_index = dependents.index(task_id)
  if dependent_index
    dependents.delete_at(dependent_index)
    graph.dependents[depends_on] = dependents
  end

  graph.layers = calculate_layers(graph)
end

#update_task_status(graph, task_id, status) ⇒ Object

Update task status

Parameters:

  • graph (DependencyGraph)

    Dependency graph

  • task_id (String)

    Task identifier

  • status (Symbol)

    New status



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/equipment/swarm_coordinator/task_decomposer.rb', line 229

def update_task_status(graph, task_id, status)
  task = graph.nodes[task_id]
  return unless task

  updated_task = if status == Types::ExecutionStatus::RUNNING && !task.started_at
    task.with(started_at: DateTime.now, status: status)
  elsif [:completed, :failed].include?(status)
    completed_at = DateTime.now
    actual_duration = task.started_at ? ((completed_at - task.started_at) * 86_400_000).to_i : nil
    task.with(completed_at: completed_at, actual_duration: actual_duration, status: status)
  else
    task.with(status: status)
  end

  graph.nodes[task_id] = updated_task
end