y_petri 2.3.11 → 2.3.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 213efc795950a5d200a6b5c10fe3150dddf4940b
4
- data.tar.gz: 6c1a54e4526c7f19ea63dc7faad780526e2d3ee2
3
+ metadata.gz: 3fe2aaae8033f7806b851cd4293f555d15beb5a5
4
+ data.tar.gz: 79271fa571273448d6716b547785f66805b5d5b4
5
5
  SHA512:
6
- metadata.gz: 60800f142748c833d2298583393f3790532d56bf294779d02a6e6b6991409bdc12b584bf64ec286868012d3b4d25e0a18cc8a5ac170359ab4c00ca7c703fdf52
7
- data.tar.gz: aacfcbc2bbba5c262c5e2cab747a4fe093d047b02a65781709eec758a30b5bc9222dcd0a6874afdf1041d1a8d3f9d9e143fe0bd80f26361df6f5cd4b64e9182e
6
+ metadata.gz: 14a6aba15f89a662ee2e13e16dc09695c1d00ccbe60ce7f969b9ae2a348f9bc8c98f51a2090643671b568d06f36419d162dda8ef5005fd34f014ec28aa75a855
7
+ data.tar.gz: 66681f89b12fc840eabc2d225af8e137492870c61c8d844b8fcb73cd78ef712bfe46c497882be534a98e5287bb76e7aa97a726f032bd16346cb79a735d4069e9
@@ -1,9 +1,9 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Adaptation of Euler method for the systems possibly with timeless transitions
4
- # and assignment transitions.
3
+ # Basic Petri net execution method for timed and hybrid nets. Works also for
4
+ # timeless nets, but for those, Core::Timeless::Basic is slightly more efficient.
5
5
  #
6
- module YPetri::Core::Timed::PseudoEuler
6
+ module YPetri::Core::Timed::Basic
7
7
  # Computes Δ for the period of Δt. Its result is a sum of the contribution of
8
8
  # timed transitions over the period Δt and the contribution of timeless
9
9
  # transitions as if each fired once.
@@ -23,4 +23,4 @@ module YPetri::Core::Timed::PseudoEuler
23
23
  simulation.increment_time! Δt
24
24
  alert! # alerts the sampler that the system has changed
25
25
  end
26
- end # YPetri::Core::Timed::PseudoEuler
26
+ end # YPetri::Core::Timed::Basic
@@ -4,9 +4,7 @@
4
4
  #
5
5
  module YPetri::Core::Timed::RungeKutta
6
6
  def delta Δt
