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
@@ -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
  #