y_petri 2.2.4 → 2.3.2

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +675 -0
  3. data/README.md +6 -3
  4. data/Rakefile +1 -1
  5. data/lib/y_petri/agent/{petri_net_related.rb → petri_net_aspect.rb} +34 -10
  6. data/lib/y_petri/agent/{simulation_related.rb → simulation_aspect.rb} +49 -34
  7. data/lib/y_petri/agent.rb +5 -5
  8. data/lib/y_petri/core/guarded.rb +24 -0
  9. data/lib/y_petri/core/timed/euler.rb +4 -8
  10. data/lib/y_petri/core/timed/gillespie.rb +11 -17
  11. data/lib/y_petri/core/timed/methods.rb +23 -0
  12. data/lib/y_petri/core/timed/pseudo_euler.rb +10 -13
  13. data/lib/y_petri/core/timed/quasi_euler.rb +9 -8
  14. data/lib/y_petri/core/timed/runge_kutta.rb +10 -18
  15. data/lib/y_petri/core/timed.rb +6 -14
  16. data/lib/y_petri/core/timeless/methods.rb +15 -0
  17. data/lib/y_petri/core/timeless/pseudo_euler.rb +4 -8
  18. data/lib/y_petri/core/timeless.rb +9 -4
  19. data/lib/y_petri/core.rb +44 -42
  20. data/lib/y_petri/net/data_set.rb +246 -142
  21. data/lib/y_petri/net/node_access.rb +282 -0
  22. data/lib/y_petri/net/own_state.rb +14 -4
  23. data/lib/y_petri/net/state/feature/assignment.rb +123 -0
  24. data/lib/y_petri/net/state/feature/delta.rb +55 -35
  25. data/lib/y_petri/net/state/feature/firing.rb +68 -25
  26. data/lib/y_petri/net/state/feature/flux.rb +9 -2
  27. data/lib/y_petri/net/state/feature/gradient.rb +36 -19
  28. data/lib/y_petri/net/state/feature/marking.rb +10 -5
  29. data/lib/y_petri/net/state/feature.rb +105 -11
  30. data/lib/y_petri/net/state/features/record.rb +144 -99
  31. data/lib/y_petri/net/state/features.rb +327 -200
  32. data/lib/y_petri/net/state.rb +48 -82
  33. data/lib/y_petri/net/visualization.rb +1 -1
  34. data/lib/y_petri/net.rb +62 -47
  35. data/lib/y_petri/place/arcs.rb +44 -0
  36. data/lib/y_petri/place/features.rb +115 -0
  37. data/lib/y_petri/place.rb +62 -29
  38. data/lib/y_petri/simulation/dependency.rb +31 -67
  39. data/lib/y_petri/simulation/feature_set.rb +1 -1
  40. data/lib/y_petri/simulation/initial_marking/access.rb +42 -26
  41. data/lib/y_petri/simulation/marking_clamps/access.rb +22 -17
  42. data/lib/y_petri/simulation/marking_clamps.rb +0 -2
  43. data/lib/y_petri/simulation/marking_vector/access.rb +102 -40
  44. data/lib/y_petri/simulation/marking_vector.rb +35 -37
  45. data/lib/y_petri/simulation/matrix.rb +1 -1
  46. data/lib/y_petri/simulation/node_representation.rb +25 -0
  47. data/lib/y_petri/simulation/nodes/access.rb +78 -0
  48. data/lib/y_petri/simulation/{elements.rb → nodes.rb} +14 -13
  49. data/lib/y_petri/simulation/place_mapping.rb +2 -2
  50. data/lib/y_petri/simulation/place_representation.rb +8 -7
  51. data/lib/y_petri/simulation/places/access.rb +89 -70
  52. data/lib/y_petri/simulation/places/free.rb +1 -1
  53. data/lib/y_petri/simulation/places/types.rb +20 -22
  54. data/lib/y_petri/simulation/places.rb +23 -18
  55. data/lib/y_petri/simulation/recorder.rb +23 -18
  56. data/lib/y_petri/simulation/timed/recorder.rb +19 -11
  57. data/lib/y_petri/simulation/timed.rb +93 -29
  58. data/lib/y_petri/simulation/timeless/recorder.rb +11 -6
  59. data/lib/y_petri/simulation/timeless.rb +13 -3
  60. data/lib/y_petri/simulation/transition_representation/A.rb +24 -4
  61. data/lib/y_petri/simulation/transition_representation/S.rb +11 -1
  62. data/lib/y_petri/simulation/transition_representation/T.rb +1 -1
  63. data/lib/y_petri/simulation/transition_representation/Ts.rb +1 -1
  64. data/lib/y_petri/simulation/transition_representation/a.rb +1 -1
  65. data/lib/y_petri/simulation/transition_representation/s.rb +12 -1
  66. data/lib/y_petri/simulation/transition_representation/t.rb +1 -1
  67. data/lib/y_petri/simulation/transition_representation/tS.rb +1 -1
  68. data/lib/y_petri/simulation/transition_representation/ts.rb +1 -1
  69. data/lib/y_petri/simulation/transition_representation/types.rb +1 -1
  70. data/lib/y_petri/simulation/transition_representation.rb +4 -11
  71. data/lib/y_petri/simulation/transitions/A.rb +17 -2
  72. data/lib/y_petri/simulation/transitions/S.rb +1 -1
  73. data/lib/y_petri/simulation/transitions/T.rb +1 -1
  74. data/lib/y_petri/simulation/transitions/Ts.rb +6 -5
  75. data/lib/y_petri/simulation/transitions/a.rb +1 -1
  76. data/lib/y_petri/simulation/transitions/access.rb +195 -168
  77. data/lib/y_petri/simulation/transitions/s.rb +1 -1
  78. data/lib/y_petri/simulation/transitions/t.rb +1 -1
  79. data/lib/y_petri/simulation/transitions/tS.rb +1 -1
  80. data/lib/y_petri/simulation/transitions/ts.rb +1 -1
  81. data/lib/y_petri/simulation/transitions/types.rb +1 -1
  82. data/lib/y_petri/simulation/transitions.rb +5 -7
  83. data/lib/y_petri/simulation.rb +84 -90
  84. data/lib/y_petri/transition/A.rb +8 -2
  85. data/lib/y_petri/transition/T.rb +25 -2
  86. data/lib/y_petri/transition/arcs.rb +19 -3
  87. data/lib/y_petri/transition/construction_convenience.rb +11 -10
  88. data/lib/y_petri/transition/t.rb +14 -1
  89. data/lib/y_petri/transition/types.rb +6 -1
  90. data/lib/y_petri/transition.rb +9 -12
  91. data/lib/y_petri/version.rb +1 -1
  92. data/lib/y_petri/world/dependency.rb +3 -3
  93. data/lib/y_petri/world/{petri_net_related.rb → petri_net_aspect.rb} +4 -4
  94. data/lib/y_petri/world/simulation_aspect.rb +352 -0
  95. data/lib/y_petri/world.rb +4 -4
  96. data/lib/y_petri.rb +1 -1
  97. data/test/agent_test.rb +2 -1
  98. data/test/examples/demonstrator.rb +4 -1
  99. data/test/examples/demonstrator_2.rb +5 -0
  100. data/test/examples/demonstrator_4.rb +6 -5
  101. data/test/examples/example_2.rb +2 -0
  102. data/test/examples/manual_examples.rb +4 -4
  103. data/test/net_test.rb +457 -54
  104. data/test/place_test.rb +11 -7
  105. data/test/simulation_test.rb +358 -331
  106. data/test/transition_test.rb +11 -10
  107. data/test/world_test.rb +2 -0
  108. data/test/y_petri_test.rb +2 -1
  109. data/y_petri.gemspec +24 -18
  110. metadata +71 -17
  111. data/LICENSE +0 -22
  112. data/lib/y_petri/net/element_access.rb +0 -239
  113. data/lib/y_petri/simulation/element_representation.rb +0 -20
  114. data/lib/y_petri/simulation/elements/access.rb +0 -57
  115. data/lib/y_petri/transition/type.rb +0 -103
  116. data/lib/y_petri/transition/type_information.rb +0 -103
  117. data/lib/y_petri/world/simulation_related.rb +0 -176
