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