y_petri 2.3.10 → 2.3.11

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: 3764e025431d0669a31797b1d5bbce55a444e3d6
4
- data.tar.gz: 6bf64d8fa786b8366219e7e2949cd581493cd75a
3
+ metadata.gz: 213efc795950a5d200a6b5c10fe3150dddf4940b
4
+ data.tar.gz: 6c1a54e4526c7f19ea63dc7faad780526e2d3ee2
5
5
  SHA512:
6
- metadata.gz: 9c7294bf61692d9514ffe266dea39c931c25587cfc5ee14a1737010d21f88653a3ef8f14b826478b255e90c8623e7b33f8e81e02eeaac2e9aa986108ec32eec3
7
- data.tar.gz: 73072db1890baeec7ea5fd6f22f80c95a6a581c69179062c6550b76a7ccf382b9ef22e4b502d0e1d957af4473e9f33df8883069a58b7f6a8bb41c87ccee52bee
6
+ metadata.gz: 60800f142748c833d2298583393f3790532d56bf294779d02a6e6b6991409bdc12b584bf64ec286868012d3b4d25e0a18cc8a5ac170359ab4c00ca7c703fdf52
7
+ data.tar.gz: aacfcbc2bbba5c262c5e2cab747a4fe093d047b02a65781709eec758a30b5bc9222dcd0a6874afdf1041d1a8d3f9d9e143fe0bd80f26361df6f5cd4b64e9182e
@@ -3,11 +3,11 @@
3
3
  # Petri net aspect of +YPetri::Agent+.
4
4
  #
5
5
  module YPetri::Agent::PetriNetAspect
6
- # Net selection class.
6
+ # A class representing a selection of nets.
7
7
  #
8
8
  NetSelection = Class.new YPetri::Agent::Selection
9
9
 
10
- # Net point
10
+ # Net point.
11
11
  #
12
12
  attr_reader :net_point
13
13
 
@@ -15,6 +15,8 @@ module YPetri::Agent::PetriNetAspect
15
15
  #
16
16
  attr_reader :net_selection
17
17
 
18
+ # Standard initialization method. Takes no arguments.
19
+ #
18
20
  def initialize
19
21
  net_point_reset
20
22
  @net_selection = NetSelection.new
@@ -27,37 +29,37 @@ module YPetri::Agent::PetriNetAspect
27
29
  :nets, :places, :transitions,
28
30
  to: :world
29
31
 
30
- # Place name.
32
+ # Returns the name of a place identified by the argument.
31
33
  #
32
34
  def pl( place_id )
33
35
  place( place_id ).name
34
36
  end
35
37
 
36
- # Transition name.
38
+ # Returns the name of a transition identified by the argument.
37
39
  #
38
40
  def tr( transition_id )
39
41
  transition( transition_id ).name
40
42
  end
41
43
 
42
- # Place names.
44
+ # Names of the places.
43
45
  #
44
46
  def pn
45
47
  places.names
46
48
  end
47
49
 
48
- # Transition names.
50
+ # Names of the transitions.
49
51
  #
50
52
  def tn
51
53
  transitions.names
52
54
  end
53
55
 
54
- # Net names.
56
+ # Names of the nets.
55
57
  #
56
58
  def nn
57
59
  nets.names
58
60
  end
59
61
 
60
- # Place constructor: Creates a new place in the current world.
62
+ # Constructor of a place: Creates a new place in the current world.
61
63
  #
62
64
  def Place( *ordered_args, **named_args, &block )
63
65
  fail ArgumentError, "If block is given, :guard named argument " +
@@ -68,24 +70,12 @@ module YPetri::Agent::PetriNetAspect
68
70
  world.Place.send( :new, *ordered_args, **named_args, &block )
69
71
  end
70
72
 
71
- # Transition constructor: Creates a new transition in the current world.
73
+ # Constructor of a transition: Creates a new transition in the current world.
72
74
  #
73
75
  def Transition( *ordered, **named, &block )
74
76
  world.Transition.send( :new, *ordered, **named, &block )
75
77
  end
76
78
 
