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.
- checksums.yaml +4 -4
- data/LICENSE.txt +675 -0
- data/README.md +6 -3
- data/Rakefile +1 -1
- data/lib/y_petri/agent/{petri_net_related.rb → petri_net_aspect.rb} +34 -10
- data/lib/y_petri/agent/{simulation_related.rb → simulation_aspect.rb} +49 -34
- data/lib/y_petri/agent.rb +5 -5
- data/lib/y_petri/core/guarded.rb +24 -0
- data/lib/y_petri/core/timed/euler.rb +4 -8
- data/lib/y_petri/core/timed/gillespie.rb +11 -17
- data/lib/y_petri/core/timed/methods.rb +23 -0
- data/lib/y_petri/core/timed/pseudo_euler.rb +10 -13
- data/lib/y_petri/core/timed/quasi_euler.rb +9 -8
- data/lib/y_petri/core/timed/runge_kutta.rb +10 -18
- data/lib/y_petri/core/timed.rb +6 -14
- data/lib/y_petri/core/timeless/methods.rb +15 -0
- data/lib/y_petri/core/timeless/pseudo_euler.rb +4 -8
- data/lib/y_petri/core/timeless.rb +9 -4
- data/lib/y_petri/core.rb +44 -42
- data/lib/y_petri/net/data_set.rb +246 -142
- data/lib/y_petri/net/node_access.rb +282 -0
- data/lib/y_petri/net/own_state.rb +14 -4
- data/lib/y_petri/net/state/feature/assignment.rb +123 -0
- data/lib/y_petri/net/state/feature/delta.rb +55 -35
- data/lib/y_petri/net/state/feature/firing.rb +68 -25
- data/lib/y_petri/net/state/feature/flux.rb +9 -2
- data/lib/y_petri/net/state/feature/gradient.rb +36 -19
- data/lib/y_petri/net/state/feature/marking.rb +10 -5
- data/lib/y_petri/net/state/feature.rb +105 -11
- data/lib/y_petri/net/state/features/record.rb +144 -99
- data/lib/y_petri/net/state/features.rb +327 -200
- data/lib/y_petri/net/state.rb +48 -82
- data/lib/y_petri/net/visualization.rb +1 -1
- data/lib/y_petri/net.rb +62 -47
- data/lib/y_petri/place/arcs.rb +44 -0
- data/lib/y_petri/place/features.rb +115 -0
- data/lib/y_petri/place.rb +62 -29
- data/lib/y_petri/simulation/dependency.rb +31 -67
- data/lib/y_petri/simulation/feature_set.rb +1 -1
- data/lib/y_petri/simulation/initial_marking/access.rb +42 -26
- data/lib/y_petri/simulation/marking_clamps/access.rb +22 -17
- data/lib/y_petri/simulation/marking_clamps.rb +0 -2
- data/lib/y_petri/simulation/marking_vector/access.rb +102 -40
- data/lib/y_petri/simulation/marking_vector.rb +35 -37
- data/lib/y_petri/simulation/matrix.rb +1 -1
- data/lib/y_petri/simulation/node_representation.rb +25 -0
- data/lib/y_petri/simulation/nodes/access.rb +78 -0
- data/lib/y_petri/simulation/{elements.rb → nodes.rb} +14 -13
- data/lib/y_petri/simulation/place_mapping.rb +2 -2
- data/lib/y_petri/simulation/place_representation.rb +8 -7
- data/lib/y_petri/simulation/places/access.rb +89 -70
- data/lib/y_petri/simulation/places/free.rb +1 -1
- data/lib/y_petri/simulation/places/types.rb +20 -22
- data/lib/y_petri/simulation/places.rb +23 -18
- data/lib/y_petri/simulation/recorder.rb +23 -18
- data/lib/y_petri/simulation/timed/recorder.rb +19 -11
- data/lib/y_petri/simulation/timed.rb +93 -29
- data/lib/y_petri/simulation/timeless/recorder.rb +11 -6
- data/lib/y_petri/simulation/timeless.rb +13 -3
- data/lib/y_petri/simulation/transition_representation/A.rb +24 -4
- data/lib/y_petri/simulation/transition_representation/S.rb +11 -1
- data/lib/y_petri/simulation/transition_representation/T.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/Ts.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/a.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/s.rb +12 -1
- data/lib/y_petri/simulation/transition_representation/t.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/tS.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/ts.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/types.rb +1 -1
- data/lib/y_petri/simulation/transition_representation.rb +4 -11
- data/lib/y_petri/simulation/transitions/A.rb +17 -2
- data/lib/y_petri/simulation/transitions/S.rb +1 -1
- data/lib/y_petri/simulation/transitions/T.rb +1 -1
- data/lib/y_petri/simulation/transitions/Ts.rb +6 -5
- data/lib/y_petri/simulation/transitions/a.rb +1 -1
- data/lib/y_petri/simulation/transitions/access.rb +195 -168
- data/lib/y_petri/simulation/transitions/s.rb +1 -1
- data/lib/y_petri/simulation/transitions/t.rb +1 -1
- data/lib/y_petri/simulation/transitions/tS.rb +1 -1
- data/lib/y_petri/simulation/transitions/ts.rb +1 -1
- data/lib/y_petri/simulation/transitions/types.rb +1 -1
- data/lib/y_petri/simulation/transitions.rb +5 -7
- data/lib/y_petri/simulation.rb +84 -90
- data/lib/y_petri/transition/A.rb +8 -2
- data/lib/y_petri/transition/T.rb +25 -2
- data/lib/y_petri/transition/arcs.rb +19 -3
- data/lib/y_petri/transition/construction_convenience.rb +11 -10
- data/lib/y_petri/transition/t.rb +14 -1
- data/lib/y_petri/transition/types.rb +6 -1
- data/lib/y_petri/transition.rb +9 -12
- data/lib/y_petri/version.rb +1 -1
- data/lib/y_petri/world/dependency.rb +3 -3
- data/lib/y_petri/world/{petri_net_related.rb → petri_net_aspect.rb} +4 -4
- data/lib/y_petri/world/simulation_aspect.rb +352 -0
- data/lib/y_petri/world.rb +4 -4
- data/lib/y_petri.rb +1 -1
- data/test/agent_test.rb +2 -1
- data/test/examples/demonstrator.rb +4 -1
- data/test/examples/demonstrator_2.rb +5 -0
- data/test/examples/demonstrator_4.rb +6 -5
- data/test/examples/example_2.rb +2 -0
- data/test/examples/manual_examples.rb +4 -4
- data/test/net_test.rb +457 -54
- data/test/place_test.rb +11 -7
- data/test/simulation_test.rb +358 -331
- data/test/transition_test.rb +11 -10
- data/test/world_test.rb +2 -0
- data/test/y_petri_test.rb +2 -1
- data/y_petri.gemspec +24 -18
- metadata +71 -17
- data/LICENSE +0 -22
- data/lib/y_petri/net/element_access.rb +0 -239
- data/lib/y_petri/simulation/element_representation.rb +0 -20
- data/lib/y_petri/simulation/elements/access.rb +0 -57
- data/lib/y_petri/transition/type.rb +0 -103
- data/lib/y_petri/transition/type_information.rb +0 -103
- 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
|
-
|
31
|
-
unless
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
5
|
-
# The recording
|
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 { |
|
18
|
-
|
17
|
+
@recording.tap { |dataset|
|
18
|
+
dataset.instance_variable_set :@settings, simulation.settings( true )
|
19
19
|
}
|
20
20
|
end
|
21
21
|
|
22
|
-
delegate :simulation,
|
23
|
-
|
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.
|
33
|
+
def initialize features: net.State.Features.Marking( free_pp ),
|
30
34
|
recording: nil,
|
31
35
|
**nn
|
32
|
-
@features = net.State.
|
33
|
-
|
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
|
40
|
+
# Construct a new recording based on the Recording() class.
|
37
41
|
#
|
38
42
|
def new_recording
|
39
|
-
features.
|
43
|
+
@features.DataSet.new
|
40
44
|
end
|
41
45
|
|
42
|
-
# Assigns to
|
43
|
-
#
|
44
|
-
#
|
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! **
|
47
|
-
@features = net.State.
|
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[
|
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, **
|
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.
|
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, **
|
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
|
-
#
|
39
|
-
#
|
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
|
-
|
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
|
69
|
+
def Fluxes( array )
|
39
70
|
tt = TS_transitions()
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
#
|
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
|
49
|
-
|
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
|
58
|
-
t_flux(
|
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, **
|
142
|
-
super( **
|
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 =
|
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
|
-
.
|
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
|
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
|
-
#
|
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 +:
|
8
|
+
# named argument +:next_event+ that sets the event (label, hash key) of
|
9
9
|
# the next sample.
|
10
10
|
#
|
11
|
-
def reset! **
|
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 =
|
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
|
-
.
|
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
|
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.( *
|
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
|
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 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
|
@@ -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 <
|
6
|
+
class TransitionRepresentation < NodeRepresentation
|
7
7
|
require_relative 'transition_representation/types'
|
8
|
-
|
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 =
|
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
|
#
|