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