77
- # Place constructor: Creates a new place in the current world.
78
- #
79
- def Place( *ordered_args, **named_args, &block )
80
- fail ArgumentError, "If block is given, :guard named argument " +
81
- "must not be given!" if named_args.has? :guard if block
82
- named_args.update( guard: block ) if block # use block as a guard
83
- named_args.may_have :default_marking, syn!: :m!
84
- named_args.may_have :marking, syn!: :m
85
- world.Place.send( :new, *ordered_args, **named_args, &block )
86
- end
87
-
88
-
89
79
  # Assignment transition constructor: Creates a new assignment transition in
90
80
  # the current world. Ordered arguments are collected as codomain. Domain key
91
81
  # (+:domain) is optional. Assignment closure must be supplied in a block.
data/lib/y_petri/agent.rb CHANGED
@@ -6,6 +6,19 @@ require_relative 'agent/petri_net_aspect'
6
6
  require_relative 'agent/simulation_aspect'
7
7
 
8
8
  # A dumb agent that represents and helps the user.
9
+ #
10
+ # An instance of this class (an agent) helps the user to interact
11
+ # with the world (YPetri::World instance) and the objects in it
12
+ # (Petri net places, transitions, nets etc.). In particular, this
13
+ # (YPetri::Agent) class is a convenient place to store various
14
+ # "shortcuts" meant to reduce the amount of typing the user has to
15
+ # do in order to construct and manipulate the world and its objects
16
+ # (such as "pl" instead of "place", "tr" instead of "transition" etc.)
17
+ # It would not be a good practice to encumber the classes where these
18
+ # methods are implemented with these semi-idiosyncratic shortcuts. This
19
+ # way, the implementation of the methods stays the concern of the mother
20
+ # classes, and Agent class is responsible for improving the ergonomy
21
+ # of their invocation.
9
22
  #
10
23
  class YPetri::Agent
11
24
  ★ PetriNetAspect # ★ means include
@@ -5,10 +5,57 @@
5
5
  module YPetri::Core::Timed::RungeKutta
6
6
  def delta Δt
7
7
  fail NotImplementedError, "RungeKutta not implemented yet!"
8
- # Of course, the following line is from Euler method.
9
- # The formula of Runge-Kutta is more complicated.
10
- #
11
- gradient * Δt
8
+
9
+ # f = simulation.method :gradient, parameter: :state
10
+ f = lambda { |mv| # mv is the marking vector of the free places
11
+ result = "make hash from free places of the simulation to zeros"
12
+ nonstoichiometric_transitions.each { |t|
13
+ places = t.codomain.free
14
+ inputs = mv.select( t.domain ) # this doesn't work this way
15
+ f = t.function
16
+ output = f.call( *inputs )
17
+ places.each { |p|
18
+ result[p] += output[p] # again, this doesn't work this way
19
+ }
20
+ }
21
+ stoichiometric_transitions.each { |t|
22
+ places = t.codomain.free
23
+ inputs = mv.select( t.domain ) # this doesn't work this way
24
+ f = t.function
25
+ output = f.call( *inputs ) * stoichiometry_vector # this doesn't work this way
26
+ places.each { |p|
27
+ result[p] += output[p]
28
+ }
29
+ }
30
+ # so you see how many selections one has to do if one doesn't
31
+ # construct a specific gadget for the operation, that's why
32
+ # I made those closures, unfortunately I didn't think about
33
+ # higher-order methods yet when making them, and maybe the core
34
+ # should own them instead of the simulation object
35
+
36
+ return result.to_vector # this doesn't work this way
37
+ }
38
+
39
+ # this is supposed to be Runge-Kutta 4th order
40
+ # but how do I get those in-between f values...
41
+
42
+ y = simulation.state # this must return a vector compatible with the one
43
+ # returned by f
44
+
45
+ k1 = f( y )
46
+ k2 = f( y + Δt / 2 * k1 )
47
+ k3 = f( y + Δt / 2 * k2 )
48
+ k4 = f( y + Δt * k3 )
49
+
50
+ rslt = Δt / 6 * ( k1 + 2 * k2 + 2 * k3 + k4 )
51
+ return rslt.to_the_kind_of_vector_that_delta_method_should_return
52
+ # which is the vector corresponding to the ordered list of
53
+ # free places of this simulation (here, every core either has a
54
+ # simulation assigned, or is parametrized with simulation, which
55
+ # might be dumb anyway, since core, by its name, should not be that
56
+ # heavily coupled with a simulation, but actually, atm, each core
57
+ # belongs to a specific simulation, so it's OK if it's parametrized
58
+ # with it for now
12
59
  end
