y_petri 2.2.4 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
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