orfeas_petri_flow 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +80 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.md +592 -0
  5. data/Rakefile +28 -0
  6. data/lib/petri_flow/colored/arc_expression.rb +163 -0
  7. data/lib/petri_flow/colored/color.rb +40 -0
  8. data/lib/petri_flow/colored/colored_net.rb +146 -0
  9. data/lib/petri_flow/colored/guard.rb +104 -0
  10. data/lib/petri_flow/core/arc.rb +63 -0
  11. data/lib/petri_flow/core/marking.rb +64 -0
  12. data/lib/petri_flow/core/net.rb +121 -0
  13. data/lib/petri_flow/core/place.rb +54 -0
  14. data/lib/petri_flow/core/token.rb +55 -0
  15. data/lib/petri_flow/core/transition.rb +88 -0
  16. data/lib/petri_flow/export/cpn_tools_exporter.rb +322 -0
  17. data/lib/petri_flow/export/json_exporter.rb +224 -0
  18. data/lib/petri_flow/export/pnml_exporter.rb +229 -0
  19. data/lib/petri_flow/export/yaml_exporter.rb +246 -0
  20. data/lib/petri_flow/export.rb +193 -0
  21. data/lib/petri_flow/generators/adapters/aasm_adapter.rb +69 -0
  22. data/lib/petri_flow/generators/adapters/state_machines_adapter.rb +83 -0
  23. data/lib/petri_flow/generators/state_machine_adapter.rb +47 -0
  24. data/lib/petri_flow/generators/workflow_generator.rb +176 -0
  25. data/lib/petri_flow/matrix/analyzer.rb +151 -0
  26. data/lib/petri_flow/matrix/causation.rb +126 -0
  27. data/lib/petri_flow/matrix/correlation.rb +79 -0
  28. data/lib/petri_flow/matrix/crud_event_mapping.rb +74 -0
  29. data/lib/petri_flow/matrix/lineage.rb +113 -0
  30. data/lib/petri_flow/matrix/reachability.rb +128 -0
  31. data/lib/petri_flow/railtie.rb +41 -0
  32. data/lib/petri_flow/registry.rb +85 -0
  33. data/lib/petri_flow/simulation/simulator.rb +188 -0
  34. data/lib/petri_flow/simulation/trace.rb +119 -0
  35. data/lib/petri_flow/tasks/petri_flow.rake +229 -0
  36. data/lib/petri_flow/verification/boundedness_checker.rb +127 -0
  37. data/lib/petri_flow/verification/invariant_checker.rb +144 -0
  38. data/lib/petri_flow/verification/liveness_checker.rb +153 -0
  39. data/lib/petri_flow/verification/reachability_analyzer.rb +152 -0
  40. data/lib/petri_flow/verification_runner.rb +287 -0
  41. data/lib/petri_flow/version.rb +5 -0
  42. data/lib/petri_flow/visualization/graphviz.rb +220 -0
  43. data/lib/petri_flow/visualization/mermaid.rb +191 -0
  44. data/lib/petri_flow/workflow.rb +228 -0
  45. data/lib/petri_flow.rb +164 -0
  46. metadata +174 -0
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PetriFlow
4
+ # Base class for defining workflow Petri nets using a declarative DSL.
5
+ #
6
+ # @example Define a workflow
7
+ # class RefundRequestWorkflow < PetriFlow::Workflow
8
+ # workflow_name "RefundRequestWorkflow"
9
+ #
10
+ # places :requested, :under_review, :approved, :rejected, :processed, :cancelled
11
+ # initial_place :requested
12
+ # terminal_places :rejected, :processed, :cancelled
13
+ #
14
+ # transition :start_review, from: :requested, to: :under_review
15
+ # transition :approve, from: :under_review, to: :approved
16
+ # transition :reject, from: :requested, to: :rejected
17
+ # transition :reject, from: :under_review, to: :rejected
18
+ # transition :process, from: :approved, to: :processed
19
+ # transition :cancel, from: :requested, to: :cancelled
20
+ # transition :cancel, from: :under_review, to: :cancelled
21
+ # end
22
+ #
23
+ class Workflow
24
+ class << self
25
+ attr_reader :defined_places, :defined_transitions, :defined_initial_place,
26
+ :defined_terminal_places, :defined_workflow_name
27
+
28
+ # DSL: Set workflow name
29
+ # @param name [String] The name for this workflow
30
+ def workflow_name(name)
31
+ @defined_workflow_name = name
32
+ end
33
+
34
+ # DSL: Define places (states) in the workflow
35
+ # @param place_ids [Array<Symbol>] List of place identifiers
36
+ # Note: This also resets transitions to handle file reloading gracefully
37
+ def places(*place_ids)
38
+ @defined_places = place_ids.flatten.map(&:to_sym)
39
+ # Reset transitions when places are redefined (handles `load` being called multiple times)
40
+ @defined_transitions = []
41
+ end
42
+
43
+ # DSL: Set the initial place (starting state)
44
+ # @param place_id [Symbol] The initial place identifier
45
+ def initial_place(place_id)
46
+ @defined_initial_place = place_id.to_sym
47
+ end
48
+
49
+ # DSL: Set terminal places (end states)
50
+ # @param place_ids [Array<Symbol>] List of terminal place identifiers
51
+ def terminal_places(*place_ids)
52
+ @defined_terminal_places = place_ids.flatten.map(&:to_sym)
53
+ end
54
+
55
+ # DSL: Define a transition between places
56
+ #
57
+ # Supports three patterns:
58
+ # - Simple: `from: :a, to: :b` (one input, one output)
59
+ # - Fork: `from: :a, to: [:b, :c]` (one input, multiple outputs - parallel split)
60
+ # - Join: `from: [:a, :b], to: :c` (multiple inputs, one output - synchronization)
61
+ #
62
+ # @param name [Symbol] Transition name (e.g., :approve, :reject)
63
+ # @param from [Symbol, Array<Symbol>] Source place(s) - array for join pattern
64
+ # @param to [Symbol, Array<Symbol>] Target place(s) - array for fork pattern
65
+ # @param method [String] Optional method name for audit trail
66
+ # @param trigger [String] Optional trigger description
67
+ def transition(name, from:, to:, method: nil, trigger: nil)
68
+ @defined_transitions ||= []
69
+
70
+ # Normalize to arrays for uniform handling
71
+ from_places = Array(from).map(&:to_sym)
72
+ to_places = Array(to).map(&:to_sym)
73
+
74
+ # Generate unique ID based on all input places
75
+ transition_id = generate_transition_id(name, from_places.first)
76
+
77
+ @defined_transitions << {
78
+ id: transition_id,
79
+ name: name.to_sym,
80
+ from: from_places,
81
+ to: to_places,
82
+ method: method || "#{name}!",
83
+ trigger: trigger
84
+ }
85
+ end
86
+
87
+ # Hook called when a class inherits from Workflow
88
+ # Registers the subclass with the Registry
89
+ def inherited(subclass)
90
+ super
91
+ Registry.register(subclass) if defined?(Registry) && Registry.respond_to?(:register)
92
+ end
93
+
94
+ private
95
+
96
+ def generate_transition_id(name, from)
97
+ :"t_#{name}_from_#{from}"
98
+ end
99
+ end
100
+
101
+ attr_reader :net, :verification_results, :terminal_reachability
102
+
103
+ def initialize
104
+ @net = PetriFlow.create_net(name: workflow_name)
105
+ @verification_results = {}
106
+ @terminal_reachability = {}
107
+ build_net
108
+ end
109
+
110
+ # Get the workflow name
111
+ # @return [String] The workflow name
112
+ def workflow_name
113
+ self.class.defined_workflow_name || self.class.name
114
+ end
115
+
116
+ # Get a URL-safe identifier for this workflow
117
+ # @return [String] Underscored workflow name
118
+ def workflow_id
119
+ workflow_name.underscore.gsub("::", "_").gsub(/\s+/, "_")
120
+ end
121
+
122
+ # Build the Petri net from class definitions
123
+ def build_net
124
+ add_places
125
+ add_transitions
126
+ end
127
+
128
+ # Create initial marking (token distribution)
129
+ # @return [PetriFlow::Core::Marking] The initial marking
130
+ def initial_marking
131
+ tokens = self.class.defined_places.each_with_object({}) do |place, hash|
132
+ hash[place] = (place == self.class.defined_initial_place) ? 1 : 0
133
+ end
134
+ PetriFlow::Core::Marking.new(tokens)
135
+ end
136
+
137
+ # Reset net to initial state
138
+ def reset_to_initial!
139
+ @net.set_marking(initial_marking)
140
+ end
141
+
142
+ # Run full verification
143
+ # @return [Hash] Verification results
144
+ def verify!
145
+ reset_to_initial!
146
+ @verification_results = PetriFlow.verify(@net)
147
+ verify_terminal_reachability
148
+ @verification_results
149
+ end
150
+
151
+ # Export as Mermaid diagram
152
+ # @return [String] Mermaid diagram source
153
+ def to_mermaid
154
+ PetriFlow.visualize(@net, format: :mermaid)
155
+ end
156
+
157
+ # Export as DOT diagram
158
+ # @return [String] GraphViz DOT source
159
+ def to_dot
160
+ PetriFlow.visualize(@net, format: :dot)
161
+ end
162
+
163
+ # Run simulation
164
+ # @param steps [Integer] Number of simulation steps
165
+ # @param strategy [Symbol] Simulation strategy (:random, :priority, :least_used)
166
+ # @return [PetriFlow::Simulation::Trace] Simulation trace
167
+ def simulate(steps: 20, strategy: :random)
168
+ reset_to_initial!
169
+ simulator = PetriFlow::Simulation::Simulator.new(@net)
170
+ simulator.run(steps: steps, strategy: strategy)
171
+ end
172
+
173
+ private
174
+
175
+ def add_places
176
+ self.class.defined_places.each do |place_id|
177
+ initial_tokens = (place_id == self.class.defined_initial_place) ? 1 : 0
178
+ @net.add_place(
179
+ id: place_id,
180
+ name: place_id.to_s.titleize,
181
+ initial_tokens: initial_tokens
182
+ )
183
+ end
184
+ end
185
+
186
+ def add_transitions
187
+ self.class.defined_transitions.each do |transition|
188
+ @net.add_transition(
189
+ id: transition[:id],
190
+ name: transition[:method] || transition[:trigger] || transition[:name].to_s
191
+ )
192
+
193
+ # Handle fork pattern: multiple output places
194
+ # Handle join pattern: multiple input places
195
+ from_places = Array(transition[:from])
196
+ to_places = Array(transition[:to])
197
+
198
+ # Add input arcs (place → transition)
199
+ from_places.each do |place_id|
200
+ @net.add_arc(source_id: place_id, target_id: transition[:id])
201
+ end
202
+
203
+ # Add output arcs (transition → place)
204
+ to_places.each do |place_id|
205
+ @net.add_arc(source_id: transition[:id], target_id: place_id)
206
+ end
207
+ end
208
+ end
209
+
210
+ def verify_terminal_reachability
211
+ analyzer = PetriFlow::Verification::ReachabilityAnalyzer.new(@net, initial_marking)
212
+ analyzer.analyze
213
+
214
+ # Get all reachable markings
215
+ reachable_markings = analyzer.reachable_markings
216
+
217
+ self.class.defined_terminal_places&.each do |state|
218
+ # Check if ANY reachable marking has a token in this terminal place
219
+ # This correctly handles fork patterns where multiple places have tokens
220
+ @terminal_reachability[state] = reachable_markings.any? do |marking|
221
+ marking.tokens_at(state) > 0
222
+ end
223
+ end
224
+
225
+ reset_to_initial!
226
+ end
227
+ end
228
+ end
data/lib/petri_flow.rb ADDED
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+ require "active_support/core_ext"
5
+ require "matrix"
6
+ require "securerandom"
7
+ require "digest"
8
+ require "set"
9
+
10
+ require_relative "petri_flow/version"
11
+
12
+ # Core Petri net components
13
+ require_relative "petri_flow/core/place"
14
+ require_relative "petri_flow/core/transition"
15
+ require_relative "petri_flow/core/arc"
16
+ require_relative "petri_flow/core/token"
17
+ require_relative "petri_flow/core/marking"
18
+ require_relative "petri_flow/core/net"
19
+
20
+ # Colored Petri net extensions
21
+ require_relative "petri_flow/colored/color"
22
+ require_relative "petri_flow/colored/guard"
23
+ require_relative "petri_flow/colored/arc_expression"
24
+ require_relative "petri_flow/colored/colored_net"
25
+
26
+ # Matrix analysis
27
+ require_relative "petri_flow/matrix/crud_event_mapping"
28
+ require_relative "petri_flow/matrix/correlation"
29
+ require_relative "petri_flow/matrix/causation"
30
+ require_relative "petri_flow/matrix/lineage"
31
+ require_relative "petri_flow/matrix/reachability"
32
+ require_relative "petri_flow/matrix/analyzer"
33
+
34
+ # Visualization
35
+ require_relative "petri_flow/visualization/graphviz"
36
+ require_relative "petri_flow/visualization/mermaid"
37
+
38
+ # Formal verification
39
+ require_relative "petri_flow/verification/reachability_analyzer"
40
+ require_relative "petri_flow/verification/boundedness_checker"
41
+ require_relative "petri_flow/verification/liveness_checker"
42
+ require_relative "petri_flow/verification/invariant_checker"
43
+
44
+ # Simulation
45
+ require_relative "petri_flow/simulation/simulator"
46
+ require_relative "petri_flow/simulation/trace"
47
+
48
+ # Export functionality
49
+ require_relative "petri_flow/export"
50
+
51
+ # Workflow base class and registry (always available)
52
+ require_relative "petri_flow/registry"
53
+ require_relative "petri_flow/workflow"
54
+ require_relative "petri_flow/verification_runner"
55
+
56
+ # Generators for creating workflows from state machines
57
+ require_relative "petri_flow/generators/state_machine_adapter"
58
+ require_relative "petri_flow/generators/adapters/state_machines_adapter"
59
+ require_relative "petri_flow/generators/adapters/aasm_adapter"
60
+ require_relative "petri_flow/generators/workflow_generator"
61
+
62
+ # Load Rails integration if Rails is available
63
+ require_relative "petri_flow/railtie" if defined?(Rails::Railtie)
64
+
65
+ module PetriFlow
66
+ class Error < StandardError; end
67
+
68
+ class << self
69
+ # Rails configuration (set by Railtie)
70
+ attr_accessor :rails_config
71
+
72
+ # Create a new Petri net
73
+ def create_net(name: "PetriNet")
74
+ Core::Net.new(name: name)
75
+ end
76
+
77
+ # Create a new Colored Petri net
78
+ def create_colored_net(name: "ColoredPetriNet")
79
+ Colored::ColoredNet.new(name: name)
80
+ end
81
+
82
+ # Create a matrix analyzer
83
+ def create_analyzer
84
+ Matrix::Analyzer.new
85
+ end
86
+
87
+ # Quick visualization
88
+ def visualize(net, format: :dot)
89
+ case format
90
+ when :dot, :graphviz
91
+ Visualization::Graphviz.new(net).to_dot
92
+ when :mermaid
93
+ Visualization::Mermaid.new(net).to_mermaid
94
+ when :ascii
95
+ Visualization::Graphviz.new(net).to_ascii
96
+ else
97
+ raise Error, "Unknown visualization format: #{format}"
98
+ end
99
+ end
100
+
101
+ # Quick verification
102
+ #
103
+ # @param net [PetriFlow::Core::Net] The Petri net to verify
104
+ # @param initial_marking [PetriFlow::Core::Marking] Initial marking
105
+ # @param pt_abstraction [Boolean] Enable P/T abstraction (ignore guards)
106
+ # Use true for full state-space exploration of colored nets.
107
+ # Guards are treated as non-deterministic choice, which is sound
108
+ # for structural properties (boundedness, liveness, reachability).
109
+ def verify(net, initial_marking: nil, pt_abstraction: false)
110
+ initial_marking ||= net.current_marking
111
+
112
+ reachability = Verification::ReachabilityAnalyzer.new(net, initial_marking, pt_abstraction: pt_abstraction)
113
+ reachability.analyze
114
+
115
+ boundedness = Verification::BoundednessChecker.new(net, reachability)
116
+ liveness = Verification::LivenessChecker.new(net, reachability)
117
+
118
+ {
119
+ reachability: reachability.report,
120
+ boundedness: boundedness.report,
121
+ liveness: liveness.report
122
+ }
123
+ end
124
+
125
+ # Quick simulation
126
+ def simulate(net, steps: 100, strategy: :random)
127
+ simulator = Simulation::Simulator.new(net)
128
+ simulator.run(steps: steps, strategy: strategy)
129
+ end
130
+
131
+ # Quick export
132
+ def export(net, format:, **options)
133
+ Export.export(net, format: format, **options)
134
+ end
135
+
136
+ # Save net to file
137
+ def save(net, filename, format: nil, **options)
138
+ Export.save(net, filename, format: format, **options)
139
+ end
140
+
141
+ # Version info
142
+ def version
143
+ VERSION
144
+ end
145
+
146
+ # Gem info
147
+ def info
148
+ {
149
+ name: "PetriFlow",
150
+ version: VERSION,
151
+ description: "Petri Net and Matrix Analysis for Event Sourcing",
152
+ components: {
153
+ core: "Basic Petri nets with places, transitions, arcs",
154
+ colored: "Colored Petri nets with guards and arc expressions",
155
+ matrix: "Matrix analysis for CRUD-Event mapping, causation, lineage",
156
+ visualization: "GraphViz, Mermaid, and ASCII visualization",
157
+ verification: "Reachability, boundedness, liveness, invariants",
158
+ simulation: "Monte Carlo simulation and trace analysis",
159
+ export: "PNML, CPN Tools XML, JSON, and YAML export formats"
160
+ }
161
+ }
162
+ end
163
+ end
164
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: orfeas_petri_flow
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Michail Pantelelis
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activesupport
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '6.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '6.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: matrix
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.4'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.4'
40
+ - !ruby/object:Gem::Dependency
41
+ name: minitest
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '5.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: minitest-reporters
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.5'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.5'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rake
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '13.0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '13.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: simplecov
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.22'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.22'
96
+ description: A comprehensive gem for Petri net modeling, colored Petri nets, matrix
97
+ analysis, visualization, and formal verification for event sourcing and CRUD-to-Event
98
+ mapping analysis. Part of the ORFEAS (Object-Relational to Event-Sourcing Architecture)
99
+ framework.
100
+ email:
101
+ - mpantel@aegean.gr
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - CHANGELOG.md
107
+ - MIT-LICENSE
108
+ - README.md
109
+ - Rakefile
110
+ - lib/petri_flow.rb
111
+ - lib/petri_flow/colored/arc_expression.rb
112
+ - lib/petri_flow/colored/color.rb
113
+ - lib/petri_flow/colored/colored_net.rb
114
+ - lib/petri_flow/colored/guard.rb
115
+ - lib/petri_flow/core/arc.rb
116
+ - lib/petri_flow/core/marking.rb
117
+ - lib/petri_flow/core/net.rb
118
+ - lib/petri_flow/core/place.rb
119
+ - lib/petri_flow/core/token.rb
120
+ - lib/petri_flow/core/transition.rb
121
+ - lib/petri_flow/export.rb
122
+ - lib/petri_flow/export/cpn_tools_exporter.rb
123
+ - lib/petri_flow/export/json_exporter.rb
124
+ - lib/petri_flow/export/pnml_exporter.rb
125
+ - lib/petri_flow/export/yaml_exporter.rb
126
+ - lib/petri_flow/generators/adapters/aasm_adapter.rb
127
+ - lib/petri_flow/generators/adapters/state_machines_adapter.rb
128
+ - lib/petri_flow/generators/state_machine_adapter.rb
129
+ - lib/petri_flow/generators/workflow_generator.rb
130
+ - lib/petri_flow/matrix/analyzer.rb
131
+ - lib/petri_flow/matrix/causation.rb
132
+ - lib/petri_flow/matrix/correlation.rb
133
+ - lib/petri_flow/matrix/crud_event_mapping.rb
134
+ - lib/petri_flow/matrix/lineage.rb
135
+ - lib/petri_flow/matrix/reachability.rb
136
+ - lib/petri_flow/railtie.rb
137
+ - lib/petri_flow/registry.rb
138
+ - lib/petri_flow/simulation/simulator.rb
139
+ - lib/petri_flow/simulation/trace.rb
140
+ - lib/petri_flow/tasks/petri_flow.rake
141
+ - lib/petri_flow/verification/boundedness_checker.rb
142
+ - lib/petri_flow/verification/invariant_checker.rb
143
+ - lib/petri_flow/verification/liveness_checker.rb
144
+ - lib/petri_flow/verification/reachability_analyzer.rb
145
+ - lib/petri_flow/verification_runner.rb
146
+ - lib/petri_flow/version.rb
147
+ - lib/petri_flow/visualization/graphviz.rb
148
+ - lib/petri_flow/visualization/mermaid.rb
149
+ - lib/petri_flow/workflow.rb
150
+ homepage: https://github.com/mpantel/lyra-engine/gems/petri-flow
151
+ licenses:
152
+ - MIT
153
+ metadata:
154
+ homepage_uri: https://github.com/mpantel/lyra-engine/gems/petri-flow
155
+ source_code_uri: https://github.com/mpantel/lyra-engine/gems/petri-flow/tree/main/gems/petri_flow
156
+ changelog_uri: https://github.com/mpantel/lyra-engine/gems/petri-flow/blob/main/gems/petri_flow/CHANGELOG.md
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubygems_version: 4.0.3
172
+ specification_version: 4
173
+ summary: Petri Net and Matrix Analysis for ORFEAS Framework
174
+ test_files: []