13
60
  alias Δ delta
14
61
  end # YPetri::Core::Timed::RungeKutta
data/lib/y_petri/core.rb CHANGED
@@ -3,6 +3,29 @@
3
3
  # This class represents a simulator.
4
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
29
  require_relative 'core/timed'
7
30
  require_relative 'core/timeless'
8
31
  require_relative 'core/guarded'
data/lib/y_petri/place.rb CHANGED
@@ -47,20 +47,20 @@ class YPetri::Place
47
47
  # +Marking+ is a standard attribute of a Petri net place, +default_marking+
48
48
  # is marking upon calling the reset method. Default marking may also be used
49
49
  # as the initial value in the simulations involving the place in question.
50
- # +Quantum+ attribute is not in use presently. In the future, it will be used
51
- # to decide when to switch between continuous and discrete stochastic modeling
52
- # of a place value. +Guard+ means a restriction of the place marking. (For
53
- # example, the place could only admit non-negative numbers, or numbers smaller
54
- # than 1, or odd numbers etc.) Named argument :guard along with a block
55
- # supplied to the constructor allow one to specify a single marking guard
56
- # upon place initialization by putting an NL assertion (a string) under
57
- # +:guard+ argument, along with a block expressing the same meaning in code.
58
- # More guards, if necessary, can be specified later using +Place#guard+ method.
59
- #
60
- # If no guard block is supplied, default guards are constructed based on the
61
- # data type of the +:marking+ or +:default_marking+ argument. If it is wished
62
- # that the place has no guards whatsoever, +:guard+ argumend should be set to
63
- # _false_.
50
+ # +Quantum+ attribute is not in use presently. In the future, it might be used
51
+ # in deciding when to switch between continuous and discrete stochastic
52
+ # representation of the marking. +Guard+ is a restriction to the place's
53
+ # marking. (For example, the place could only admit non-negative numbers,
54
+ # or numbers smaller than 1, or odd numbers etc.) Any number of guards can
55
+ # be specified for a constructed place via +Place#guard+ method. For the cases
56
+ # when a place has only one guard, it is, as a syntactic sugar, possible to
57
+ # introduce exactly one guard already upon place initialization by supplying
58
+ # to this constructor, in addition to other parameters, a string expressing
59
+ # the guard as +:guard+ and a block expressing the same guard in code. If no
60
+ # guard block is supplied to this constructor, default guards are constructed
61
+ # based on the data type of the +:marking+ or +:default_marking+ argument. If
62
+ # it is wished that the place has no guards whatsoever, +:guard+ should be set
63
+ # to _false_.
64
64
  #
65
65
  def initialize guard: L!, **named_args, &block
66
66
  @upstream_arcs, @downstream_arcs, @guards = [], [], [] # init to empty
@@ -38,21 +38,21 @@ class YPetri::Simulation
38
38
  end
39
39
  end
40
40
 
41
- # Necessary to overcoming the protected character of the listed methods.
41
+ # Necessary to overcome the protected character of the listed methods.
42
42
  #
43
43
  [ :node,
44
44
  :place,
45
45
  :transition
46
46
  ].each { |sym| define_method sym do |e| simulation.send sym, e end }
47
47
 
48
- # Necessary to overcoming the protected character of the listed methods.
48
+ # Necessary to overcome the protected character of the listed methods.
49
49
  #
50
50
  [ :Nodes,
51
51
  :Places,
52
52
  :Transitions
53
53
  ].each { |sym| define_method sym do |array| simulation.send sym, array end }
54
54
 
55
- # Necessary to overcoming the protected character of the listed methods.
55
+ # Necessary to overcome the protected character of the listed methods.
56
56
  #
