y_petri 2.2.4 → 2.3.2
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/LICENSE.txt +675 -0
- data/README.md +6 -3
- data/Rakefile +1 -1
- data/lib/y_petri/agent/{petri_net_related.rb → petri_net_aspect.rb} +34 -10
- data/lib/y_petri/agent/{simulation_related.rb → simulation_aspect.rb} +49 -34
- data/lib/y_petri/agent.rb +5 -5
- data/lib/y_petri/core/guarded.rb +24 -0
- data/lib/y_petri/core/timed/euler.rb +4 -8
- data/lib/y_petri/core/timed/gillespie.rb +11 -17
- data/lib/y_petri/core/timed/methods.rb +23 -0
- data/lib/y_petri/core/timed/pseudo_euler.rb +10 -13
- data/lib/y_petri/core/timed/quasi_euler.rb +9 -8
- data/lib/y_petri/core/timed/runge_kutta.rb +10 -18
- data/lib/y_petri/core/timed.rb +6 -14
- data/lib/y_petri/core/timeless/methods.rb +15 -0
- data/lib/y_petri/core/timeless/pseudo_euler.rb +4 -8
- data/lib/y_petri/core/timeless.rb +9 -4
- data/lib/y_petri/core.rb +44 -42
- data/lib/y_petri/net/data_set.rb +246 -142
- data/lib/y_petri/net/node_access.rb +282 -0
- data/lib/y_petri/net/own_state.rb +14 -4
- data/lib/y_petri/net/state/feature/assignment.rb +123 -0
- data/lib/y_petri/net/state/feature/delta.rb +55 -35
- data/lib/y_petri/net/state/feature/firing.rb +68 -25
- data/lib/y_petri/net/state/feature/flux.rb +9 -2
- data/lib/y_petri/net/state/feature/gradient.rb +36 -19
- data/lib/y_petri/net/state/feature/marking.rb +10 -5
- data/lib/y_petri/net/state/feature.rb +105 -11
- data/lib/y_petri/net/state/features/record.rb +144 -99
- data/lib/y_petri/net/state/features.rb +327 -200
- data/lib/y_petri/net/state.rb +48 -82
- data/lib/y_petri/net/visualization.rb +1 -1
- data/lib/y_petri/net.rb +62 -47
- data/lib/y_petri/place/arcs.rb +44 -0
- data/lib/y_petri/place/features.rb +115 -0
- data/lib/y_petri/place.rb +62 -29
- data/lib/y_petri/simulation/dependency.rb +31 -67
- data/lib/y_petri/simulation/feature_set.rb +1 -1
- data/lib/y_petri/simulation/initial_marking/access.rb +42 -26
- data/lib/y_petri/simulation/marking_clamps/access.rb +22 -17
- data/lib/y_petri/simulation/marking_clamps.rb +0 -2
- data/lib/y_petri/simulation/marking_vector/access.rb +102 -40
- data/lib/y_petri/simulation/marking_vector.rb +35 -37
- data/lib/y_petri/simulation/matrix.rb +1 -1
- data/lib/y_petri/simulation/node_representation.rb +25 -0
- data/lib/y_petri/simulation/nodes/access.rb +78 -0
- data/lib/y_petri/simulation/{elements.rb → nodes.rb} +14 -13
- data/lib/y_petri/simulation/place_mapping.rb +2 -2
- data/lib/y_petri/simulation/place_representation.rb +8 -7
- data/lib/y_petri/simulation/places/access.rb +89 -70
- data/lib/y_petri/simulation/places/free.rb +1 -1
- data/lib/y_petri/simulation/places/types.rb +20 -22
- data/lib/y_petri/simulation/places.rb +23 -18
- data/lib/y_petri/simulation/recorder.rb +23 -18
- data/lib/y_petri/simulation/timed/recorder.rb +19 -11
- data/lib/y_petri/simulation/timed.rb +93 -29
- data/lib/y_petri/simulation/timeless/recorder.rb +11 -6
- data/lib/y_petri/simulation/timeless.rb +13 -3
- data/lib/y_petri/simulation/transition_representation/A.rb +24 -4
- data/lib/y_petri/simulation/transition_representation/S.rb +11 -1
- data/lib/y_petri/simulation/transition_representation/T.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/Ts.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/a.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/s.rb +12 -1
- data/lib/y_petri/simulation/transition_representation/t.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/tS.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/ts.rb +1 -1
- data/lib/y_petri/simulation/transition_representation/types.rb +1 -1
- data/lib/y_petri/simulation/transition_representation.rb +4 -11
- data/lib/y_petri/simulation/transitions/A.rb +17 -2
- data/lib/y_petri/simulation/transitions/S.rb +1 -1
- data/lib/y_petri/simulation/transitions/T.rb +1 -1
- data/lib/y_petri/simulation/transitions/Ts.rb +6 -5
- data/lib/y_petri/simulation/transitions/a.rb +1 -1
- data/lib/y_petri/simulation/transitions/access.rb +195 -168
- data/lib/y_petri/simulation/transitions/s.rb +1 -1
- data/lib/y_petri/simulation/transitions/t.rb +1 -1
- data/lib/y_petri/simulation/transitions/tS.rb +1 -1
- data/lib/y_petri/simulation/transitions/ts.rb +1 -1
- data/lib/y_petri/simulation/transitions/types.rb +1 -1
- data/lib/y_petri/simulation/transitions.rb +5 -7
- data/lib/y_petri/simulation.rb +84 -90
- data/lib/y_petri/transition/A.rb +8 -2
- data/lib/y_petri/transition/T.rb +25 -2
- data/lib/y_petri/transition/arcs.rb +19 -3
- data/lib/y_petri/transition/construction_convenience.rb +11 -10
- data/lib/y_petri/transition/t.rb +14 -1
- data/lib/y_petri/transition/types.rb +6 -1
- data/lib/y_petri/transition.rb +9 -12
- data/lib/y_petri/version.rb +1 -1
- data/lib/y_petri/world/dependency.rb +3 -3
- data/lib/y_petri/world/{petri_net_related.rb → petri_net_aspect.rb} +4 -4
- data/lib/y_petri/world/simulation_aspect.rb +352 -0
- data/lib/y_petri/world.rb +4 -4
- data/lib/y_petri.rb +1 -1
- data/test/agent_test.rb +2 -1
- data/test/examples/demonstrator.rb +4 -1
- data/test/examples/demonstrator_2.rb +5 -0
- data/test/examples/demonstrator_4.rb +6 -5
- data/test/examples/example_2.rb +2 -0
- data/test/examples/manual_examples.rb +4 -4
- data/test/net_test.rb +457 -54
- data/test/place_test.rb +11 -7
- data/test/simulation_test.rb +358 -331
- data/test/transition_test.rb +11 -10
- data/test/world_test.rb +2 -0
- data/test/y_petri_test.rb +2 -1
- data/y_petri.gemspec +24 -18
- metadata +71 -17
- data/LICENSE +0 -22
- data/lib/y_petri/net/element_access.rb +0 -239
- data/lib/y_petri/simulation/element_representation.rb +0 -20
- data/lib/y_petri/simulation/elements/access.rb +0 -57
- data/lib/y_petri/transition/type.rb +0 -103
- data/lib/y_petri/transition/type_information.rb +0 -103
- data/lib/y_petri/world/simulation_related.rb +0 -176
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
# Firing of
|
3
|
+
# Firing of an S transition. (Firing is only defined on S transitions, whose
|
4
|
+
# action can be computed as firing * stoichometry_vector_of_the_transition.)
|
4
5
|
#
|
5
6
|
class YPetri::Net::State::Feature::Firing < YPetri::Net::State::Feature
|
6
7
|
attr_reader :transition
|
@@ -10,25 +11,27 @@ class YPetri::Net::State::Feature::Firing < YPetri::Net::State::Feature
|
|
10
11
|
#
|
11
12
|
def parametrize *args
|
12
13
|
Class.instance_method( :parametrize ).bind( self ).( *args ).tap do |ç|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
14
|
+
# First, prepare the hash of instances.
|
15
|
+
hsh = Hash.new do |hsh, id|
|
16
|
+
case id
|
17
|
+
when self then # missing key "id" is a Firing instance
|
18
|
+
hsh[ id.transition ]
|
19
|
+
when ç.net.Transition then
|
20
|
+
t = begin
|
21
|
+
ç.net.S_transitions( id ).first
|
22
|
+
rescue TypeError => err
|
23
|
+
msg = "Transition #{id} not " +
|
24
|
+
"recognized as tS transition in " +
|
25
|
+
"net #{ç.net}! (%s)"
|
26
|
+
raise TypeError, msg % err
|
27
|
+
end
|
28
|
+
hsh[ id ] = t.timed? ? ç.timed( t ) : ç.timeless( t )
|
29
|
+
else
|
30
|
+
hsh[ ç.net.transition( id ) ]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# And then, assign it to the :@instances variable.
|
34
|
+
ç.instance_variable_set :@instances, hsh
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
@@ -45,6 +48,21 @@ class YPetri::Net::State::Feature::Firing < YPetri::Net::State::Feature
|
|
45
48
|
def of id
|
46
49
|
new id
|
47
50
|
end
|
51
|
+
|
52
|
+
# Expects a single timed transition and constructs a timed firing feature.
|
53
|
+
#
|
54
|
+
def timed id
|
55
|
+
__new__( net.T_tt( id ).first )
|
56
|
+
.tap { |i| i.instance_variable_set :@timed, true }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Expects a single timeless transition and constructs a timeless firing
|
60
|
+
# feature.
|
61
|
+
#
|
62
|
+
def timeless id
|
63
|
+
__new__( net.t_tt( id ).first )
|
64
|
+
.tap { |i| i.instance_variable_set :@timed, false }
|
65
|
+
end
|
48
66
|
end
|
49
67
|
|
50
68
|
# The constructor of a marking feature takes exactly one argument (transition
|
@@ -54,22 +72,40 @@ class YPetri::Net::State::Feature::Firing < YPetri::Net::State::Feature
|
|
54
72
|
@transition = net.transition( transition )
|
55
73
|
end
|
56
74
|
|
57
|
-
# Extracts the
|
58
|
-
#
|
75
|
+
# Extracts the value of this feature from the target (eg. a simulation).
|
76
|
+
# If the receiver firing feature is timed, this method requires an additional
|
77
|
+
# named argument +:delta_time+, alias +:Δt+.
|
59
78
|
#
|
60
|
-
def extract_from arg, **
|
79
|
+
def extract_from arg, **named_args
|
61
80
|
case arg
|
62
81
|
when YPetri::Simulation then
|
63
|
-
|
82
|
+
if timed? then
|
83
|
+
arg.send( :TS_transitions, transition ).first
|
84
|
+
.firing( named_args.must_have :delta_time, syn!: :Δt )
|
85
|
+
else
|
86
|
+
arg.send( :tS_transitions, transition ).first.firing
|
87
|
+
end
|
64
88
|
else
|
65
89
|
fail TypeError, "Argument type not supported!"
|
66
90
|
end
|
67
91
|
end
|
68
92
|
|
93
|
+
# Is the delta feature timed?
|
94
|
+
#
|
95
|
+
def timed?
|
96
|
+
@timed
|
97
|
+
end
|
98
|
+
|
99
|
+
# Opposite of +#timed?+.
|
100
|
+
#
|
101
|
+
def timeless?
|
102
|
+
! timed?
|
103
|
+
end
|
104
|
+
|
69
105
|
# Type of this feature.
|
70
106
|
#
|
71
107
|
def type
|
72
|
-
:
|
108
|
+
:firing
|
73
109
|
end
|
74
110
|
|
75
111
|
# A string briefly describing the firing feature.
|
@@ -89,4 +125,11 @@ class YPetri::Net::State::Feature::Firing < YPetri::Net::State::Feature
|
|
89
125
|
def inspect
|
90
126
|
"<Feature::Firing of #{transition.name ? transition.name : transition}>"
|
91
127
|
end
|
128
|
+
|
129
|
+
# Firing features are equal if they are of equal PS and refer
|
130
|
+
# to the same transition.
|
131
|
+
#
|
132
|
+
def == other
|
133
|
+
other.is_a? net.State.Feature.Firing and transition == other.transition
|
134
|
+
end
|
92
135
|
end # YPetri::Net::State::Feature::Firing
|
@@ -17,7 +17,7 @@ class YPetri::Net::State::Feature::Flux < YPetri::Net::State::Feature
|
|
17
17
|
hsh[ id.transition ]
|
18
18
|
when ç.net.Transition then
|
19
19
|
t = begin
|
20
|
-
ç.net.TS_transitions(
|
20
|
+
ç.net.TS_transitions( id ).first
|
21
21
|
rescue TypeError => err
|
22
22
|
msg = "Transition #{id} not " +
|
23
23
|
"recognized as TS transition in " +
|
@@ -60,7 +60,7 @@ class YPetri::Net::State::Feature::Flux < YPetri::Net::State::Feature
|
|
60
60
|
def extract_from arg, **nn
|
61
61
|
case arg
|
62
62
|
when YPetri::Simulation then
|
63
|
-
arg.send( :TS_transitions,
|
63
|
+
arg.send( :TS_transitions, transition ).first.flux
|
64
64
|
else
|
65
65
|
fail TypeError, "Argument type not supported!"
|
66
66
|
end
|
@@ -89,4 +89,11 @@ class YPetri::Net::State::Feature::Flux < YPetri::Net::State::Feature
|
|
89
89
|
def inspect
|
90
90
|
"<Feature::Flux of #{transition.name ? transition.name : transition}>"
|
91
91
|
end
|
92
|
+
|
93
|
+
# Flux features are equal if they are of equal PS and refer to the
|
94
|
+
# same transition.
|
95
|
+
#
|
96
|
+
def == other
|
97
|
+
other.is_a? net.State.Feature.Flux and transition == other.transition
|
98
|
+
end
|
92
99
|
end # class YPetri::Net::State::Feature::Flux
|
@@ -4,6 +4,7 @@
|
|
4
4
|
#
|
5
5
|
class YPetri::Net::State::Feature::Gradient < YPetri::Net::State::Feature
|
6
6
|
attr_reader :place, :transitions
|
7
|
+
alias tt transitions
|
7
8
|
|
8
9
|
class << self
|
9
10
|
# Customization of the Class#parametrize method.
|
@@ -16,25 +17,28 @@ class YPetri::Net::State::Feature::Gradient < YPetri::Net::State::Feature
|
|
16
17
|
ꜧ[ [ id.place, transitions: id.transitions.sort_by( &:object_id ) ] ]
|
17
18
|
else
|
18
19
|
p = id.fetch( 0 )
|
19
|
-
tt = id
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
20
|
+
tt = id.fetch( 1 ).fetch( :transitions )
|
21
|
+
tt_array = Array( tt )
|
22
|
+
if tt == tt_array then
|
23
|
+
if p.is_a? ç.net.Place and tt.all? { |t| t.is_a? ç.net.Transition }
|
24
|
+
tt_sorted = tt.sort_by &:object_id
|
25
|
+
if tt == tt_sorted then
|
26
|
+
tt = begin
|
27
|
+
ç.net.T_Transitions( tt )
|
28
|
+
rescue TypeError => err
|
29
|
+
msg = "Transitions #{tt} not recognized as T " +
|
30
|
+
"transitions in net #{ç.net}! (%s)"
|
31
|
+
raise TypeError, msg % err
|
32
|
+
end
|
33
|
+
ꜧ[ id ] = ç.__new__( *id )
|
34
|
+
else
|
35
|
+
ꜧ[ [ p, transitions: tt.sort_by( &:object_id ) ] ]
|
36
|
+
end
|
33
37
|
else
|
34
|
-
ꜧ[ [ p, transitions:
|
38
|
+
ꜧ[ [ ç.net.place( p ), transitions: ç.net.Transitions( tt ) ] ]
|
35
39
|
end
|
36
40
|
else
|
37
|
-
ꜧ[ [
|
41
|
+
ꜧ[ [ p, transitions: tt_array ] ]
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
@@ -63,7 +67,7 @@ class YPetri::Net::State::Feature::Gradient < YPetri::Net::State::Feature
|
|
63
67
|
#
|
64
68
|
def initialize *id
|
65
69
|
@place = net.place id.fetch( 0 )
|
66
|
-
@transitions = net.
|
70
|
+
@transitions = net.Transitions id.fetch( 1 ).fetch( :transitions )
|
67
71
|
end
|
68
72
|
|
69
73
|
# Extracts the receiver gradient feature from the argument. This can be
|
@@ -72,7 +76,7 @@ class YPetri::Net::State::Feature::Gradient < YPetri::Net::State::Feature
|
|
72
76
|
def extract_from arg, **nn
|
73
77
|
case arg
|
74
78
|
when YPetri::Simulation then
|
75
|
-
arg.send( :
|
79
|
+
arg.send( :T_Transitions, transitions ).gradient.fetch( place )
|
76
80
|
else
|
77
81
|
fail TypeError, "Argument type not supported!"
|
78
82
|
end
|
@@ -93,7 +97,12 @@ class YPetri::Net::State::Feature::Gradient < YPetri::Net::State::Feature
|
|
93
97
|
# Label for the gradient feature (to use in graphics etc.)
|
94
98
|
#
|
95
99
|
def label
|
96
|
-
"∂:#{place.name}
|
100
|
+
"∂:#{place.name}:%s" %
|
101
|
+
if transitions.size == 1 then
|
102
|
+
transitions.first.name || transitions.first
|
103
|
+
else
|
104
|
+
"#{transitions.size}tt"
|
105
|
+
end
|
97
106
|
end
|
98
107
|
|
99
108
|
# Inspect string of the gradient feature.
|
@@ -102,4 +111,12 @@ class YPetri::Net::State::Feature::Gradient < YPetri::Net::State::Feature
|
|
102
111
|
"<Feature::Gradient ∂:#{place.name || place}:[%s]>" %
|
103
112
|
transitions.names( true ).join( ', ' )
|
104
113
|
end
|
114
|
+
|
115
|
+
# Gradient features are equal if they are of equal PS and refer to
|
116
|
+
# the same place and transition set.
|
117
|
+
#
|
118
|
+
def == other
|
119
|
+
other.is_a? net.State.Feature.Gradient and
|
120
|
+
place == other.place && transitions == other.transitions
|
121
|
+
end
|
105
122
|
end # class YPetri::Net::State::Feature::Gradient
|
@@ -19,9 +19,8 @@ class YPetri::Net::State::Feature::Marking < YPetri::Net::State::Feature
|
|
19
19
|
p = begin
|
20
20
|
ç.net.place id
|
21
21
|
rescue TypeError => err
|
22
|
-
|
23
|
-
"
|
24
|
-
raise TypeError, msg % err
|
22
|
+
raise TypeError, "Place #{id} not " +
|
23
|
+
"present in net #{ç.net}! (#{err})"
|
25
24
|
end
|
26
25
|
hsh[ id ] = ç.__new__( id )
|
27
26
|
else
|
@@ -59,8 +58,7 @@ class YPetri::Net::State::Feature::Marking < YPetri::Net::State::Feature
|
|
59
58
|
def extract_from arg, **nn
|
60
59
|
case arg
|
61
60
|
when YPetri::Simulation then
|
62
|
-
|
63
|
-
arg.m( [ place ] ).first
|
61
|
+
arg.m( place ).first
|
64
62
|
else
|
65
63
|
fail TypeError, "Argument type not supported!"
|
66
64
|
end
|
@@ -89,4 +87,11 @@ class YPetri::Net::State::Feature::Marking < YPetri::Net::State::Feature
|
|
89
87
|
def inspect
|
90
88
|
"<Feature::Marking of #{place.name ? place.name : place}>"
|
91
89
|
end
|
90
|
+
|
91
|
+
# Marking features are equal if they are of equal PS and refer
|
92
|
+
# to the same place.
|
93
|
+
#
|
94
|
+
def == other
|
95
|
+
other.is_a? net.State.Feature.Marking and place == other.place
|
96
|
+
end
|
92
97
|
end # YPetri::Net::State::Feature::Marking
|
@@ -8,6 +8,7 @@ class YPetri::Net::State::Feature
|
|
8
8
|
require_relative 'feature/gradient'
|
9
9
|
require_relative 'feature/flux'
|
10
10
|
require_relative 'feature/delta'
|
11
|
+
require_relative 'feature/assignment'
|
11
12
|
|
12
13
|
class << self
|
13
14
|
def parametrize parameters
|
@@ -21,28 +22,40 @@ class YPetri::Net::State::Feature
|
|
21
22
|
ç.instance_variable_set :@Gradient, Gradient.parametrize( State: sç )
|
22
23
|
ç.instance_variable_set :@Flux, Flux.parametrize( State: sç )
|
23
24
|
ç.instance_variable_set :@Delta, Delta.parametrize( State: sç )
|
25
|
+
ç.instance_variable_set :@Assignment, Assignment.parametrize( State: sç )
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
27
|
-
delegate :net,
|
28
|
-
to: "State()"
|
29
|
+
delegate :net, to: "State()"
|
29
30
|
|
31
|
+
# Marking feature constructor. Takes a single place identifying argument.
|
32
|
+
#
|
30
33
|
def Marking id=L!
|
31
34
|
return @Marking if id.local_object?
|
32
35
|
case id
|
33
36
|
when Marking() then id
|
34
37
|
when Marking then Marking().of( id.place )
|
35
|
-
else Marking().of( id ) end # assume
|
38
|
+
else Marking().of( id ) end # assume place
|
36
39
|
end
|
37
40
|
|
41
|
+
# Firing feature constructor. Takes a single argument, which must identify
|
42
|
+
# an S transition (nonstoichiometric transitions don't have firing, though
|
43
|
+
# they do have action.)
|
44
|
+
#
|
38
45
|
def Firing id=L!
|
39
46
|
return @Firing if id.local_object?
|
40
47
|
case id
|
41
48
|
when Firing() then id
|
42
49
|
when Firing then Firing().of( id.transition )
|
43
|
-
else Firing().of( id ) end # assume
|
50
|
+
else Firing().of( id ) end # assume transition
|
44
51
|
end
|
45
52
|
|
53
|
+
# Gradient feature constructor. Takes a single ordered argument, which must
|
54
|
+
# identify a place, and an optional named argument +:transitions+, which must
|
55
|
+
# contain an array of T transition identifyers (gradient is defined as time
|
56
|
+
# derivative, so timeless transitions are not eligible). If not given, the
|
57
|
+
# gradient feature is constructed with respect to all net's T transitions.
|
58
|
+
#
|
46
59
|
def Gradient id=L!, transitions: net.T_tt
|
47
60
|
return @Gradient if id.local_object?
|
48
61
|
case id
|
@@ -50,32 +63,113 @@ class YPetri::Net::State::Feature
|
|
50
63
|
when Gradient then
|
51
64
|
Gradient().of( id.place, transitions: id.transitions )
|
52
65
|
else
|
53
|
-
Gradient().of( id, transitions: transitions )
|
54
|
-
end
|
66
|
+
Gradient().of( id, transitions: transitions ) # assume place
|
67
|
+
end
|
55
68
|
end
|
56
69
|
|
70
|
+
# Flux feature constructor. Takes a single argument, which must identify
|
71
|
+
# a TS transition. Flux is defined as time derivative of firing.
|
72
|
+
#
|
57
73
|
def Flux id=L!
|
58
74
|
return @Flux if id.local_object?
|
59
75
|
case id
|
60
76
|
when Flux() then id
|
61
77
|
when Flux then Flux().of( id.transition )
|
62
|
-
else
|
63
|
-
Flux().of( id )
|
64
|
-
end # assume it's a place
|
78
|
+
else Flux().of( id ) end # assume transition
|
65
79
|
end
|
66
80
|
|
81
|
+
# Delta feature constructor. Takes a single ordered argument, which must
|
82
|
+
# identify a place, and an optional named argument +:transitions+, which
|
83
|
+
# must contain an array of transition idetifyers. If not given, the delta
|
84
|
+
# feature is constructed with respect to all net's transitions.
|
85
|
+
#
|
86
|
+
# Furthermore, if the +:transitions+ argument is given, the transitions must
|
87
|
+
# be either all timeless, or all timed. Delta features are thus of 2 kinds:
|
88
|
+
# timed and timeless (can be inquired via +#timed?+). When used to extract
|
89
|
+
# values from the target object, timeless delta merely returns a value, while
|
90
|
+
# timed returns unary closure waiting for Δt argument to return delta for
|
91
|
+
# that Δt (if you want the rate directly, use a gradient feature).
|
92
|
+
#
|
67
93
|
def Delta id=L!, transitions: net.tt
|
68
94
|
return @Delta if id.local_object?
|
69
95
|
case id
|
70
96
|
when Delta() then id
|
71
97
|
when Delta then
|
72
98
|
Delta().of( id.place, transitions: id.transitions )
|
73
|
-
else
|
99
|
+
else
|
100
|
+
Delta().of( id, transitions: transitions )
|
101
|
+
end # assume place
|
102
|
+
end
|
103
|
+
|
104
|
+
# Assignment feature constructor. Takes a single ordered argument, which
|
105
|
+
# must identify a place, and an optional argument +:transition+, which
|
106
|
+
# must identify a single A (assignment) transition. The feature extracts
|
107
|
+
# the assignment action from the transition to the place. If the
|
108
|
+
# +:transition+ named argument is not given, the place's upstream arcs
|
109
|
+
# must contain exactly one A transition.
|
110
|
+
#
|
111
|
+
def Assignment id=L!, transition: L!
|
112
|
+
return @Assignment if id.local_object? && transition.local_object?
|
113
|
+
case id
|
114
|
+
when Assignment() then id
|
115
|
+
when Assignment then
|
116
|
+
Assignment().to( id.place, transition: id.transition )
|
117
|
+
else
|
118
|
+
fail ArgumentError, "No place given!" if id.local_object?
|
119
|
+
if transition.local_object? then
|
120
|
+
Assignment().to( id )
|
121
|
+
else
|
122
|
+
Assignment().to( id, transition: transition )
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Takes a single argument, and infers a feature from it in the following way:
|
128
|
+
# A +net.State.Feature+ instance is returned unchanged. Place or place id is
|
129
|
+
# converted to a marking feature. Otherwise, the argument is treated as a
|
130
|
+
# transition, and is converted to either a flux feature (if timed), or a
|
131
|
+
# firing feature (if timeless).
|
132
|
+
#
|
133
|
+
def infer_from_node( arg )
|
134
|
+
case arg
|
135
|
+
when self then return arg
|
136
|
+
when Marking then return Marking().of( arg.place )
|
137
|
+
when Firing then return Firing().of( arg.transition )
|
138
|
+
when Gradient then
|
139
|
+
return Gradient().of( arg.place, transitions: arg.transitions )
|
140
|
+
when Flux then return Flux().of( arg.transition )
|
141
|
+
when Delta then
|
142
|
+
return Delta().of( arg.place, transitions: arg.transitions )
|
143
|
+
when Assignment then
|
144
|
+
return Assignment().to( arg.place, transitions: arg.transition )
|
145
|
+
else # treated as a place or transition id
|
146
|
+
e, type = begin
|
147
|
+
[ net.place( arg ), :place ]
|
148
|
+
rescue TypeError, NameError
|
149
|
+
[ net.transition( arg ), :transition ]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
case type
|
153
|
+
when :place then Marking( e )
|
154
|
+
when :transition then
|
155
|
+
fail TypeError, "Flux / firing features can only be auto-inferred " +
|
156
|
+
"from S transitions! (#{arg} was given)" unless e.S?
|
157
|
+
e.timed? ? Flux( e ) : Firing( e )
|
158
|
+
end
|
74
159
|
end
|
75
160
|
end # class << self
|
76
161
|
|
77
162
|
delegate :net,
|
78
163
|
:State,
|
79
|
-
:Marking, :Firing, :Gradient, :Flux, :Delta,
|
80
164
|
to: "self.class"
|
165
|
+
|
166
|
+
# Interpolation operator +%+ acts as an alias for the +#extract_from+ feature
|
167
|
+
# extraction method.
|
168
|
+
#
|
169
|
+
def % operand
|
170
|
+
args = Array( operand )
|
171
|
+
named_args = args.extract_options!
|
172
|
+
arg = args.first
|
173
|
+
extract_from arg, **named_args
|
174
|
+
end
|
81
175
|
end # class YPetri::Net::State::Feature
|