7
- fail NotImplementedError, "RungeKutta not implemented yet!"
8
-
9
- # f = simulation.method :gradient, parameter: :state
7
+ # The f below is from the equation state' = f( state )
10
8
  f = lambda { |mv| # mv is the marking vector of the free places
11
9
  result = "make hash from free places of the simulation to zeros"
12
10
  nonstoichiometric_transitions.each { |t|
@@ -4,7 +4,7 @@
4
4
  # and assignment transitions. Unlike +pseudo_euler+, which fires every step,
5
5
  # +quasi_euler+ fires every time tick. Not implemented yet.
6
6
  #
7
- module YPetri::Core::Timed::QuasiEuler
7
+ module YPetri::Core::Timed::Ticked
8
8
  # Computes Δ for the period of Δt. Not mplemented yet.
9
9
  #
10
10
  def delta Δt
@@ -19,4 +19,4 @@ module YPetri::Core::Timed::QuasiEuler
19
19
  # Now one would have to compare whichever comes first, time tick or the
20
20
  # end of Δt, and then again and again, until Δt is fired...
21
21
  end
22
- end # YPetri::Core::Timed::QuasiEuler
22
+ end # YPetri::Core::Timed::Ticked
@@ -1,10 +1,34 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Timed simulation core.
3
+ # Timed simulation core. Knows several simulation methods applicable to
4
+ # timed nets.
4
5
  #
5
- module YPetri::Core::Timed
6
- require_relative 'timed/methods'
7
- ★ Methods
6
+ class YPetri::Core::Timed
7
+ YPetri::Core
8
+
9
+ require_relative 'timed/basic'
10
+ require_relative 'timed/ticked' #
11
+ require_relative 'timed/euler'
12
+ require_relative 'timed/runge_kutta'
13
+ require_relative 'timed/gillespie'
14
+
15
+ METHODS = {
16
+ basic: Basic, # simple PN execution, timeless tt fire after each step
17
+ ticked: Ticked, # like basic, but timeless tt fire at every time tick
18
+ euler: Euler, # for timed nets only
19
+ runge_kutta: RungeKutta, # for timed nets only
20
+ gillespie: Gillespie # for timed nets only
21
+ }
22
+
23
+ def initialize **named_args
24
+ super
25
+ extend METHODS.fetch simulation_method
26
+ # look in the Core#initialize method for the closures and parameters
27
+ # and such. Here, we could define:
28
+ @Ts_gradient_closure = simulation.Ts_gradient_closure
29
+ # which would remind us that this machine needs to be
30
+ # actually defined internal to Core instance
31
+ end
8
32
 
9
33
  # Makes a single step by Δt.
10
34
  #
@@ -25,6 +49,8 @@ module YPetri::Core::Timed
25
49
  #
26
50
  def gradient_Ts
27
51
  simulation.Ts_gradient_closure.call
52
+ # this could be
53
+ # @Ts_gradient_closure.call
28
54
  end
29
55
 
30
56
  # Gradient contribution by TS transitions.
@@ -51,11 +77,9 @@ module YPetri::Core::Timed
51
77
  alias propensity_vector_TS flux_vector_TS
52
78
  end # module YPetri::Core::Timed
53
79
 
54
- # In general, it is not required that all net nodes are simulated with the
55
- # same method. Practically, ODE systems have many good simulation methods
56
- # available.
80
+ # Textbook simulation methods ODE systems have many good simulation methods available.
57
81
  #
58
- # (1) ᴍ(t) = ϝ f(ᴍ, t).dt, where f(ᴍ, t) is a known function.
82
+ # (1) mv' = ϝ f(mv, t).dt, where f(m, t) is a known function.
59
83
  #
60
84
  # Many of these methods depend on the Jacobian, but that may not be available
61
85
  # for some places. Therefore, the places, whose marking defines the system
@@ -66,3 +90,5 @@ end # module YPetri::Core::Timed
66
90
  # If we apply the definition of "causal orientation" on A and E places, then it
67
91
  # can be said, that only the transitions causally oriented towards "A" places
68
92
  # are allowed for compliance with the equation (1).
93
+
94
+ # In general, it is not required that all net nodes are simulated with the same method.
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ # The basic simulation method in YPetri is simple Petri net (PN) execution. While
4
+ # in principle applicable to any PN type, it can be made slightly more efficient
5
+ # if it is known in advance that no no timed transitions will be in the net.
6
+ #
7
+ module YPetri::Core::Timeless::Basic
8
+ # Peforms a single step of the basic method.
9
+ #
10
+ def step!
11
+ # Compute the sum of the contribution of ts and tS transitions, and
12
+ # increment the free marking vector by it.
13
+ increment_free_vector by: delta_ts + delta_tS
14
+ # Fire all the assignment transitions in their order.
15
+ fire_all_assignment_transitions!
16
+ # before: assignment_transitions_all_fire!
17
+ # Alert the recorder(s) that the system has changed.
18
+ alert!
19
+ end
20
+ end # module YPetri::Core::Timeless::Basic
@@ -1,15 +1,27 @@
1
1
  # encoding: utf-8
2
2
 
3
- # Timeless simulator mixin.
3
+ # Timeless simulator core. Knows thus far only one, but potentially several
4
+ # methods applicable to timeless systems simulations.
4
5
  #
5
- module YPetri::Core::Timeless
6
- require_relative 'timeless/methods'
7
- ★ Methods
6
+ class YPetri::Core::Timeless
7
+ YPetri::Core
8
+
9
+ require_relative 'timeless/basic'
10
+
11
+ METHODS = { basic: Basic } # basic PN execution
12
+ # Note: the reason why Timeless core has distinct basic method is because
13
+ # without having to consider timed transitions, it can be made simpler.
8
14
 
9
- # Makes a single step.
15
+ def initialize **named_args
16
+ super
17
+ extend METHODS.fetch simulation_method
18
+ end
19
+
20
+ # Computes the system state delta.
10
21
  #
11
22
  def delta
12
- delta_timeless
23
+ delta_timeless # this method was taken from core.rb
24
+ # delta_ts + delta_tS # this is the contents of delta_timeless method
13
25
  end
14
26
 
15
27
  # Computes the system state delta.
data/lib/y_petri/core.rb CHANGED
@@ -1,83 +1,62 @@
1
1
  # encoding: utf-8
2
2
 
3
- # This class represents a simulator.
3
+ # This module represents a simulation core (execution machine), which can be
4
+ # either timed (class Core::Timed) or timeless (class Core::Timeless).
4
5
  #
5
- class YPetri::Core
6
- # TODO: currently, Core and Simulation classes are tightly coupled.
7
- # each simulation has just one core, and that core looks directly
8
- # into the simulation's state. What needs to be done is a simulation
9
- # that at least hints the process of core recruitment for the requested
10
- # operation (be it step, step backwards, run forward aso.) and then
11
- # imprints the core with its current marking vector, tells the core
12
- # what to do, and then reads the result and updates its marking vector
13
- # accordingly. There are multiple possibilities, such as constructing
14
- # a new core for each operation, or keeping the same core for all the
15
- # operations using a given method. A simulation method (like euler,
16
- # gillespie, or runge-kutta) should be associated not so much with
17
- # the simulation object, as it should be associated with the core
18
- # object. A core object should be more or less one-trick pony. While
19
- # later, it is possible for a simulation to have broader simulation
20
- # strategy, or "method" in the broader sense. But simulation should
21
- # also avoid doing too much, because above it, there is Agent class,
22
- # and this class can be taught to do the more complicated things
23
- # such as parameter optimization or computation of control coefficients
24
- # and such. It is also possible to construct more specialized agent-like
25
- # classes for these more specialized tasks, since the main purpose
26
- # of Agent class, as I saw it, was to represent the user (represent
27
- # what the user means), to provide the user interface.
28
-
6
+ module YPetri::Core
7
+ YPetri::Simulation::Dependency # dependency stays for now
8
+
29
9
  require_relative 'core/timed'
30
10
  require_relative 'core/timeless'
31
- require_relative 'core/guarded'
32
11
 
33
- YPetri::Simulation::Dependency
12
+ DEFAULT_METHOD = :basic
34
13
 
35
- DEFAULT_METHOD = :pseudo_euler
14
+ # I'm doing it this way in order to gradually begin decoupling in my mind
15
+ # core from simulation. The constructed core will have to be assigned the
16
+ # simulation object on which it will depend before core is made completely
17
+ # independend on simulation. (Not gonna happen any soon.)
18
+ #
19
+ attr_reader :simulation # just a remark:
20
+ attr_reader :simulation_method # "reader" is "selector" in Landin's language
36
21
 
37
- class << self
38
- # Timed subclass of self.
39
- #
40
- def timed
41
- Class.new self do
42
- include Timed
43
- def timed?; true end
44
- def timeless?; false end
45
- end
46
- end
47
-
48
- # Timeless subclass of self.
49
- #
50
- def timeless
51
- Class.new self do
52
- include Timeless
53
- def timed?; false end
54
- def timeless?; true end
55
- end
56
- end
57
-
58
- # Vanilla simulator is not guarded.
22
+ def initialize simulation: nil, method: nil, guarded: false, **named_args
23
+ @simulation = simulation or fail ArgumentError, "Core requires simulation!"
24
+ @simulation_method = method || DEFAULT_METHOD
25
+
26
+ if guarded then # TODO: Guarded is unfinished business.
27
+ fail NotImplementedMethod, "Guarded core is not implemented yet!"
28
+ require_relative 'core/guarded' # TODO: Should be replaced with autoload.
29
+ else @guarded = false end
30
+
31
+ # Dependent on Simulation, this machine returns "delta contribution for ts
32
+ # (timeless nonstoichiometric) transitions", which smells like a vector of
33
+ # size corresponding to the number of free places.
59
34
  #
60
- def guarded?; false end
35
+ @delta_closure_for_ts_transitions = simulation.ts_delta_closure
61
36
 
62
- # Guarded subclass of self (not working yet).
37
+ # This one is slightly different in that it returns so-called "firing vector",
38
+ # from which delta vector is computed by multiplying it with tS stoichiometry
39
+ # matrix.
63
40
  #
64
- def guarded
65
- Class.new self do
66
- include Guarded
67
- def guarded?; true end
68
- end
69
- end
70
- end
41
+ @firing_closure_for_tS_transitions = simulation.tS_firing_closure
71
42
 
72
- attr_reader :simulation_method
43
+ # This machine is special in that it directly modifies the marking vector,
44
+ # firing the assignment transitions one by one (or so I think).
45
+ #
46
+ @assignment_closure_for_A_transitions = simulation.A_direct_assignment_closure
73
47
 
74
- def initialize method: nil, guarded: false, **named_args
75
- @simulation_method = method || DEFAULT_METHOD
76
- method_init # defined in Timed::Methods and Timeless::Methods
48
+ # We're gonna change all of the above. The marking vectors will be owned by
49
+ # the core now. Machines will be wired only inside the core.
77
50
  end
78
51
 
79
- delegate :simulation,
80
- :timed?,
52
+ # TODO: this delegation below is not completely right.
53
+ # 1. There is no subclassing and Timed/Timeless module inclusion, so there
54
+ # is no need to delegate timed?/timeless? to the class, if only the modules
55
+ # provide those inquirer methods (predicates in Landin's language).
56
+ # 2. Same goes for guarded? predicate, which might be the business of
57
+ # Core::Guarded module (or not)
58
+ #
59
+ delegate :timed?,
81
60
  :timeless?,
82
61
  :guarded?,
83
62
  to: "self.class"
@@ -102,24 +81,71 @@ class YPetri::Core
102
81
  #
103
82
  def delta_ts
104
83
  simulation.ts_delta_closure.call
84
+ # @delta_closure_for_ts_transitions.call
105
85
  end
106
86
 
107
87
  # Firing vector of tS transitions.
108
88
  #
109
89
  def firing_vector_tS
110
90
  simulation.tS_firing_closure.call
91
+ # @firing_closure_for_tS_transitions.call
111
92
  end
112
93
 
113
94
  # Increments the marking vector by a given delta.
114
95
  #
115
96
  def increment_marking_vector( delta )
116
97
  print '.'
98
+ # TODO: From now on, this won't touch the simulation's property
99
+ # at all. It will be left to the simulation to ask for the results,
100
+ # or to rig the core to message back when done.
117
101
  simulation.increment_marking_vector_closure.( delta )
118
102
  end
119
103
 
120
- # Fires assignment transitions.
104
+ # Fires all the assignment transitions.
121
105
  #
122
- def assignment_transitions_all_fire!
106
+ def fire_all_assignment_transitions!
123
107
  simulation.A_direct_assignment_closure.call
108
+ # @assignment_closure_for_A_transitions.call
124
109
  end
125
- end # class YPetri::Core
110
+ alias assignment_transitions_all_fire! fire_all_assignment_transitions!
111
+ end # module YPetri::Core
112
+
113
+ # TODO: Decouple Core and Simulation classes. It still looks like one
114
+ # simulation will use only one core (or one for each type of simulation
115
+ # trick), but I don't want the core to be parametrized by a Simulation
116
+ # instance. There should be at least a hint of core recruitment, sending
117
+ # the state to the core, asking the core to perform its trick on it, and
118
+ # asking back the results (or rigging the core to send them back as soon
119
+ # as done). A core should be more or less a one-trick pony. But simulation
120
+ # should also avoid doing too much, because above it, other classes (Agent
121
+ # and co.) may exist, doing things like optimization, parameter inferences
122
+ # aso.
123
+
124
+ # TODO: Regarding guarded cores, many kinds of PNs prohibit places from
125
+ # acquiring negative marking, or impose other restrictions. If the system
126
+ # state somehow makes it out of this safe envelope, the transitions may
127
+ # start behaving unpredictably. So there is a question of who is responsible
128
+ # for keeping the system sane (in the safe state envelope). The simple thing
129
+ # is for the core not to test anything and leave it up to the user not to
130
+ # define systems that are not sane. Simple is good, but there must be agreement,
131
+ # a requirement that the system specification behaves. If there is no such
132
+ # agreement, the core has no excuse from the need to guard against transitions
133
+ # trying to fire when they should properly be disabled (at least not if the
134
+ # core knows that the PN in question is classical). I did not decide what exactly
135
+ # should happen if the sanity is broken (raise an error? warn and try minor
136
+ # repair measures yourself?), but something should.
137
+ #
138
+ # Another example, in chemical systems, negative markings (concentrations)
139
+ # also ordinarily make no sense. But insensitive combination of functions
140
+ # and simulation method may lead to unsafe state with relatively late detection
141
+ # of error, leaving the modeller wondering when exactly the system state went
142
+ # haywire. Again, I'm not sure how exactly should the guarded core react to
143
+ # the treat of insane situation, but it somehow should.
144
+ #
145
+ # I feel it is necessary for the core to have awareness of the quality of
146
+ # the momentary system's state (at least to be able to tell whether it's
147
+ # meaningful at all), because later I want to let the core choose between
148
+ # deterministic (continous) and stochastic (discrete, going quantum by
149
+ # quantum, or by several quanta, there is more than one stochastic discrete
150
+ # method in stock) methods for simulation of individual processes.
151
+
@@ -9,7 +9,7 @@ module YPetri
9
9
  Transition = Class.new
10
10
  Net = Class.new Module
11
11
  Simulation = Class.new
12
- Core = Class.new
12
+ Core = Module.new
13
13
  World = Class.new
14
14
  Agent = Class.new
15
15
  end # module YPetri
@@ -254,14 +254,15 @@ module YPetri::Simulation::Timed
254
254
  @time_unit = anything.class.one
255
255
  @initial_time, @target_time = time_unit * 0, time_unit * Float::INFINITY
256
256
  end
257
- init_core_and_recorder_subclasses
257
+ # Set up a parametrized subclas of the sampler for timed simulation.
258
+ param_class( { Recorder: Recorder }, with: { simulation: self } )
258
259
  reset_time!
259
260
  @step = settings[:step] || time_unit
260
261
  @default_sampling = settings[:sampling] || step
261
262
  @core = if @guarded then
262
- Core().guarded.new( method: method )
263
+ YPetri::Core::Timed.new( simulation: self, method: method, guarded: true )
263
264
  else
264
- Core().new( method: method )
265
+ YPetri::Core::Timed.new( simulation: self, method: method, guarded: false )
265
266
  end
266
267
  @recorder = if features_to_record then
267
268
  # we'll have to figure out features
@@ -277,13 +278,4 @@ module YPetri::Simulation::Timed
277
278
  Recorder().new( sampling: settings[:sampling] )
278
279
  end
279
280
  end
280
-
281
- # Sets up subclasses of +Core+ (the simulator) and +Recorder+ (the sampler)
282
- # for timed simulations.
283
- #
284
- def init_core_and_recorder_subclasses
285
- param_class( { Core: YPetri::Core.timed,
286
- Recorder: Recorder },
287
- with: { simulation: self } )
288
- end
289
281
  end # module YPetri::Simulation::Timed
@@ -2,36 +2,38 @@
2
2
 
3
3
  # A mixin for timeless simulations.
4
4
  #
5
- class YPetri::Simulation
6
- module Timeless
7
- require_relative 'timeless/recorder'
5
+ module YPetri::Simulation::Timeless
6
+ require_relative 'timeless/recorder'
8
7
 
9
- # False for timeless simulations.
10
- #
11
- def timed?
12
- false
13
- end
8
+ # False for timeless simulations.
9
+ #
10
+ def timed?
11
+ false
12
+ end
14
13
 
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
14
+ # Changing the simulation method on the fly not supported.
15
+ #
16
+ def set_simulation_method
17
+ fail NoMethodError, "Changing simulation method on the fly not supported!"
18
+ end
20
19
 
21
- private
20
+ private
22
21
 
23
- # Initialization subroutine for timeless simulations. Sets up the
24
- # parametrized subclasses +@Core+ (the simulator) and +@Recorder+,
25
- # and initializes the +@recorder+ attribute.
26
- #
27
- def init **settings
28
- method = settings[:method] # the simulation method
29
- features_to_record = settings[:record]
30
- init_core_and_recorder_subclasses
22
+ # Initialization subroutine for timeless simulations. Sets up the
23
+ # parametrized subclasses +@Core+ (the simulator) and +@Recorder+,
24
+ # and initializes the +@recorder+ attribute.
25
+ #
26
+ def init **settings
27
+ method = settings[:method] # the simulation method
28
+ features_to_record = settings[:record]
29
+ # Sets up a parametrized subclass of the sampler for timeless simulation.
30
+ param_class( { Recorder: Recorder }, with: { simulation: self } )
31
31
  @core = if @guarded then
32
- Core().guarded.new( method: method )
32
+ YPetri::Core::Timeless
33
+ .new( simulation: self, method: method, guarded: true )
33
34
  else
34
- Core().new( method: method )
35
+ YPetri::Core::Timeless
36
+ .new( simulation: self, method: method, guarded: false )
35
37
  end
36
38
  @recorder = if features_to_record then
37
39
  # we'll have to figure out features
@@ -47,14 +49,4 @@ class YPetri::Simulation
47
49
  Recorder().new # init the recorder
48
50
  end
49
51
  end
50
-
51
- # Sets up subclasses of +Core+ (the simulator) and +Recorder+ (the sampler)
52
- # for timeless simulations.
53
- #
54
- def init_core_and_recorder_subclasses
55
- param_class( { Core: YPetri::Core.timeless,
56
- Recorder: Recorder },
57
- with: { simulation: self } )
58
- end
59
- end # module Timeless
60
- end # module YPetri::Simulation
52
+ end # module YPetri::Simulation::Timeless
@@ -42,7 +42,7 @@ class YPetri::Simulation
42
42
  ★ MarkingClamps::Access
43
43
  ★ MarkingVector::Access
44
44
 
45
- DEFAULT_SETTINGS = -> do { method: :pseudo_euler, guarded: false } end
45
+ DEFAULT_SETTINGS = -> do { method: :basic, guarded: false } end
46
46
 
47
47
  class << self
48
48
  alias __new__ new
@@ -1,4 +1,4 @@
1
1
  module YPetri
2
- VERSION = "2.3.11"
2
+ VERSION = "2.3.12"
3
3
  DEBUG = false
4
4
  end
@@ -123,7 +123,7 @@ require_relative '../lib/y_petri' # tested component itself
123
123
  # @sim.m.must_equal [1, 2]
124
124
  # @sim.p_m.must_equal( { A: 1, B: 2 } )
125
125
  # @sim.recording.must_equal( { 0 => [1, 2]} )
126
- # @sim.simulation_method.must_equal :pseudo_euler
126
+ # @sim.simulation_method.must_equal :basic
127
127
  # @sim.core.must_be_kind_of YPetri::Core
128
128
  # @sim.ts_tt.first.domain.must_equal []
129
129
  # @sim.send( :ts_transitions ).first.domain_access_code.must_equal ''
@@ -195,7 +195,7 @@ require_relative '../lib/y_petri' # tested component itself
195
195
 
196
196
  # it "should behave" do
197
197
  # @sim.timed?.must_equal true
198
- # @sim.simulation_method.must_equal :pseudo_euler
198
+ # @sim.simulation_method.must_equal :basic
199
199
  # @sim.Ts_tt.size.must_equal 1
200
200
  # @sim.send( :transitions ).Ts.first.gradient_closure.call.must_equal [1]
201
201
  # @sim.Ts_tt.first.codomain.names.must_equal [:A]
@@ -212,7 +212,7 @@ require_relative '../lib/y_petri' # tested component itself
212
212
 
213
213
  # it "should behave" do
214
214
  # @sim.send( :transitions ).Ts.first.codomain.names.must_equal [:A]
215
- # @sim.simulation_method.must_equal :pseudo_euler
215
+ # @sim.simulation_method.must_equal :basic
216
216
  # @sim.timed?.must_equal true
217
217
  # @sim.core.timed?.must_equal true
218
218
  # @sim.reset!
@@ -289,7 +289,7 @@ require_relative '../lib/y_petri' # tested component itself
289
289
  # it "should behave" do
290
290
  # s = simulation
291
291
  # assert ! s.timed?
292
- # s.core.must_be_kind_of YPetri::Core::Timeless::PseudoEuler
292
+ # s.core.ancestors.must_include YPetri::Core::Timeless::Basic
293
293
  # ds = s.recording
294
294
  # ds.size.must_equal 6
295
295
  # ds.events.must_equal [0, 1, 2, 3, 4, 5]
@@ -334,7 +334,7 @@ describe "timed simulation" do
334
334
  it "should behave" do
335
335
  places.map( &:marking ).must_equal [0.5, 0.5] # marking unaffected
336
336
  s = simulation
337
- s.settings.must_equal( { method: :pseudo_euler, guarded: false,
337
+ s.settings.must_equal( { method: :basic, guarded: false,
338
338
  step: 0.1, sampling: 5, time: 0..60 } )
339
339
  assert s.recording.to_csv.start_with?( ":event,:A,:B\n" +
340
340
  "0.0,0.5,0.5\n" +
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: y_petri
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.11
4
+ version: 2.3.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - boris
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-05 00:00:00.000000000 Z
11
+ date: 2015-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -145,15 +145,13 @@ files:
145
145
  - lib/y_petri/core.rb
146
146
  - lib/y_petri/core/guarded.rb
147
147
  - lib/y_petri/core/timed.rb
148
+ - lib/y_petri/core/timed/basic.rb
148
149
  - lib/y_petri/core/timed/euler.rb
149
150
  - lib/y_petri/core/timed/gillespie.rb
150
- - lib/y_petri/core/timed/methods.rb
151
- - lib/y_petri/core/timed/pseudo_euler.rb
152
- - lib/y_petri/core/timed/quasi_euler.rb
153
151
  - lib/y_petri/core/timed/runge_kutta.rb
152
+ - lib/y_petri/core/timed/ticked.rb
154
153
  - lib/y_petri/core/timeless.rb
155
- - lib/y_petri/core/timeless/methods.rb
156
- - lib/y_petri/core/timeless/pseudo_euler.rb
154
+ - lib/y_petri/core/timeless/basic.rb
157
155
  - lib/y_petri/dsl.rb
158
156
  - lib/y_petri/fixed_assets.rb
159
157
  - lib/y_petri/net.rb
@@ -1,23 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # Timed simulation core.
4
- #
5
- module YPetri::Core::Timed
6
- require_relative 'euler'
7
- require_relative 'pseudo_euler' # t transitions firing after each step
8
- require_relative 'quasi_euler' # t transitions firing after each time tick
9
- require_relative 'gillespie'
10
- require_relative 'runge_kutta'
11
-
12
- module Methods
13
- def method_init
14
- extend case simulation_method
15
- when :euler then Euler
16
- when :pseudo_euler then PseudoEuler
17
- when :quasi_euler then QuasiEuler
18
- when :gillespie then Gillespie
19
- when :runge_kutta then RungeKutta
20
- else fail TypeError, "Unknown timed simulation method: #{method}!" end
21
- end
22
- end
23
- end
@@ -1,15 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # Timed simulation core.
4
- #
5
- module YPetri::Core::Timeless
6
- require_relative 'pseudo_euler'
7
-
8
- module Methods
9
- def method_init
10
- extend case simulation_method
11
- when :pseudo_euler then PseudoEuler
12
- else fail TypeError, "Unknown timeless simulation method: #{method}!" end
13
- end
14
- end
15
- end
@@ -1,14 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # Implicit Euler for timeless nets.
4
- #
5
- module YPetri::Core::Timeless::PseudoEuler
6
- # Method #step! for timeless +pseudo_euler+ method. Simply, timeless
7
- # transitions fire simultaneously, after which, A transitions (if any) fire.
8
- #
9
- def step!
10
- increment_marking_vector Δ
11
- assignment_transitions_all_fire!
12
- alert!
13
- end
14
- end # module YPetri::Core::Timeless::PseudoEuler