57
57
  [ :nodes,
58
58
  :places,
@@ -24,7 +24,7 @@ class YPetri::Simulation
24
24
 
25
25
  # Creates a subset of this collection (of the same class).
26
26
  #
27
- def subset nodes=nil, &block
27
+ def subset nodes=nil, &block # TODO: Rename to subarray
28
28
  if block_given? then
29
29
  fail ArgumentError, "If block given, arguments not allowed!" unless
30
30
  nodes.nil?
@@ -1,4 +1,4 @@
1
1
  module YPetri
2
- VERSION = "2.3.10"
2
+ VERSION = "2.3.11"
3
3
  DEBUG = false
4
4
  end
data/lib/y_petri/world.rb CHANGED
@@ -4,10 +4,11 @@ require_relative 'world/dependency'
4
4
  require_relative 'world/petri_net_aspect'
5
5
  require_relative 'world/simulation_aspect'
6
6
 
7
- # As the name suggests, represents the world. Holds places, transitions, nets
8
- # and other assets needed to set up and simulate Petri nets (settings, clamps,
9
- # initial markings etc.). Provides basic methods to do what is necessary. More
10
- # ergonomic and DSL-like methods are up to the YPetri::Agent.
7
+ # Represents YPetri workspace, but "world" is shorter. Its instance holds
8
+ # places, transitions, nets and other assets needed to perform the tasks
9
+ # of system specification and simulation (simulation settings, place clamps,
10
+ # initial markings etc.). Provides basic methods to do just what is necessary.
11
+ # More ergonomic and DSL-like methods may be defined in YPetri::Agent.
11
12
  #
12
13
  class YPetri::World
13
14
  ★ NameMagic # ★ means include
@@ -15,14 +16,17 @@ class YPetri::World
15
16
  ★ SimulationAspect
16
17
 
17
18
  def initialize
18
- # Parametrize the Place / Transition / Net classes.
19
+ # Set up parametrized subclasses of Place, Transition, Net.
19
20
  param_class!( { Place: YPetri::Place,
20
21
  Transition: YPetri::Transition,
21
22
  Net: YPetri::Net },
22
23
  with: { world: self } )
23
- # Make them their own namespaces.
24
+ # Invoke #namespace! method (from YSupport's NameMagic) on each of them.
25
+ # This causes each of them to do bookkeeping of their instances. This is
26
+ # because there is little point in keeping the objects from separate
27
+ # worlds (ie. workspaces) on the same list.
24
28
  [ Place(), Transition(), Net() ].each &:namespace!
25
- # And proceeed as usual.
29
+ # And proceed with initializations (if any) higher in the lookup chain.
26
30
  super
27
31
  end
28
32
  end
data/lib/y_petri.rb CHANGED
@@ -35,33 +35,37 @@ require_relative 'y_petri/core'
35
35
  require_relative 'y_petri/agent'
36
36
  require_relative 'y_petri/dsl'
37
37
 
38
- # YPetri is a domain model and a domain-specific language (DSL) for modelling
39
- # dynamical systems. (Industrial modellers use the term DSML domain specific
40
- # modelling language.) YPetri caters solely to the two main concerns of
41
- # modelling: model specification and simulation, excelling in the first one.
38
+ # YPetri is a domain-specific language (DSL) for modelling dynamical systems. It
39
+ # caters solely to the two main concerns of modelling: model specification and
40
+ # simulation.
42
41
  #
43
- # YPetri model specification is based on a Petri net paradigm. A Petri net (PN)
44
- # is a bipartite graph with two kinds of nodes: places and transitions. Places
45
- # are visualised as circles, transitions as rectangles. During PN execution
46
- # (simulation), transitions act upon places and change their marking by adding
47
- # / removing tokens as dictated by the prescription of their operation. For
48
- # classical PNs, transition action is a discrete stoichiometric addition /
49
- # subtraction of tokens to / from the connected places. However, many extended
50
- # PN types have been defined, where the transition action is determined by a
51
- # mathematical function attached to the transition. Such transitions are called
52
- # functional, and almost all YPetri transitions are of this type. Borrowing more
53
- # from the terminology of functions, YPetri defines keywords domain an codomain
54
- # for transitions in a way similar to the domain and codomain of functions.
42
+ # Model specification in YPetri is based on a Petri net. Classical Petri net
43
+ # (PN), originally described by Carl Adam Petri in 1962, is a bipartite graph
44
+ # with two kinds of nodes: places (circles) and transitions (rectangles),
45
+ # connected by arcs (lines). Places act as variables each place holds exactly
46
+ # one value ("marking"), a discrete number imagined as consisting of individual
47
+ # units ("tokens"). The action of transitions ("firing") is also discrete. Each
48
+ # time a transition fires, a fixed number of tokens is added/subtracted to the
49
+ # connected places. It turns out that classical PNs are very useful in describing
50
+ # things like industrial systems, production lines, and also basic chemical
51
+ # systems with a number of molecules is connected by stoichiometric reactions.
52
+ #
53
+ # YPetri allows specification of not just classical PNs, but also of many
54
+ # extended Petri net (XPN) types, which have been described since Petri's work.
55
+ # This is achieved by making YPetri transitions functional (mathematical
56
+ # functions in lambda notation can be attached to them), and allowing the
57
+ # possibility of transitions being defined as either timed and timeless, and as
58
+ # eithier nonstoichiometric and explicitly stoichiometric. Together, this makes 4
59
+ # types of functional transitions available in YPetri, which can be used to
60
+ # capture almost any type of XPN. In this way, YPetri can serve as a common
61
+ # platform for data exchange and cooperation between different XPN formalisms,
62
+ # without sacrificing the special qualities of XPNs described thus far.
63
+ #
64
+ # The basic simulation method is simple PN execution. In its course, transitions
65
+ # fire, and thereby change the places' marking by adding/removing tokens as
66
+ # dictated by their operating prescription. Other simulation methods become
67
+ # available for more specific net types, such as timed nets.
55
68
  #
56
- # Many extended PN types have been defined. YPetri implements a universal PN
57
- # abstraction designed to subsume and integrate the dichotomies of the common
58
- # extended PN types. YPetri unifies discrete and stochastic modelling of timed
59
- # transitions at the level of model specification in line with the present day
60
- # unifying Petri net frameworks. YPetri also integrates other dichotomies: timed
61
- # / timeless and stoichiometric / nonstoichiometric. The idea is to save the
62
- # Ruby-based modeller the work of researching different PN types and provide a
63
- # single abstraction and the DSL to rule them all.
64
- #
65
69
  module YPetri
66
70
  class << self
67
71
  def included( receiver )
data/test/core_test.rb ADDED
@@ -0,0 +1,26 @@
1
+ #! /usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ gem 'minitest'
5
+ require 'minitest/autorun'
6
+ require_relative '../lib/y_petri' # tested component itself
7
+ # require 'y_petri'
8
+ # require 'sy'
9
+
10
+ describe "use of timed and timeless core" do
11
+ before do
12
+ # set up a user of core, which will imitate some of the needs
13
+ # of the Simulation class, or be an actual instance of that class
14
+ end
15
+
16
+ it "should behave" do
17
+ # the core will be informed of the task required (bring the system
18
+ # whose specification is known to the core user mentioned above from
19
+ # some initial state to some next state by performing a requested
20
+ # something in a way requested by the user, where something can be
21
+ # eg. step forward, or run forward by a specified period of time or
22
+ # number of steps or until some other condition is fulfilled, or
23
+ # step backward, or even run backward, if the system allows such thing
24
+ # at all.
25
+ end
26
+ end
data/test/y_petri_test.rb CHANGED
@@ -11,6 +11,7 @@ require_relative '../lib/y_petri' # tested component itself
11
11
  require_relative 'place_test'
12
12
  require_relative 'transition_test'
13
13
  require_relative 'net_test'
14
+ require_relative 'core_test'
14
15
  require_relative 'simulation_test'
15
16
  require_relative 'world_test'
16
17
  require_relative 'agent_test'
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.10
4
+ version: 2.3.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - boris
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-08 00:00:00.000000000 Z
11
+ date: 2015-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -248,6 +248,7 @@ files:
248
248
  - test/acceptance/visualization_test.rb
249
249
  - test/acceptance_tests.rb
250
250
  - test/agent_test.rb
251
+ - test/core_test.rb
251
252
  - test/examples/demonstrator.rb
252
253
  - test/examples/demonstrator_2.rb
253
254
  - test/examples/demonstrator_4.rb
@@ -299,6 +300,7 @@ test_files:
299
300
  - test/acceptance/visualization_test.rb
300
301
  - test/acceptance_tests.rb
301
302
  - test/agent_test.rb
303
+ - test/core_test.rb
302
304
  - test/examples/demonstrator.rb
303
305
  - test/examples/demonstrator_2.rb
304
306
  - test/examples/demonstrator_4.rb