@@ -2,9 +2,9 @@
2
2
 
3
3
  require_relative 'simulation/matrix'
4
4
  require_relative 'simulation/dependency'
5
- require_relative 'simulation/element_representation'
6
- require_relative 'simulation/elements'
7
- require_relative 'simulation/elements/access'
5
+ require_relative 'simulation/node_representation'
6
+ require_relative 'simulation/nodes'
7
+ require_relative 'simulation/nodes/access'
8
8
  require_relative 'simulation/place_representation'
9
9
  require_relative 'simulation/places'
10
10
  require_relative 'simulation/places/access'
@@ -22,22 +22,22 @@ require_relative 'simulation/recorder'
22
22
  require_relative 'simulation/timeless'
23
23
  require_relative 'simulation/timed'
24
24
 
25
- # Represents a Petri net simulation, concerning are the simulation method and
26
- # settings, initial values, marking clamps, guards and similar. Its concerns are
27
- # are separated from those of the Petri net domain model (existence, naming,
28
- # connectivity, functions...). Clamps, guards, initial values etc. <b>do not
29
- # belong</b> to the model, although for convenience, places may carry default
30
- # initial marking, guards, and clamps for use in the token game. Simulation
31
- # instance can also use these if none other are specified.
25
+ # Represents a Petri net simulation. Its concerns include the simulation method,
26
+ # simulation settings, initial values, marking clamps used during the simulation,
27
+ # guards etc. Its concerns do not include the Petri net domain model as such
28
+ # (places, transitions, arcs, transition functions...)
32
29
  #
