y_petri 2.3.10 → 2.3.11

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