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
@@ -1,25 +1,32 @@
1
- #encoding: utf-8
2
-
3
- require_relative 'places/types'
4
- require_relative 'places/free'
5
- require_relative 'places/clamped'
1
+ # encoding: utf-8
6
2
 
7
3
  # Place collection for YPetri::Simulation.
8
4
  #
9
- class YPetri::Simulation::Places
5
+ class YPetri::Simulation::Places < YPetri::Simulation::Nodes
6
+
7
+ require_relative 'places/types'
8
+ require_relative 'places/free'
9
+ require_relative 'places/clamped'
10
+
10
11
  ★ Types
11
12
 
12
13
  # Pushes a place to the collection.
13
14
  #
14
15
  def push place
15
- p = begin
16
- net.place( place )
17
- rescue NameError, TypeError
16
+ p = begin; net.place( place ); rescue NameError, TypeError
18
17
  return super place( place )
19
18
  end
20
19
  super p.name ? Place().new( p, name: p.name ) : Place().new( p )
21
20
  end
22
21
 
22
+ # Marking of the place collection in the current simulation.
23
+ #
24
+ def marking
25
+ simulation.M self
26
+ end
27
+
28
+ private
29
+
23
30
  # Ensures that all the places that are not clamped have their initial marking
24
31
  # set. Optional argument :use_default_marking is set to _true_ by default, in
25
32
  # which case own default marking of the source places is used if it was not
@@ -27,15 +34,13 @@ class YPetri::Simulation::Places
27
34
  # of places with missing initial marking simply raises errors.
28
35
  #
29
36
  def complete_initial_marking( use_default_marking: true )
