y_petri 2.0.3 → 2.0.7

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.
data/lib/y_petri/place.rb CHANGED
@@ -1,87 +1,103 @@
1
1
  # -*- coding: utf-8 -*-
2
- # This class represents Petri net places.
2
+
3
+ require_relative 'dependency_injection'
4
+ require_relative 'place/guard'
5
+ require_relative 'place/arcs'
6
+
7
+ # Represents a Petri net place.
3
8
  #
4
9
  class YPetri::Place
5
- USE_QUANTUM = false
6
10
  include NameMagic
11
+ include YPetri::DependencyInjection
7
12
 
8
13
  attr_reader :quantum
14
+ attr_reader :guards
9
15
  attr_accessor :default_marking
10
- attr_accessor :marking # instance-attached marking
11
- alias :value :marking
12
- alias :m :marking
13
-
14
- # Alias for #marking=
15
- #
16
- def value=( marking ); self.marking = marking end
17
-
18
- # Alias for #marking=
19
- #
20
- def m=( marking ); self.marking = marking end
21
-
22
- # Transitions that can directly add/remove tokens from this place.
23
- # It is aliased as #upstream_transitions and #ϝ. (ϝ (Greek digamma) looks
24
- # like "function", which we know from spreadsheet software: A collection
25
- # of transitions directly affecting marking of this place.)
26
- #
27
- attr_reader :upstream_arcs
28
- alias :upstream_transitions :upstream_arcs
29
- alias :ϝ :upstream_arcs
30
-
31
- # Transitions whose action directly depends on this place. Aliased
32
- # as #downstream_transitions.
33
- #
34
- attr_reader :downstream_arcs
35
- alias :downstream_transitions :downstream_arcs
16
+ attr_writer :marking
36
17
 
37
18
  # Named parameters supplied upon place initialization may include:
38
19
  #
39
- # * :marking (alias :m)
40
- # * :default_marking (alias :dflt_m or :m!)
41
- # * :quantum (alias :q)
42
- #
43
- # While 'marking' is a standard Petri net concept, and default marking
44
- # is self-explanatory, place quantum is the concept by which YPetri
45
- # reconciles with letter H in the abbreviation HFPN. YPetri places are
46
- # always considered discrete, and it is true insomuch, as their marking
47
- # is represented by a finite-digit number. The place quantum feature is
48
- # not supported yet, but in future, it should enable smooth transition
49
- # between continuous and stochastic modes of simulation.
50
- #
51
- def initialize *aa; oo = aa.extract_options!
52
- # set domain and codomain of the place empty
53
- @upstream_arcs = []
54
- @downstream_arcs = []
55
- @quantum = oo.may_have( :quantum, syn!: :q ) || 1
56
- @default_marking = oo.may_have( :default_marking, syn!: [ :dflt_m, :m! ] )
57
- @marking = oo.may_have( :marking, syn!: :m ) || @default_marking
20
+ # * :marking
21
+ # * :default_marking
22
+ # * :quantum
23
+ # * :guard
24
+ #
25
+ # Those familiar with Petri nets need no introduction into _marking_
26
+ # attribute of a Petri net place. However, _quantum_ is a relatively uncommon
27
+ # concept in the context of Petri nets. +YPetri+ introduces quantum as a
28
+ # replacement for the hybrid-ness of Hybrid Functional Petri Nets (HFPNs).
29
+ # Formally, +YPetri+ is a discrete functional Petri net (FPN). The quantum
30
+ # is a numeric representation of a token: The smallest number by which the
31
+ # numeric representation of the place's marking can change. This is intended
32
+ # to enable smooth transition between continuous and stochastic simulation
33
+ # depending on pre-defined statistical settings.
34
+ #
35
+ # The :guard named argument and optional block specification allows to specify
36
+ # one marking guard already upon place initialization. This is done by putting
37
+ # the NL assertion string of the guard under the :guard named argument, and
38
+ # supplying the guard block to the constructor. More guards can be defined
39
+ # later for the place using its +#guard+ method.
40
+ #
41
+ # If no guard block is supplied, default guards are constructed based on the
42
+ # type of the marking or default marking supplied upon initialization. For
43
+ # numeric marking except complex numbers, the default type guard allows all
44
+ # +Numeric+ types except complex numbers, and the default value guard prohibits
45
+ # negative values. For all other classes, there is just one guard enforcing
46
+ # the class compliance of the marking.
47
+ #
48
+ # To construct a place with no guards whatsoever, set :guard named argument
49
+ # to _false_.
50
+ #
51
+ def initialize quantum: 1,
52
+ default_marking: nil,
53
+ marking: nil,
54
+ guard: L!,
55
+ &block
56
+ @upstream_arcs, @downstream_arcs, @guards = [], [], [] # init to empty
57
+ @quantum, @default_marking = quantum, default_marking
58
+ @marking = marking || default_marking
59
+
60
+ # Check in :guard named argument and &block.
61
+ if guard.ℓ? then # guard NL assertion not given, use block or default guards
62
+ block ? guard( &block ) : add_default_guards!( @marking )
63
+ elsif guard then # guard NL assertion given
64
+ fail ArgumentError, "No guard block given!" unless block
65
+ guard( guard, &block )
66
+ else
67
+ fail ArgumentError, "Block given, but :guard set to falsey!" if block
68
+ end
69
+ end
70
+
71
+ # Getter of +@marking+ attribute.
72
+ #
73
+ def m; @marking end
74
+ alias value m
75
+
76
+ # This method, which acts as a simple getter of +@marking+ attribute if no
77
+ # block is supplied to it, is overloaded to act as +#guard+ method frontend
78
+ # if a guard block is supplied. The reason is because this
79
+ #
80
+ # marking "should be a number" do |m| fail unless m.is_a? Numeric end
81
+ #
82
+ # reads better than
83
+ #
84
+ # guard "should be a number" do |m| fail unless m.is_a? Numeric end
85
+ #
86
+ # {See #guard method}[rdoc-ref:YPetri::guard] for more information.
87
+ #
88
+ def marking *args, &block
89
+ return @marking if args.empty?
90
+ fail ArgumentError, "Too many arguments!" if args.size > 1
91
+ guard args[0], &block
58
92
  end
