y_petri 2.0.3 → 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|