30
- missing = reject { |pl| ( free + clamped ).include? pl }
31
- unless use_default_marking
32
- fail TypeError, "All places must have default marking or clamp!" unless
33
- missing.empty?
34
- end
35
- missing.each { |pl|
36
- dflt = pl.source.default_marking
37
- fail TypeError, "Source's default marking is missing (nil)!" if dflt.nil?
38
- simulation.send :set_initial_marking, { of: pl, to: dflt }
37
+ offenders = reject { |place| ( free + clamped ).include? place }
38
+ fail TypeError, "All places must have default marking or clamp!" unless
39
+ use_default_marking unless offenders.empty?
40
+ offenders.each { |place|
41
+ dm = place.source.default_marking
42
+ fail TypeError, "#{place.source} has no default marking!" if dm.nil?
43
+ simulation.send( :set_initial_marking, place, to: dm )
39
44
  }
40
45
  end
41
46
  end # class YPetri::Simulation::Places
@@ -1,8 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  # A machine that receives alerts during simulation and records a recording
4
- # according to its implementation. Alerts are received via +#alert+ method.
5
- # The recording bein recorded is stored in @recording instance variable.
4
+ # according to its implementation. Alerts are received via +#alert!+ method.
5
+ # The recording being recorded is stored in +@recording+ instance variable.
6
6
  # This can be reset by +#reset!+ method, which also accepts arguments to
7
7
  # change the recorder settings and/or insert another recording.
8
8
  #
@@ -14,45 +14,50 @@ class YPetri::Simulation::Recorder
14
14
  attr_reader :features
15
15
 
16
16
  def recording
17
- @recording.tap { |ds|
18
- ds.instance_variable_set :@settings, simulation.settings( true )
17
+ @recording.tap { |dataset|
18
+ dataset.instance_variable_set :@settings, simulation.settings( true )
19
19
  }
20
20
  end
21
21
 
22
- delegate :simulation, to: "self.class"
23
- delegate :reconstruct, :reduce, to: :recording
22
+ delegate :simulation,
23
+ to: "self.class"
24
+
25
+ delegate :reconstruct,
26
+ :reduce,
27
+ to: :recording
24
28
 
25
29
  # Initializes the recorder. Takes 2 arguments: +:features+ expecting the
26
30
  # feature set to record during simulation, and +:recording+, expecting the
27
31
  # initial state of the recording.
28
32
  #
29
- def initialize features: net.State.marking( free_pp ),
33
+ def initialize features: net.State.Features.Marking( free_pp ),
30
34
  recording: nil,
31
35
  **nn
32
- @features = net.State.features( features )
33
- if recording then reset! recording: recording else reset! end
36
+ @features = net.State.Features( features )
37
+ recording ? reset!( recording: recording ) : reset!
34
38
  end
35
39
 
36
- # Construct a new recording based on the parametrized class Recording().
40
+ # Construct a new recording based on the Recording() class.
37
41
  #
38
42
  def new_recording
39
- features.new_dataset
43
+ @features.DataSet.new
40
44
  end
41
45
 
42
- # Assigns to @recording a new Dataset instance. Without arguments, the new
43
- # recording is empty. With +:recording+ named argument supplied, the new
44
- # recording is filled with the prescribed contents.
46
+ # Assigns to +@recording+ a new +DataSet+ instance. If no arguments are
47
+ # supplied to this method, the new recording will stay empty. A recording
48
+ # can be optionally supplied via +:recording+ named argument.
45
49
  #
46
- def reset! **nn
47
- @features = net.State.features( nn[:features] || @features )
50
+ def reset! features: nil, recording: nil, **named_args
51
+ @features = net.State.Features( features ) if features
48
52
  @recording = new_recording
49
- @recording.update Hash[ nn[:recording] ] if nn[:recording]
53
+ @recording.update Hash[ recording ] if recording
54
+ return self
50
55
  end
51
56
 
52
57
  # Hook to be called by simulators whenever there is a state change. The
53
58
  # decision to sample is then the business of the recorder.
54
59
  #
55
- def alert
60
+ def alert!
56
61
  sample! # vanilla recorder samples at every occasion
57
62
  end
58
63
 
@@ -6,6 +6,7 @@ module YPetri::Simulation::Timed
6
6
 
7
7
  attr_reader :next_time
8
8
  attr_accessor :sampling
9
+
9
10
  delegate :time,
10
11
  :default_sampling,
11
12
  to: :simulation
@@ -13,32 +14,29 @@ module YPetri::Simulation::Timed
13
14
  # Apart from the vanilla version arguments, timed recorder takes +:sampling+
14
15
  # argument.
15
16
  #
16
- def initialize sampling: default_sampling, next_time: time, **nn
17
+ def initialize( sampling: default_sampling, next_time: time, **named_args )
17
18
  super
18
- @sampling = sampling
19
- @next_time = next_time
19
+ @sampling, @next_time = sampling, next_time
20
20
  end
21
21
 
22
22
  # Construct a new recording based on +features+.
23
23
  #
24
24
  def new_recording
25
- features.new_dataset type: :timed
25
+ features.DataSet.new type: :timed
26
26
  end
27
27
 
28
28
  # Like +YPetri::Simulation::Recorder#reset+, but allowing for an additional
29
29
  # named argument +:next_time+ that sets the next sampling time, and
30
30
  # +:sampling:, resetting the sampling period.
31
31
  #
32
- def reset! sampling: default_sampling, next_time: time, **nn
33
- super
34
- @sampling = sampling
35
- @next_time = next_time
32
+ def reset! sampling: default_sampling, next_time: time, **named_args
33
+ super.tap{ @sampling, @next_time = sampling, next_time }
36
34
  end
37
35
 
38
- # Hook to be called by simulators whenever the state changes (every time
39
- # that simulation +time+ is incremented).
36
+ # To be called by simulators whenever the state changes (every time that
37
+ # simulation +time+ is incremented).
40
38
  #
41
- def alert
39
+ def alert!
42
40
  t = time.round( 9 )
43
41
  t2 = next_time.round( 9 )
44
42
  if t >= t2 then # it's time to sample
@@ -47,6 +45,16 @@ module YPetri::Simulation::Timed
47
45
  end
48
46
  end
49
47
 
48
+ # Steps the simulation back. This prototype version of the method simply
49
+ # reconstructs a new simulation at a given time (1 simulation step by
50
+ # default) before the current time.
51
+ #
52
+ def back! by=simulation.step
53
+ time = simulation.time - by
54
+ simulation.recording.reconstruct( at: simulation.recording.floor( time ) )
55
+ .tap { |sim| sim.run! upto: time }
56
+ end
57
+
50
58
  private
51
59
 
52
60
  # Records the current state as a pair { sampling_time => system_state }.
@@ -23,6 +23,39 @@ module YPetri::Simulation::Timed
23
23
  alias starting_time initial_time
24
24
  alias ending_time target_time
25
25
 
26
+ attr_accessor :step, :target_time
27
+
28
+ # Explicit alias for +#step=+ method. Deprecated, use +#step=+ instead.
29
+ #
30
+ def set_step n
31
+ step=( n )
32
+ end
33
+ alias set_step_size set_step
34
+
35
+ # Explicit alias for +#target_time=+ method. Deprecated, use +#target_time=+
36
+ # instead.
37
+ #
38
+ def set_time target_time
39
+ target_time=( target_time )
40
+ end
41
+ alias set_target_time set_time
42
+
43
+ delegate :sampling,
44
+ :sampling=, to: :recorder
45
+
46
+ # Sets sampling of the simulation's data recorder.
47
+ #
48
+ def set_sampling sampling
49
+ recorder.sampling = sampling
50
+ end
51
+
52
+ # Changing the simulation method on the fly not supported.
53
+ #
54
+ def set_simulation_method
55
+ fail NotImplementedError,
56
+ "Changing simulation method on the fly not supported!"
57
+ end
58
+
26
59
  delegate :flux_vector_TS,
27
60
  :gradient_TS,
28
61
  :gradient_Ts,
@@ -30,33 +63,52 @@ module YPetri::Simulation::Timed
30
63
  :flux_vector,
31
64
  to: :core
32
65
 
33
- delegate :sampling, to: :recorder
34
-
35
- # Returns the flux of the indicated TS transitions (all TS transitions,
36
- # if no argument is given).
66
+ # Expects a single array of TS transitions or transition ids and returns an
67
+ # array of their fluxes under current marking.
37
68
  #
38
- def flux ids_of_TS_transitions=nil
69
+ def Fluxes( array )
39
70
  tt = TS_transitions()
40
- return flux tt if ids_of_TS_transitions.nil?
41
- TS_transitions( ids_of_TS_transitions ).map { |t|
42
- flux_vector.column_to_a.fetch tt.index( t )
43
- }
71
+ TS_Transitions( array )
72
+ .map { |t| flux_vector.column_to_a.fetch tt.index( t ) }
73
+ end
74
+
75
+ # Expects an arbitrary number of arguments identifying TS transitions, and
76
+ # retuns an array of their fluxes. Returns fluxes of all the TS transitions
77
+ # if no argument is given.
78
+ #
79
+ def fluxes( *transitions )
80
+ return Fluxes TS_transitions() if transitions.empty?
81
+ Fluxes( transitions )
82
+ end
83
+ alias flux fluxes
84
+
85
+ # Fluxes of the indicated TS transitions. Expects a single array argument,
86
+ # and returns a hash with transition names as keys.
87
+ #
88
+ def T_fluxes( array )
89
+ TS_Transitions( array ).names( true ) >> Fluxes( array )
44
90
  end
91
+ alias t_Fluxes T_fluxes
45
92
 
46
- # Flux of the indicated TS transitions (as hash with transition names as keys).
93
+ # Fluxes of the indicated TS transitions. Expects an arbitrary number of
94
+ # TS transitions or their ids, returns a hash with transition names as keys.
47
95
  #
48
- def t_flux ids=nil
49
- TS_transitions( ids ).names( true ) >> flux( ids )
96
+ def t_fluxes( *transitions )
97
+ return T_fluxes TS_transitions() if transitions.empty?
98
+ T_fluxes( transitions )
50
99
  end
100
+ alias t_flux t_fluxes
51
101
 
52
- # Pretty prints flux of the indicated TS transitions as hash with transition
102
+ # Pretty prints flux of the indicated TS transitions as a hash with transition
53
103
  # names as keys. Takes optional list of transition ids (first ordered arg.),
54
- # and optional 2 named arguments (+:gap+ and +:precision), as in
104
+ # and optional 2 named arguments (+:gap+ and +:precision+), as in
55
105
  # +#pretty_print_numeric_values+.
56
106
  #
57
- def pflux ids=nil, gap: 0, precision: 4
58
- t_flux( ids ).pretty_print_numeric_values( gap: gap, precision: precision )
107
+ def pflux( *transitions, gap: 0, precision: 4 )
108
+ t_flux( *transitions )
109
+ .pretty_print_numeric_values( gap: gap, precision: precision )
59
110
  end
111
+ alias pfluxes pflux
60
112
 
61
113
  # Reads the time range (initial_time .. target_time) of the simulation.
62
114
  #
@@ -125,7 +177,7 @@ module YPetri::Simulation::Timed
125
177
  #
126
178
  def increment_time! Δt=step
127
179
  @time += Δt
128
- recorder.alert
180
+ recorder.alert!
129
181
  end
130
182
 
131
183
  # Resets the timed simulation.
@@ -138,10 +190,15 @@ module YPetri::Simulation::Timed
138
190
  # Customized dup method that allows to modify the attributes of
139
191
  # the duplicate upon creation.
140
192
  #
141
- def dup time: time, **nn
142
- super( **nn ).tap { |i| i.reset_time! time }
193
+ def dup time: time, **named_args
194
+ super( **named_args ).tap { |instance| instance.reset_time! time }
195
+ end
196
+
197
+ # Alias for +#dup+ for timed simulations.
198
+ #
199
+ def at *args
200
+ dup *args
143
201
  end
144
- alias at dup
145
202
 
146
203
  # Returns the zero gradient. Optionally, places can be specified, for which
147
204
  # the zero vector is returned.
@@ -155,6 +212,14 @@ module YPetri::Simulation::Timed
155
212
  end
156
213
  alias zero_∇ zero_gradient
157
214
 
215
+ protected
216
+
217
+ # Resets the time to initial time, or to the argument (if provided).
218
+ #
219
+ def reset_time! time=nil
220
+ @time = time.nil? ? initial_time : time
221
+ end
222
+
158
223
  private
159
224
 
160
225
  # Initialization subroutine for timed simulations. Expects named arguments
@@ -193,13 +258,17 @@ module YPetri::Simulation::Timed
193
258
  reset_time!
194
259
  @step = settings[:step] || time_unit
195
260
  @default_sampling = settings[:sampling] || step
196
- @core = Core().new( method: method, guarded: guarded )
261
+ @core = if @guarded then
262
+ Core().guarded.new( method: method )
263
+ else
264
+ Core().new( method: method )
265
+ end
197
266
  @recorder = if features_to_record then
198
267
  # we'll have to figure out features
199
268
  ff = case features_to_record
200
269
  when Array then
201
270
  net.State.Features
202
- .infer_from_elements( features_to_record )
271
+ .infer_from_nodes( features_to_record )
203
272
  when Hash then
204
273
  net.State.features( features_to_record )
205
274
  end
@@ -213,13 +282,8 @@ module YPetri::Simulation::Timed
213
282
  # for timed simulations.
214
283
  #
215
284
  def init_core_and_recorder_subclasses
216
- param_class( { Core: YPetri::Core::Timed, Recorder: Recorder },
285
+ param_class( { Core: YPetri::Core.timed,
286
+ Recorder: Recorder },
217
287
  with: { simulation: self } )
218
288
  end
219
-
220
- # Resets the time to initial time, or to the argument (if provided).
221
- #
222
- def reset_time! time=nil
223
- @time = time.nil? ? initial_time : time
224
- end
225
289
  end # module YPetri::Simulation::Timed
@@ -1,18 +1,23 @@
1
1
  module YPetri::Simulation::Timeless
2
- # A timeless recorder.
2
+ # Timeless recorder.
3
3
  #
4
4
  class Recorder < YPetri::Simulation::Recorder
5
5
  attr_reader :next_event
6
6
 
7
7
  # Like +YPetri::Simulation::Recording#reset+, but allowing for additional
8
- # named argument +:next_sample+ that sets the event (label, hash key) of
8
+ # named argument +:next_event+ that sets the event (label, hash key) of
9
9
  # the next sample.
10
10
  #
11
- def reset! **nn
12
- super
13
- @next_event = nn[:next_event] || 0
11
+ def reset! next_event: 0, **named_args
12
+ super.tap { @next_event = next_event }
14
13
  end
15
14
 
15
+ # Backsteps the simulation.
16
+ #
17
+ def back!
18
+ fail NotImplementedError, "Backstep for timeless simulation not done yet!"
19
+ end
20
+
16
21
  private
17
22
 
18
23
  # Records the current system state under a numbered sample.
@@ -21,5 +26,5 @@ module YPetri::Simulation::Timeless
21
26
  super next_event
22
27
  @next_event = @next_event.next # "event" shoud implement next method
23
28
  end
24
- end # Recorder
29
+ end # class Recorder
25
30
  end # YPetri::Simulation::Timeless
@@ -12,6 +12,12 @@ class YPetri::Simulation
12
12
  false
13
13
  end
14
14
 
15
+ # Changing the simulation method on the fly not supported.
16
+ #
17
+ def set_simulation_method
18
+ fail NoMethodError, "Changing simulation method on the fly not supported!"
19
+ end
20
+
15
21
  private
16
22
 
17
23
  # Initialization subroutine for timeless simulations. Sets up the
@@ -22,13 +28,17 @@ class YPetri::Simulation
22
28
  method = settings[:method] # the simulation method
23
29
  features_to_record = settings[:record]
24
30
  init_core_and_recorder_subclasses
25
- @core = Core().new( method: method, guarded: guarded )
31
+ @core = if @guarded then
32
+ Core().guarded.new( method: method )
33
+ else
34
+ Core().new( method: method )
35
+ end
26
36
  @recorder = if features_to_record then
27
37
  # we'll have to figure out features
28
38
  ff = case features_to_record
29
39
  when Array then
30
40
  net.State.Features
31
- .infer_from_elements( features_to_record )
41
+ .infer_from_nodes( features_to_record )
32
42
  when Hash then
33
43
  net.State.features( features_to_record )
34
44
  end
@@ -42,7 +52,7 @@ class YPetri::Simulation
42
52
  # for timeless simulations.
43
53
  #
44
54
  def init_core_and_recorder_subclasses
45
- param_class( { Core: YPetri::Core::Timeless,
55
+ param_class( { Core: YPetri::Core.timeless,
46
56
  Recorder: Recorder },
47
57
  with: { simulation: self } )
48
58
  end
@@ -1,9 +1,9 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # A mixin for A transition representations.
4
4
  #
5
5
  module YPetri::Simulation::TransitionRepresentation::Type_A
6
- attr_reader :assignment_closure
6
+ attr_reader :assignment_closure, :direct_assignment_closure
7
7
 
8
8
  # Assignment action -- true for A transitions.
9
9
  #
@@ -54,6 +54,8 @@ module YPetri::Simulation::TransitionRepresentation::Type_A
54
54
  # Initialization subroutine.
55
55
  #
56
56
  def init
57
+ @function = source.action_closure
58
+ @direct_assignment_closure = construct_direct_assignment_closure
57
59
  @assignment_closure = to_assignment_closure
58
60
  end
59
61
 
@@ -68,13 +70,13 @@ module YPetri::Simulation::TransitionRepresentation::Type_A
68
70
  # could change their values.
69
71
  #
70
72
  def act
71
- codomain >> Array( function.( *domain_marking ) )
73
+ codomain >> Array( function.( *domain.marking ) )
72
74
  end
73
75
 
74
76
  # Builds an assignment closure, which, when called, directly affects the
75
77
  # simulation's marking vector (free places only).
76
78
  #
77
- def to_assignment_closure
79
+ def construct_direct_assignment_closure
78
80
  mv, ac = simulation.m_vector, source.action_closure
79
81
  λ = if codomain.size == 1 then
80
82
  target = codomain.first
@@ -87,4 +89,22 @@ module YPetri::Simulation::TransitionRepresentation::Type_A
87
89
  end
88
90
  eval λ % domain_access_code( vector: :mv )
89
91
  end
92
+
93
+ # Builds an assignment closure, which is bound to the domain and upon calling,
94
+ # returns the assignment action given the current domain marking.
95
+ #
96
+ def to_assignment_closure
97
+ build_closure
98
+ end
99
+
100
+ # Builds the A transition's function (asssignment action closure) into a
101
+ # closure already bound to the domain. Functions for A transitions have
102
+ # return value arity equal to the codomain size. The returned closure here
103
+ # ensures that the return value is always of Array type.
104
+ #
105
+ def build_closure
106
+ mv, f = simulation.m_vector, function
107
+ λ = "-> { Array f.( %s ) }" % domain_access_code( vector: :mv )
108
+ eval λ
109
+ end
90
110
  end # class YPetri::Simulation::TransitionRepresentation::Type_A
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # A mixin for S transition representations.
4
4
  #
@@ -41,5 +41,15 @@ class YPetri::Simulation::TransitionRepresentation
41
41
  @sparse_sv = Matrix.correspondence_matrix( codomain, places ) *
42
42
  stoichiometry.to_column_vector
43
43
  end
44
+
45
+ # Builds the S transition's function into a closure. Functions of
46
+ # S transitions return only a single number (flux for TS, firing for
47
+ # tS).
48
+ #
49
+ def build_closure
50
+ mv, f = simulation.m_vector, function
51
+ λ = "-> { f.( %s ) }" % domain_access_code( vector: :mv )
52
+ eval λ
53
+ end
44
54
  end # module Type_S
45
55
  end # class YPetri::Simulation::TransitionRepresentation
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # A mixin for timed transition representations.
4
4
  #
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # A mixin for Ts transition representations.
4
4
  #
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # A mixin for non-assignment transition representations.
4
4
  #
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # A mixin for s (nonstoichiometric) transition representations.
4
4
  #
@@ -25,5 +25,16 @@ class YPetri::Simulation::TransitionRepresentation
25
25
  def init
26
26
  super
27
27
  end
28
+
29
+ # Builds the s transition's function into a closure. Functions for s
30
+ # transitions (nonstoichiometric transitions) have return value arity
31
+ # equal to the codomain size. The returned closure here ensures that
32
+ # the return value is always of Array type.
33
+ #
34
+ def build_closure
35
+ mv, f = simulation.m_vector, function
36
+ λ = "-> { Array f.( %s ) }" % domain_access_code( vector: :mv )
37
+ eval λ
38
+ end
28
39
  end # module Type_s
29
40
  end # class YPetri::Simulation::TransitionRepresentation
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # A mixin for timed transition representations.
4
4
  #
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # A mixin for tS transition representations.
4
4
  #
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  # A mixin for ts transition representations.
4
4
  #
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
 
3
3
  require_relative 'a'
4
4
  require_relative 'A'
@@ -3,9 +3,10 @@
3
3
  # Representation of a YPetri::Transition inside a YPetri::Simulation instance.
4
4
  #
5
5
  class YPetri::Simulation
6
- class TransitionRepresentation < ElementRepresentation
6
+ class TransitionRepresentation < NodeRepresentation
7
7
  require_relative 'transition_representation/types'
8
- include Types
8
+
9
+ ★ Types
9
10
 
10
11
  attr_reader :domain, :codomain
11
12
  attr_reader :function # source transition function
@@ -14,7 +15,7 @@ class YPetri::Simulation
14
15
  #
15
16
  def initialize net_transition
16
17
  super
17
- @domain, @codomain = places( source.domain ), places( source.codomain )
18
+ @domain, @codomain = Places( source.domain ), Places( source.codomain )
18
19
  type_init
19
20
  end
20
21
 
@@ -42,14 +43,6 @@ class YPetri::Simulation
42
43
  codomain.map { |p| free_places.index p }
43
44
  end
44
45
 
45
- # Builds the transition's function into a closure.
46
- #
47
- def build_closure
48
- mv, f = simulation.m_vector, function
49
- λ = "-> { f.( %s ) }" % domain_access_code( vector: :mv )
50
- eval λ
51
- end
52
-
53
46
  # Builds a code string for accessing the domain directly from a marking
54
47
  # vector, given as argument.
55
48
  #