33
- # A simulation distinguishes between free and clamped places. For free places,
34
- # initial marking has to be specified. For clamped places, marking clamps have
35
- # to be specified. Both come as hashes:
30
+ # In a simulation, some places are designated as free (ie. their marking is free
31
+ # to be changed by firing of the net's transitions), while others are clamped
32
+ # (their marking is clamped by the simulation rather than changed by the
33
+ # transitions). For free places, initial marking has to be specified. For
34
+ # clamped places, marking clamps have to be specified. (For convenience, places
35
+ # may carry their own initial marking.)
36
36
  #
37
37
  class YPetri::Simulation
38
38
  ★ Places::Access # ★ means include
39
39
  ★ Transitions::Access
40
- Elements::Access
40
+ Nodes::Access
41
41
  ★ InitialMarking::Access
42
42
  ★ MarkingClamps::Access
43
43
  ★ MarkingVector::Access
@@ -52,7 +52,7 @@ class YPetri::Simulation
52
52
  end
53
53
  end
54
54
 
55
- # Parametrized subclasses:
55
+ # Parametrized subclasses.
56
56
  attr_reader :core,
57
57
  :recorder,
58
58
  :guarded,
@@ -64,7 +64,7 @@ class YPetri::Simulation
64
64
  :Ts_gradient_closure,
65
65
  :tS_firing_closure,
66
66
  :TS_rate_closure,
67
- :A_assignment_closure,
67
+ :A_direct_assignment_closure,
68
68
  :increment_marking_vector_closure
69
69
 
70
70
  alias guarded? guarded
@@ -72,12 +72,12 @@ class YPetri::Simulation
72
72
  delegate :net, to: "self.class"
73
73
 
74
74
  delegate :simulation_method,
75
- :guarded?,
76
75
  :step!,
77
76
  :firing_vector_tS,
78
77
  to: :core
79
78
 
80
79
  delegate :recording,
80
+ :back!,
81
81
  to: :recorder
82
82
 
83
83
  alias r recording
@@ -99,7 +99,7 @@ class YPetri::Simulation
99
99
 
100
100
  # Firing of the indicated tS transitions (as hash with transition names as
101
101
  # keys).
102
- #
102
+ #
103
103
  def t_firing ids=nil
104
104
  tS_transitions( ids ).names( true ) >> firing( ids )
105
105
  end
@@ -113,69 +113,63 @@ class YPetri::Simulation
113
113
  t_firing( ids ).pretty_print_numeric_values( gap: gap, precision: precision )
114
114
  end
115
115
 
116
- # The basic simulation parameter is :net – +YPetri::Net+ instance which to
117
- # simulate. Net implies the collection of places and transitions. Other
118
- # required attributes are +:marking_clamps+ and +:initial_marking+
116
+ # The basic simulation parameter is +:net+a collection of places and
117
+ # transitions (a <tt>YPetri::Net</tt> instance) that is simulated. Other
118
+ # required arguments are +:marking_clamps+ and +:initial_marking+
119
119
  # (or +:marking -- if no +:initial_marking+ is supplied, +:marking+ will be