59
93
 
60
- # Returns an array of all the transitions connected to the place.
61
- #
62
- def arcs
63
- upstream_arcs | downstream_arcs
64
- end
65
-
66
- # Returns the union of domains of the transitions associated
67
- # with the upstream arcs of this place.
94
+ # Alias for #marking=
68
95
  #
69
- def precedents
70
- upstream_transitions
71
- .map( &:upstream_places )
72
- .reduce( [], :| )
73
- end
74
- alias :upstream_places :precedents
96
+ def value=( marking ); self.marking = marking end
75
97
 
76
- # Returns the union of codomains of the transitions associated
77
- # with the downstream arcs originating from this place.
98
+ # Alias for #marking=
78
99
  #
79
- def dependents
80
- downstream_transitions
81
- .map( &:downstream_places )
82
- .reduce( [], :| )
83
- end
84
- alias :downstream_places :dependents
100
+ def m=( marking ); self.marking = marking end
85
101
 
86
102
  # Adds tokens to the place.
87
103
  #
@@ -91,7 +107,7 @@ class YPetri::Place
91
107
 
92
108
  # Subtracts tokens from the place.
93
109
  #
94
- def subtract( amount_of_tokens)
110
+ def subtract( amount_of_tokens )
95
111
  @marking -= amount_of_tokens
96
112
  end
97
113
 
@@ -101,87 +117,28 @@ class YPetri::Place
101
117
  @marking = @default_marking
102
118
  end
103
119
 
104
- # Firing of upstream transitions regardless of cocking. (To #fire
105
- # transitions, they have to be cocked with #cock method; the firing
106
- # methods with exclamation marks disregard cocking.)
107
- #
108
- def fire_upstream!
109
- @upstream_arcs.each &:fire!
110
- end
111
- alias :fire! :fire_upstream!
112
-
113
- # Fires whole upstream portion of the net.
114
- #
115
- def fire_upstream_recursively
116
- # LATER: so far, implemented without concerns about infinite loops
117
- # LATER: This as a global hash { place => fire_list }
118
- @upstream_arcs.each &:fire_upstream_recursively
119
- end
120
- alias :fire_upstream! :fire_upstream_recursively
121
-
122
- # Firing of downstream transitions regardless of cocking. (To #fire
123
- # transitions, they have to be cocked with #cock method; the firing
124
- # methods with exclamation marks disregard cocking.)
125
- #
126
- def fire_downstream!
127
- @downstream_arcs.each &:fire!
128
- end
129
-
130
- # Fires whole downstream portion of the net.
131
- #
132
- def fire_downstream_recursively
133
- # LATER: so far, implemented withoud concerns about infinite loops
134
- # LATER: This as a global hash { place => fire_list }
135
- @downstream_arcs.each &:fire_downstream_recursively
136
- end
137
- alias :fire_downstream! :fire_downstream_recursively
138
-
139
120
  # Produces the inspect string of the place.
140
121
  #
141
122
  def inspect
142
123
  n, m, d, q = instance_description_strings
143
- "#<Place: #{ ( USE_QUANTUM ? [n, m, d, q] : [n, m, d] ).join ', ' } >"
124
+ "#<Place: #{ ( [n, m, d, q].compact ).join ', ' }>"
144
125
  end
145
126
 
146
127
  # Returns a string briefly describing the place.
147
128
  #
148
129
  def to_s
149
130
  n, m = name, marking
150
- "#{n.nil? ? 'Place' : n}[ #{m.nil? ? 'nil' : m} ]"
131
+ "#{n.nil? ? 'Place' : n}[#{m.nil? ? 'nil' : m}]"
151
132
  end
152
133
 
153
134
  private
154
135
 
155
- # Makes the place notice an upstream transition;
156
- # to be called from the connecting transitions.
157
- def register_upstream_transition( transition )
158
- @upstream_arcs << transition
159
- end
160
-
161
- # Makes the place notice a downstream transition;
162
- # to be called from the connecting transitions.
163
- def register_downstream_transition( transition )
164
- @downstream_arcs << transition
165
- end
166
-
167
136
  def instance_description_strings
168
137
  m, n, d, q = marking, name, default_marking, quantum
169
138
  nς = "name: #{n.nil? ? '∅' : n}"
170
139
  mς = "marking: #{m.nil? ? 'nil' : m}"
171
140
  dς = "default_marking: #{d.nil? ? '∅' : d}"
172
- qς = "quantum: #{q.nil? ? '∅' : q}"
141
+ qς = q == 1 ? nil : "quantum: #{q.nil? ? '∅' : q}"
173
142
  return nς, mς, dς, qς
174
143
  end
175
-
176
- # Place, Transition, Net class
177
- #
178
- def Place; ::YPetri::Place end
179
- def Transition; ::YPetri::Transition end
180
- def Net; ::YPetri::Net end
181
-
182
- # Instance identification methods.
183
- #
184
- def place( which ); Place().instance( which ) end
185
- def transition( which ); Transition().instance( which ) end
186
- def net( which ); Net().instance( which ) end
187
144
  end # class YPetri::Place