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.
- checksums.yaml +4 -4
- data/lib/y_petri/dependency_injection.rb +45 -0
- data/lib/y_petri/manipulator/petri_net_related_methods.rb +26 -7
- data/lib/y_petri/manipulator/simulation_related_methods.rb +4 -4
- data/lib/y_petri/net.rb +30 -21
- data/lib/y_petri/place/arcs.rb +96 -0
- data/lib/y_petri/place/guard.rb +122 -0
- data/lib/y_petri/place.rb +89 -132
- data/lib/y_petri/simulation.rb +191 -168
- data/lib/y_petri/timed_simulation.rb +29 -20
- data/lib/y_petri/transition/arcs.rb +51 -0
- data/lib/y_petri/transition/cocking.rb +32 -0
- data/lib/y_petri/transition/constructor_syntax.rb +378 -0
- data/lib/y_petri/transition.rb +391 -831
- data/lib/y_petri/version.rb +1 -1
- data/lib/y_petri/workspace/parametrized_subclassing.rb +8 -13
- data/lib/y_petri/workspace/simulation_related_methods.rb +13 -11
- data/lib/y_petri.rb +8 -3
- data/test/place_test.rb +83 -0
- data/test/transition_test.rb +325 -0
- data/test/y_petri_test.rb +15 -410
- metadata +12 -2
data/lib/y_petri/place.rb
CHANGED
@@ -1,87 +1,103 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
|
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
|
-
|
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
|
40
|
-
# * :default_marking
|
41
|
-
# * :quantum
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
#
|
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
|
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
|
-
#
|
77
|
-
# with the downstream arcs originating from this place.
|
98
|
+
# Alias for #marking=
|
78
99
|
#
|
79
|
-
def
|
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: #{ (
|
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}[
|
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
|