120
- # used in its stead). There is a possibility to extract the initial marking
121
- # from the net elements directly, controlled by the optional argument
122
- # +:use_default_marking+, _true_ by default. It means that even if the caller
123
- # does not supply required +:initial_marking+ values, the constructor will
124
- # extract them from the places, so long as these have their initial markings
125
- # set. Setting +:use_default_marking+ to _false_ will cause an error unless
126
- # +:initial_marking+ and +:place_clamps+ are supplied explicitly.
120
+ # used in its stead). Even when the caller did not provide all the
121
+ # +:initial_marking+, there is an option of extracting them from the place
122
+ # instances themselves. This option, controlled by the named argument
123
+ # +use_default_marking+, is normally set to _true_, to turn it off, change
124
+ # it to _false_.
127
125
  #
128
- # Simulation method is controlled by the :method argument, guarding is
129
- # switched on and off by the :guarded argument (_true_ / _false_). Simulations
130
- # of timed nets are timed. A timed simulation constructor may have +:time+
131
- # (alias +:time_range+), +:step+, controlling the size of the simulation step,
132
- # and +:sampling+, controlling the sampling period. At least one of these named
133
- # arguments has to be set for timed simulations.
126
+ # Simulation method is set by +:method+ named argument, guarding is controlled
127
+ # by +:guarded+ named argument (_true_/_false_). Simulations of timed nets are
128
+ # also timed. For a timed simulation, the constructor permits named arguments
129
+ # +:time+ (alias +:time_range+), +:step+ (simulation step size), and
130
+ # +:sampling+ (sampling period), and requires that at least one of these named
131
+ # arguments be supplied.
134
132
  #
135
- def initialize **settings
136
- @guarded = settings[:guarded] # guarding on / off
137
- m_clamps = settings[:marking_clamps] || {}
138
- m = settings[:marking]
139
- init_m = settings[:initial_marking] || {}
140
- use_default_marking = if settings.has? :use_default_marking then
141
- settings[ :use_default_marking ]
142
- else true end
143
- # Time-independent simulation settings received, constructing param. classes
144
- param_class!( { Place: PlaceRepresentation,
133
+ def initialize use_default_marking: true,
134
+ guarded: false,
135
+ marking_clamps: {},
136
+ initial_marking: {},
137
+ marking: nil,
138
+ **settings
139
+ param_class!( { Place: PlaceRepresentation, # parametrized subclasses
145
140
  Places: Places,
146
141
  Transition: TransitionRepresentation,
147
142
  Transitions: Transitions,
143
+ Nodes: Nodes,
148
144
  PlaceMapping: PlaceMapping,
149
145
  InitialMarking: InitialMarking,
150
146
  MarkingClamps: MarkingClamps,
151
147
  MarkingVector: MarkingVector },
152
148
  with: { simulation: self } )
153
- # Place and transition representation classes are their own namespaces.
154
- Place().namespace!
155
- Transition().namespace!
156
- # Set up the places collection.
149
+ [ Place(), Transition() ].each &:namespace! # each serves as its namespace
150
+ @guarded = guarded # TODO: Not operable as of now.
157
151
  @places = Places().load( net.places )
158
- # Clamped places' mapping to the clamp values.
159
- @marking_clamps = MarkingClamps().load( m_clamps )
160
- # Free places' mapping to the initial marking values.
161
- @initial_marking = InitialMarking()
162
- .load( if m then # use :marking as :initial_marking when possible
163
- init_m_from_init_m = PlaceMapping().load( init_m )
164
- init_m_from_marking = PlaceMapping().load( m )
165
- init_m_from_marking.merge init_m_from_init_m
166
- else init_m end )
167
- # Set up the place and transition collections.
168
- @places.complete_initial_marking( use_default_marking: use_default_marking )
169
- # Correspondence matrix free --> all
152
+ @marking_clamps = MarkingClamps().load( marking_clamps )
153
+ @initial_marking = if marking then
154
+ m = PlaceMapping().load( marking )
155
+ im = PlaceMapping().load( initial_marking )
156
+ InitialMarking().load( m.merge im )
157
+ else
158
+ InitialMarking().load( initial_marking )
159
+ end
160
+ # Fill in the missing initial marking from the places' default marking.
161
+ @places.send( :complete_initial_marking,
162
+ use_default_marking: use_default_marking )
163
+ # Correspondence matrix free places --> all places
170
164
  @f2a = free_places.correspondence_matrix( places )
171
- # Correspondence matrix clamped --> all
165
+ # Correspondence matrix clamped places --> all places
172
166
  @c2a = clamped_places.correspondence_matrix( places )
173
167
  # Conditionally extend self depending on net's timedness.
174
- anything_time = settings[:time] || settings[:step] || settings[:sampling]
175
- extend( anything_time ? Timed : Timeless )
168
+ time_mentioned = settings[:time] || settings[:step] || settings[:sampling]
169
+ if time_mentioned then extend Timed else extend Timeless end
176
170
  # Initialize the marking vector.
177
171
  @m_vector = MarkingVector().zero
178
- # Set up the transitions collection.
172
+ # Set up the collection of transitions.
179
173
  @transitions = Transitions().load( net.transitions )
180
174
  # Set up stoichiometry matrices relative to free places.
181
175
  @tS_stoichiometry_matrix = transitions.tS.stoichiometry_matrix
@@ -183,46 +177,48 @@ class YPetri::Simulation
183
177
  # Set up stoichiometry matrices relative to all places.
184
178
  @tS_SM = transitions.tS.SM
185
179
  @TS_SM = transitions.TS.SM
186
- # Call timedness-dependent initialization.
180
+ # Call timedness-dependent #init subroutine.
187
181
  init **settings
188
- # Make timeless closures.
182
+ # Make time-independent closures.
189
183
  @ts_delta_closure = transitions.ts.delta_closure
190
184
  @tS_firing_closure = transitions.tS.firing_closure
191
- @A_assignment_closure = transitions.A.assignment_closure
185
+ @A_direct_assignment_closure = transitions.A.direct_assignment_closure
192
186
  @increment_marking_vector_closure = m_vector.increment_closure
193
- # Make timed closures.
187
+ # Make timed-only closures.
194
188
  if timed? then
195
189
  @Ts_gradient_closure = transitions.Ts.gradient_closure
196
190
  @TS_rate_closure = transitions.TS.rate_closure
197
191
  end
198
192
  # Reset.
199
- if m then reset! marking: m else reset! end
193
+ if marking then reset! marking: marking else reset! end
200
194
  end
201
195
 
202
196
  # Simulation settings.
203
197
  #
204
198
  def settings all=false
205
199
  return { method: simulation_method, guarded: guarded? } unless all == true
206
- settings( false )
207
- .update( net: net,
208
- marking_clamps: marking_clamps.keys_to_source_places,
209
- initial_marking: initial_marking.keys_to_source_places )
200
+ { net: net,
201
+ marking_clamps: marking_clamps.keys_to_source_places,
202
+ initial_marking: initial_markings.keys_to_source_places
203
+ }.update( settings )
210
204
  end
211
205
 
212
206
  # Returns a new simulation instance. Unless modified by arguments, the state
213
207
  # of the new instance is the same as the creator's. Arguments can partially or
214
208
  # wholly modify the attributes of the duplicate.
215
209
  #
216
- def dup( marking: marking, recording: recording, **nn )
217
- self.class.new( nn.reverse_merge! settings( true ) ).tap do |dup|
218
- dup.recording.reset! recording: recording
219
- dup.m_vector.reset! case marking
220
- when Hash then
221
- m_vector.to_hash_with_source_places
222
- .update( PlaceMapping().load( marking ) )
223
- .to_marking_vector
224
- when Matrix, Array then marking
225
- else marking.each.to_a end
210
+ def dup( marking: marking, recording: recording, **named_args )
211
+ named_args.reverse_merge! settings( true )
212
+ self.class.new( named_args ).tap do |duplicate|
213
+ duplicate.recorder.reset! recording: recording
214
+ duplicate.m_vector.reset! case marking
215
+ when Hash then
216
+ m_vector.to_hash_with_source_places
217
+ .update( PlaceMapping().load( marking )
218
+ .to_marking_vector
219
+ .to_hash_with_source_places )
220
+ when Matrix, Array then marking
221
+ else marking.each.to_a end
226
222
  end
227
223
  end
228
224
 
@@ -240,12 +236,10 @@ class YPetri::Simulation
240
236
 
241
237
  # Resets the simulation.
242
238
  #
243
- def reset! **nn
244
- m = nn[:marking]
239
+ def reset! marking: nil, **named_args
245
240
  tap do
246
- if m then m_vector.reset! m else m_vector.reset! end
247
- recorder.reset!
248
- recorder.alert
241
+ marking ? m_vector.reset!( marking ) : m_vector.reset!
242
+ recorder.reset!.alert!
249
243
  end
250
244
  end
251
245
 
@@ -258,7 +252,7 @@ class YPetri::Simulation
258
252
 
259
253
  # Extract a prescribed set of features.
260
254
  #
261
- def get_features arg
262
- net.State.features( arg ).extract_from( self )
255
+ def get_features *args
256
+ net.State.Features( *args ).extract_from( self )
263
257
  end
264
258
  end # class YPetri::Simulation
@@ -1,4 +1,4 @@
1
- # -*- coding: utf-8 -*-
1
+ # encoding: utf-8
2
2
 
3
3
  # Mixin for the transitions with assignment action.
4
4
  #
@@ -24,7 +24,7 @@ module YPetri::Transition::Type_A
24
24
  msg = "Wrong output arity of the action closure of #{self}"
25
25
  fail TypeError, msg if act.size != codomain.size
26
26
  codomain.each_with_index { |p, i|
27
- note "assigning action element no. #{i} to #{p}"
27
+ note "assigning action node no. #{i} to #{p}"
28
28
  p.marking = note "marking to assign", is: act.fetch( i )
29
29
  }
30
30
  end
@@ -36,4 +36,10 @@ module YPetri::Transition::Type_A
36
36
  def enabled?
37
37
  true
38
38
  end
39
+
40
+ # Transition's assignment action under current simulation.
41
+ #
42
+ def a simulation=world.simulation
43
+ simulation.net.State.Feature.Assignment( self ) % simulation
44
+ end
39
45
  end # class YPetri::Transition::Type_A
@@ -1,4 +1,4 @@
1
- # -*- coding: utf-8 -*-
1
+ # encoding: utf-8
2
2
 
3
3
  # Mixin for timed Petri net transitions.
4
4
  #
@@ -30,7 +30,7 @@ module YPetri::Transition::Type_T
30
30
  msg = "Wrong output arity of the action closure of #{self}!"
31
31
  fail TypeError, msg if act.size != codomain.size
32
32
  codomain.each_with_index do |p, i|
33
- note "adding action element no. #{i} to #{p}"
33
+ note "adding action node no. #{i} to #{p}"
34
34
  p.add note( "marking change", is: act.fetch( i ) )
35
35
  end
36
36
  end
@@ -47,4 +47,27 @@ module YPetri::Transition::Type_T
47
47
  rescue YPetri::GuardError; false end
48
48
  end
49
49
  end
50
+
51
+ # Transition's firing under current simulation.
52
+ #
53
+ def fir simulation=world.simulation, **nn
54
+ nn.must_have :delta_time, syn!: :Δt
55
+ Δt = nn.delete( :delta_time ) || simulation.step
56
+ simulation.net.State.Feature.Firing( self ) % [ simulation, Δt: Δt ]
57
+ end
58
+
59
+ # Transition's flux under current simulation.
60
+ #
61
+ def f simulation=world.simulation
62
+ simulation.net.State.Feature.Flux( self ) % simulation
63
+ end
64
+
65
+ # Prints the transition's action under current simulation.
66
+ #
67
+ def pa simulation=world.simulation, **nn
68
+ nn.must_have :delta_time, syn!: :Δt
69
+ Δt = nn.delete( :delta_time ) || simulation.step
70
+ ff = simulation.net.State.Features.Delta( codomain, transitions: self )
71
+ ( ff >> ff % simulation ).pretty_print_numeric_values( **nn )
72
+ end
50
73
  end # class YPetri::Transition::Type_T
@@ -15,11 +15,27 @@ module YPetri::Transition::Arcs
15
15
 
16
16
  # Union of action arcs and test arcs.
17
17
  #
18
- def arcs; domain | codomain end
18
+ def arcs
19
+ domain | codomain
20
+ end
19
21
 
20
- # Returns names of the (places connected to) the transition's arcs.
22
+ # Names of the places connected to the transition. The optional argument
23
+ # controls what is returned for unnamed instances, and works just like in
24
+ # <tt>Array#names</tt> method from <tt>y_support/name_magic</tt>:
25
+ # The default value (_nil_) returns _nil_, _true_ returns the instance itself,
26
+ # and _false_ drops the unnamed instances from the list altogether.
21
27
  #
22
- def aa; arcs.map { |p| p.name || p.object_id } end
28
+ def aa arg=nil
29
+ arcs.names arg
30
+ end
31
+
32
+ # Arc (a place connected to this transition) identifier.
33
+ #
34
+ def arc id
35
+ place = place( id )
36
+ arcs.find { |p| p == place } or
37
+ fail TypeError, "No place #{id} connected to #{self}!"
38
+ end
23
39
 
24
40
  # Marking of the domain places.
25
41
  #
@@ -1,9 +1,9 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  # Given the four transition types (TS, Ts, tS, ts), transition construction
4
- # is not an easy task. Actually, having convenient constructor syntax is an
5
- # important part of the functionality of the Transition class. Construction
6
- # related functionality is thus gathered together in this mixin.
4
+ # is not an easy task. Having convenient constructor syntax is an important
5
+ # part of the functionality of the Transition class. Construction related
6
+ # functionality is thus gathered together in this mixin.
7
7
  #
8
8
  module YPetri::Transition::ConstructionConvenience
9
9
  private
@@ -116,8 +116,8 @@ module YPetri::Transition::ConstructionConvenience
116
116
  end
117
117
  else # not a Proc, must guess user's intent
118
118
  λ = if stoichiometric? then # standard mass action
119
- msg = "With numeric rate, domain must not be given!"
120
- fail TypeError, msg if nn.has? :domain
119
+ fail TypeError, "With numeric rate, domain must not be given!" if
120
+ nn.has? :domain
121
121
  __standard_mass_action__( λ )
122
122
  else # constant closure
123
123
  msg = "With numeric rate and no stoichio., codomain size must be 1!"
@@ -126,8 +126,8 @@ module YPetri::Transition::ConstructionConvenience
126
126
  if dom == :missing then
127
127
  dom = [] # Missing domain is natural here
128
128
  else # but should it was supplied explicitly, it must be empty.
129
- msg = "Rate is a number, but domain is non-empty!"
130
- fail TypeError, msg unless domain.empty? if nn.has? :domain
129
+ fail TypeError, "Rate is a number, but domain non-empty!" unless
130
+ domain.empty? if nn.has? :domain
131
131
  end
132
132
  end
133
133
  end
@@ -191,8 +191,9 @@ module YPetri::Transition::ConstructionConvenience
191
191
  # plain factors, assuming that if these places were not involved
192
192
  # in the transition at all, the user would not be mentioning them.
193
193
  case coeff
194
- when 0, -1 then marking * acc
195
- else marking ** -coeff end
194
+ when 0 then marking * acc # coefficient 0 indicates plain factor
195
+ when -1 then marking * acc # for speed, 1 gets special treatment
196
+ else marking ** -coeff * acc end
196
197
  end
197
198
  end
198
199
  end
@@ -214,7 +215,7 @@ module YPetri::Transition::ConstructionConvenience
214
215
  else
215
216
  # array of stoichiometry coefficients
216
217
  msg = "With array-type stoichiometry, :codomain must be given!"
217
- fail ArgumentError unless oo.has? :codomain
218
+ fail ArgumentError, msg unless oo.has? :codomain
218
219
  [ oo[:codomain], Array( oo[:stoichiometry] ) ]
219
220
  end
220
221
  # enforce that stoichiometry is a collection of numbers
@@ -29,7 +29,7 @@ module YPetri::Transition::Type_t
29
29
  msg = "Wrong output arity of the action closure of #{self}!"
30
30
  fail TypeError, msg if act.size != codomain.size
31
31
  codomain.each_with_index do |p, i|
32
- note "adding action element no. #{i} to #{p}"
32
+ note "adding action node no. #{i} to #{p}"
33
33
  p.add note( "marking change", is: act.fetch( i ) )
34
34
  end
35
35
  end
@@ -45,4 +45,17 @@ module YPetri::Transition::Type_t
45
45
  rescue YPetri::GuardError; false end
46
46
  end
47
47
  end
48
+
49
+ # Transition's firing under current simulation.
50
+ #
51
+ def fir simulation=world.simulation
52
+ simulation.net.State.Feature.Firing( self ) % simulation
53
+ end
54
+
55
+ # Prints the transition's action under current simulation.
56
+ #
57
+ def pa simulation=world.simulation, **nn
58
+ ff = simulation.net.State.Features.Delta( codomain, transitions: self )
59
+ ( ff >> ff % simulation ).pretty_print_numeric_values **nn
60
+ end
48
61
  end # class YPetri::Transition::Type_t
@@ -41,9 +41,13 @@ module YPetri::Transition::Types
41
41
  end
42
42
  alias s? nonstoichiometric?
43
43
 
44
- # Does the transition's action depend on delta time?
44
+ # Does the transition's action depend on delta time? (Note that although A
45
+ # transitions are technically timeless, for pragmatic reasons, they are
46
+ # excluded from T/t classification, because they are generally handled
47
+ # differently in Petri net execution.)
45
48
  #
46
49
  def timed?
50
+ return nil if A?
47
51
  @timed
48
52
  end
49
53
  alias T? timed?
@@ -51,6 +55,7 @@ module YPetri::Transition::Types
51
55
  # Is the transition timeless? (Opposite of #timed?)
52
56
  #
53
57
  def timeless?
58
+ return nil if A?
54
59
  not timed?
55
60
  end
56
61
  alias t? timeless?
@@ -53,6 +53,7 @@ require_relative 'transition/usable_without_world'
53
53
  # 2. *Stoichiometricity*: _stoichiometric_ (*S*) / _nonstoichiometric_ (*s*)
54
54
  #
55
55
  # ==== Timedness
56
+
56
57
  #
57
58
  # * Timed transitions have _rate_ _closure_, whose result is to be multiplied
58
59
  # by +Δtime+.
@@ -168,7 +169,7 @@ class YPetri::Transition
168
169
  else Type_t end )
169
170
  inform_upstream_places # that they have been connected
170
171
  inform_downstream_places # that they have been connected
171
- uncock # initialize in the uncocked state
172
+ uncock # initialize in uncocked state
172
173
  end
173
174
 
174
175
  # Domain, or 'upstream arcs', is a collection of places, whose marking
@@ -267,18 +268,14 @@ class YPetri::Transition
267
268
  # return self
268
269
  # end
269
270
 
270
- # Inspect string for a transition.
271
- #
272
- def inspect
273
- to_s
274
- end
271
+ # Let's just leave this to NameMagic
275
272
 
276
- # Conversion to a string.
277
- #
278
- def to_s
279
- "#<Transition: %s>" %
280
- "#{'%s ' % name if name}(#{type})#{' id:%s' % object_id unless name}"
281
- end
273
+ # # Conversion to a string.
274
+ # #
275
+ # def to_s
276
+ # "#<Transition: %s>" %
277
+ # "#{'%s ' % name if name}(#{type})#{' id:%s' % object_id unless name}"
278
+ # end
282
279
 
283
280
  def place id
284
281
  super rescue Place().instance( id )
@@ -1,4 +1,4 @@
1
1
  module YPetri
2
- VERSION = "2.2.4"
2
+ VERSION = "2.3.2"
3
3
  DEBUG = false
4
4
  end
@@ -19,16 +19,16 @@ class YPetri::World
19
19
  world.transition( id )
20
20
  end
21
21
 
22
- # Element instance identification.
22
+ # Node instance identification.
23
23
  #
24
- def element id
24
+ def node id
25
25
  begin
26
26
  place( id )
27
27
  rescue NameError, TypeError
28
28
  begin
29
29
  transition( id )
30
30
  rescue NameError, TypeError => err
31
- raise TypeError, "Unrecognized place or transition: #{element} (#{err})"
31
+ raise TypeError, "Unrecognized node: #{id} (#{err})"
32
32
  end
33
33
  end
34
34
  end
@@ -1,9 +1,9 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Workspace instance methods related to Petri net itsef (places, transitions,
4
- # net instances).
3
+ # Workspace instance methods related to the Petri net aspect of YPetri
4
+ # (places, transitions, net instances).
5
5
  #
6
- module YPetri::World::PetriNetRelated
6
+ module YPetri::World::PetriNetAspect
7
7
  # Instance initialization.
8
8
  #
9
9
  def initialize
@@ -58,4 +58,4 @@ module YPetri::World::PetriNetRelated
58
58
  # Hook new transitions to add themselves magically to the :Top net.
59
59
  Transition().new_instance_hook { |new_inst| net( :Top ) << new_inst }
60
60
  end
61
- end # module YPetri::World::PetriNetRelated
61
+ end # module YPetri::World::PetriNetAspect