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
data/lib/y_petri/net/state.rb
CHANGED
@@ -1,129 +1,95 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
# An array whose elements
|
4
|
-
#
|
3
|
+
# An array whose elements represent marking of places of a +YPetri::Net+.
|
4
|
+
#
|
5
5
|
class YPetri::Net::State < Array
|
6
6
|
require_relative 'state/feature'
|
7
7
|
require_relative 'state/features'
|
8
8
|
|
9
9
|
class << self
|
10
|
-
# Customization of the parametrize method for the State class: Its
|
11
|
-
#
|
10
|
+
# Customization of the parametrize method for the State class: Its dependents
|
11
|
+
# Feature and Features (feature set class) are also parametrized.
|
12
12
|
#
|
13
13
|
def parametrize net: ( fail ArgumentError, "No owning net!" )
|
14
14
|
Class.new( self ).tap do |ç|
|
15
15
|
ç.define_singleton_method :net do net end
|
16
|
-
ç.param_class( { Feature: Feature,
|
17
|
-
|
18
|
-
|
16
|
+
ç.param_class!( { Feature: Feature,
|
17
|
+
Features: Features },
|
18
|
+
with: { State: ç } )
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
delegate :Marking,
|
23
|
-
:Firing,
|
24
|
-
:Gradient,
|
25
|
-
:Flux,
|
26
|
-
:Delta,
|
27
|
-
to: "Feature()"
|
28
|
-
|
29
22
|
# Returns the feature identified by the argument.
|
30
|
-
#
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
when Feature
|
35
|
-
when
|
36
|
-
|
37
|
-
msg = "Malformed feature identifier!"
|
38
|
-
fail ArgumentError, msg unless id.size == 1 and id.first.is_a? Hash
|
39
|
-
ꜧ = id.first
|
40
|
-
fail ArgumentError, msg unless ꜧ.size == 1
|
41
|
-
key, val = ꜧ.keys.first, ꜧ.values.first
|
42
|
-
recognized = :marking, :firing, :gradient, :flux, :delta
|
43
|
-
msg = "Unrecognized feature: #{key}"
|
44
|
-
fail ArgumentError, msg unless recognized.include? key
|
45
|
-
# And now, with everything clean...
|
23
|
+
#
|
24
|
+
def Feature arg=nil, **named_args
|
25
|
+
case arg
|
26
|
+
when Feature() then arg
|
27
|
+
when Feature then arg.class.new( arg )
|
28
|
+
when nil then
|
29
|
+
key, val = named_args.first
|
46
30
|
case key
|
47
|
-
when :marking then Marking( val )
|
48
|
-
when :firing then Firing( val )
|
49
|
-
when :flux then Flux( val )
|
50
|
-
when :gradient then Gradient( *val )
|
51
|
-
when :delta then Delta( *val )
|
31
|
+
when :marking then Feature().Marking( val )
|
32
|
+
when :firing then Feature().Firing( val )
|
33
|
+
when :flux then Feature().Flux( val )
|
34
|
+
when :gradient then Feature().Gradient( *val )
|
35
|
+
when :delta then Feature().Delta( *val )
|
36
|
+
when :assignment then Feature().Assignment( val )
|
37
|
+
else fail ArgumentError, "Unrecognized feature: #{key}!"
|
52
38
|
end
|
39
|
+
else
|
40
|
+
Feature().infer_from_node( arg )
|
53
41
|
end
|
54
42
|
end
|
55
43
|
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
# +:firing+, +:gradient+, +:flux+ and +:delta+, specifying the respective
|
60
|
-
# features. For +:marking+, an array of places (or Marking features) is
|
61
|
-
# expected. For +:firing+ and +:flux+, an array of transitions (or Firing
|
62
|
-
# / Flux features) is expected. For +:gradient+ and +:delta+, a hash value
|
63
|
-
# is expected, containing keys +:places+ and +:transitions+, specifying
|
64
|
-
# for which place set / transition set should gradient / delta features
|
65
|
-
# be constructed. More in detail, values supplied under keys +:marking+,
|
66
|
-
# +:firing+, +:gradient+, +:flux+ and +:delta+ are delegated to
|
67
|
-
# +Features.marking+, +Features.firing+, +Features.gradient+ and
|
68
|
-
# +Features.flux+ methods, and their results are joined into a single
|
69
|
-
# feature set.
|
44
|
+
# A constructor of a +Features+ instance. Note that the message +:Features+
|
45
|
+
# called without arguments is intercepted by a singleton method and returns
|
46
|
+
# the parametrized subclass of +State::Features+ owned by this class.
|
70
47
|
#
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
flux = arg[:flux] || [] # array of TS transitions
|
79
|
-
delta = arg[:delta] || [ [], transitions: [] ]
|
80
|
-
[ Features().marking( marking ),
|
81
|
-
Features().firing( firing ),
|
82
|
-
Features().gradient( *gradient ),
|
83
|
-
Features().flux( flux ),
|
84
|
-
Features().delta( *delta ) ].reduce :+
|
85
|
-
end
|
48
|
+
# This method may accept a single array-type argument, constructing a feature
|
49
|
+
# set out of it. Alternatively, the method may accept named arguments:
|
50
|
+
# +:marking+, +:firing+, +:gradient+, +:flux+, +:delta+, and +:assignment+,
|
51
|
+
# specifying the a single (possibly mixed) feature set.
|
52
|
+
#
|
53
|
+
def Features array=nil, **named_args
|
54
|
+
Features()[ *array, **named_args ]
|
86
55
|
end
|
56
|
+
end # class << self
|
87
57
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
# For non-parametrized vesion of the class, the class instance variables
|
92
|
-
# hold the non-parametrized dependent classes.
|
58
|
+
# For non-parametrized vesion of the class, should it ever be used in such way,
|
59
|
+
# the class instance variables hold the non-parametrized dependent classes.
|
93
60
|
#
|
94
61
|
@Feature, @Features = Feature, Features
|
95
62
|
|
96
63
|
delegate :net,
|
97
|
-
:Feature,
|
98
|
-
:Features,
|
99
|
-
:features,
|
100
|
-
:marking, :firing, :gradient, :flux, :delta,
|
64
|
+
:Feature, # Note that as syntactic salt, specific methods
|
65
|
+
:Features, # #marking, #firing, #gradient, #flux etc. are
|
66
|
+
:features, # not delegated to self.class.
|
101
67
|
to: "self.class"
|
102
68
|
|
103
|
-
# Given a set of clamped places,
|
69
|
+
# Given a set of clamped places, this method outputs a +Record+ instance
|
104
70
|
# containing the marking of the free places (complementary to the supplied
|
105
71
|
# set of clamped places). I no set of clamped places is supplied, it is
|
106
72
|
# considered empty.
|
107
73
|
#
|
108
|
-
def to_record clamped_places
|
74
|
+
def to_record clamped_places
|
109
75
|
free_places = case clamped_places
|
110
76
|
when Hash then to_record( clamped_places.keys )
|
111
77
|
else
|
112
|
-
|
78
|
+
places - places( clamped_places )
|
113
79
|
end
|
114
80
|
features( marking: free_places ).Record.load markings( free_places )
|
115
81
|
end
|
116
82
|
|
117
83
|
# Marking of a single given place in this state.
|
118
84
|
#
|
119
|
-
def marking
|
120
|
-
self[ places.index place(
|
85
|
+
def marking place
|
86
|
+
self[ net.places.index net.place( place ) ]
|
121
87
|
end
|
122
88
|
|
123
|
-
#
|
89
|
+
# Expects an arbitrary number of places or place ids, and returns an array
|
90
|
+
# of their markings as per the receiver +State+ instance.
|
124
91
|
#
|
125
|
-
def markings
|
126
|
-
|
127
|
-
place_ids.map &:marking
|
92
|
+
def markings *places
|
93
|
+
places.map &method( :marking )
|
128
94
|
end
|
129
95
|
end # YPetri::Net::State
|
data/lib/y_petri/net.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require_relative 'net/
|
3
|
+
require_relative 'net/node_access'
|
4
4
|
require_relative 'net/visualization'
|
5
5
|
require_relative 'net/own_state'
|
6
6
|
require_relative 'net/data_set'
|
@@ -10,21 +10,33 @@ require_relative 'net/state'
|
|
10
10
|
# connector arrows – called _arcs_ in classical Petri net terminology – can be
|
11
11
|
# considered a property of transitions. Therefore in +YPetri::Net+, you won't
|
12
12
|
# find arcs as first-class citizens, but only as a synonym denoting nearest
|
13
|
-
# neighbors of
|
13
|
+
# neighbors of nodes (places or transitions).
|
14
14
|
#
|
15
15
|
class YPetri::Net
|
16
|
+
# ===========================================================================
|
17
|
+
# !!! TODO !!!
|
18
|
+
#
|
19
|
+
# Refactoring plans for Net class
|
20
|
+
#
|
21
|
+
# Make it a subclass of Module class, so places and transitions can simply
|
22
|
+
# be defined as its constants.
|
23
|
+
#
|
24
|
+
# ===========================================================================
|
25
|
+
|
16
26
|
★ NameMagic # ★ means include
|
17
|
-
★
|
27
|
+
★ NodeAccess
|
18
28
|
★ Visualization
|
19
29
|
★ OwnState
|
20
30
|
|
21
31
|
class << self
|
22
32
|
★ YPetri::World::Dependency
|
23
33
|
|
24
|
-
|
34
|
+
private :new
|
35
|
+
|
36
|
+
# Constructs a net containing a particular set of nodes.
|
25
37
|
#
|
26
|
-
def of
|
27
|
-
new.tap { |inst|
|
38
|
+
def of nodes
|
39
|
+
new.tap { |inst| nodes.each { |node| inst << node } }
|
28
40
|
end
|
29
41
|
end
|
30
42
|
|
@@ -34,93 +46,95 @@ class YPetri::Net
|
|
34
46
|
# Takes 2 arguments (+:places+ and +:transitions+) and builds a net from them.
|
35
47
|
#
|
36
48
|
def initialize( places: [], transitions: [] )
|
37
|
-
param_class( { State: State
|
49
|
+
param_class!( { State: State,
|
50
|
+
Simulation: YPetri::Simulation },
|
51
|
+
with: { net: self } )
|
38
52
|
@places, @transitions = [], []
|
39
53
|
places.each &method( :include_place )
|
40
54
|
transitions.each &method( :include_transition )
|
41
|
-
param_class( { Simulation: YPetri::Simulation },
|
42
|
-
with: { net: self } )
|
43
55
|
end
|
44
56
|
|
45
57
|
# Includes a place in the receiver. Returns _true_ if successful, _false_ if
|
46
58
|
# the place is already included in the receiver net.
|
47
59
|
#
|
48
|
-
def include_place
|
49
|
-
|
50
|
-
return false if
|
51
|
-
true.tap { @places <<
|
60
|
+
def include_place place
|
61
|
+
place = Place().instance( place )
|
62
|
+
return false if include_place? place
|
63
|
+
true.tap { @places << place }
|
52
64
|
end
|
53
65
|
|
54
66
|
# Includes a transition in the receiver. Returns _true_ if successful, _false_
|
55
67
|
# if the transition is already included in the net. The arcs of the transition
|
56
68
|
# being included may only connect to the places already in the receiver net.
|
57
69
|
#
|
58
|
-
def include_transition
|
59
|
-
|
60
|
-
return false if
|
61
|
-
|
62
|
-
|
63
|
-
true.tap { @transitions <<
|
70
|
+
def include_transition transition
|
71
|
+
transition = Transition().instance( transition )
|
72
|
+
return false if include_transition? transition
|
73
|
+
fail "Transition #{transition} has arcs to places outside #{self}!" unless
|
74
|
+
transition.arcs.all? { |place| include_place? place }
|
75
|
+
true.tap { @transitions << transition }
|
64
76
|
end
|
65
77
|
|
66
78
|
# Excludes a place from the receiver. Returns _true_ if successful, _false_
|
67
79
|
# if the place was not found in the receiver net. A place may not be excluded
|
68
80
|
# from the receiver so long as any transitions therein connect to it.
|
69
81
|
#
|
70
|
-
def exclude_place
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
false.tap { return true if @places.delete(
|
82
|
+
def exclude_place place
|
83
|
+
place = Place().instance( place )
|
84
|
+
fail "Unable to exclude #{place} from #{self}: Transitions depend on it!" if
|
85
|
+
transitions.any? { |transition| transition.arcs.include? place }
|
86
|
+
false.tap { return true if @places.delete( place ) }
|
75
87
|
end
|
76
88
|
|
77
89
|
# Excludes a transition from the receiver. Returns _true_ if successful,
|
78
90
|
# _false_ if the transition was not found in the receiver net.
|
79
91
|
#
|
80
|
-
def exclude_transition
|
81
|
-
|
82
|
-
false.tap { return true if @transitions.delete(
|
92
|
+
def exclude_transition transition
|
93
|
+
transition = Transition().instance( transition )
|
94
|
+
false.tap { return true if @transitions.delete( transition ) }
|
83
95
|
end
|
84
96
|
|
85
97
|
# Includes another net in the receiver net. Returns _true_ if successful
|
86
98
|
# (ie. if there was any change to the receiver net), _false_ if the receiver
|
87
99
|
# net already includes the argument net.
|
88
100
|
#
|
89
|
-
def include_net
|
90
|
-
net = Net().instance(
|
91
|
-
|
92
|
-
|
93
|
-
|
101
|
+
def include_net net
|
102
|
+
net = Net().instance( net ) rescue YPetri::Net.instance( net )
|
103
|
+
p_results = net.pp.map &method( :include_place )
|
104
|
+
t_results = net.tt.map &method( :include_transition )
|
105
|
+
( p_results + t_results ).reduce :|
|
94
106
|
end
|
95
107
|
alias merge! include_net
|
96
108
|
|
97
109
|
# Excludes another net from the receiver net. Returns _true_ if successful
|
98
110
|
# (ie. if there was any change to the receiver net), _false_ if the receiver
|
99
|
-
# net contained no
|
111
|
+
# net contained no node of the argument net.
|
100
112
|
#
|
101
113
|
def exclude_net id
|
102
|
-
net = Net().instance( id )
|
114
|
+
net = Net().instance( id ) rescue YPetri::Net.instance( net )
|
103
115
|
t_rslt = net.tt.map { |t| exclude_transition t }.reduce :|
|
104
116
|
p_rslt = net.pp.map { |p| exclude_place p }.reduce :|
|
105
117
|
p_rslt || t_rslt
|
106
118
|
end
|
107
119
|
|
108
|
-
# Includes
|
120
|
+
# Includes a node (place or transition) in the receiver net.
|
109
121
|
#
|
110
|
-
def <<
|
122
|
+
def << node
|
111
123
|
begin
|
112
|
-
type
|
124
|
+
type = :place
|
125
|
+
place = self.class.place node
|
113
126
|
rescue NameError, TypeError
|
114
127
|
begin
|
115
|
-
type
|
128
|
+
type = :transition
|
129
|
+
transition = self.class.transition node
|
116
130
|
rescue NameError, TypeError => err
|
117
|
-
raise TypeError, "Current world contains no place or
|
118
|
-
"
|
131
|
+
raise TypeError, "Current world contains no place or " +
|
132
|
+
"transition #{node}! (#{err})"
|
119
133
|
end
|
120
134
|
end
|
121
135
|
case type # Factored out to minimize the code inside the rescue clause.
|
122
|
-
when :place then include_place(
|
123
|
-
when :transition then include_transition(
|
136
|
+
when :place then include_place( place )
|
137
|
+
when :transition then include_transition( transition )
|
124
138
|
else fail "Implementation error!" end
|
125
139
|
return self # important to enable chaining, eg. foo_net << p1 << p2 << t1
|
126
140
|
end
|
@@ -135,12 +149,12 @@ class YPetri::Net
|
|
135
149
|
end
|
136
150
|
end
|
137
151
|
|
138
|
-
#
|
139
|
-
#
|
152
|
+
# Returns a new net that is the result of subtraction of the net given as
|
153
|
+
# argument from this net.
|
140
154
|
#
|
141
155
|
def - other
|
142
156
|
self.class.send( :new ).tap do |net|
|
143
|
-
net.
|
157
|
+
net.include_net self
|
144
158
|
net.exclude_net other
|
145
159
|
end
|
146
160
|
end
|
@@ -148,13 +162,13 @@ class YPetri::Net
|
|
148
162
|
# Is the net _functional_?
|
149
163
|
#
|
150
164
|
def functional?
|
151
|
-
transitions.any?
|
165
|
+
transitions.any? &:functional?
|
152
166
|
end
|
153
167
|
|
154
168
|
# Is the net _timed_?
|
155
169
|
#
|
156
170
|
def timed?
|
157
|
-
transitions.any?
|
171
|
+
transitions.any? &:timed?
|
158
172
|
end
|
159
173
|
|
160
174
|
# Creates a new simulation from the net.
|
@@ -162,6 +176,7 @@ class YPetri::Net
|
|
162
176
|
def simulation( **settings )
|
163
177
|
Simulation().__new__ **settings
|
164
178
|
end
|
179
|
+
alias new_simulation simulation
|
165
180
|
|
166
181
|
# Networks are equal when their places and transitions are equal.
|
167
182
|
#
|
data/lib/y_petri/place/arcs.rb
CHANGED
@@ -23,6 +23,24 @@ module YPetri::Place::Arcs
|
|
23
23
|
upstream_arcs | downstream_arcs
|
24
24
|
end
|
25
25
|
|
26
|
+
# Names of the transitions connected to the place. The optional argument
|
27
|
+
# controls what is returned for unnamed instances, and works just like in
|
28
|
+
# <tt>Array#names</tt> method from <tt>y_support/name_magic</tt>:
|
29
|
+
# The default value (_nil_) returns _nil_, _true_ returns the instance itself,
|
30
|
+
# and _false_ drops the unnamed instances from the list altogether.
|
31
|
+
#
|
32
|
+
def aa arg=nil
|
33
|
+
arcs.names arg
|
34
|
+
end
|
35
|
+
|
36
|
+
# Arc (a transition connected to this place) identifier.
|
37
|
+
#
|
38
|
+
def arc id
|
39
|
+
transition = transition( id )
|
40
|
+
arcs.find { |t| t == transition } or
|
41
|
+
fail TypeError, "No transition #{id} connected to #{self}!"
|
42
|
+
end
|
43
|
+
|
26
44
|
# Union of the domains of the upstream transitions.
|
27
45
|
#
|
28
46
|
def precedents
|
@@ -37,6 +55,32 @@ module YPetri::Place::Arcs
|
|
37
55
|
end
|
38
56
|
alias :downstream_places :dependents
|
39
57
|
|
58
|
+
# A net containing all the upstream transitions and their connected places.
|
59
|
+
#
|
60
|
+
def upstream_net
|
61
|
+
net_klass = world.Net rescue YPetri::Net # for when not used as PS
|
62
|
+
upstream_transitions.each_with_object net_klass.send( :new ) do |t, net|
|
63
|
+
t.arcs.each { |place| net << place }
|
64
|
+
net << t
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# A net containing all the upstream transitions and their connected places.
|
69
|
+
#
|
70
|
+
def downstream_net
|
71
|
+
net_klass = world.Net rescue YPetri::Net # for when not used as PS
|
72
|
+
downstream_transitions.each_with_object net_klass.send( :new ) do |t, net|
|
73
|
+
t.arcs.each { |place| net << place }
|
74
|
+
net << t
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# A union of upstream local net and downstream local net.
|
79
|
+
#
|
80
|
+
def local_net
|
81
|
+
downstream_net + upstream_net
|
82
|
+
end
|
83
|
+
|
40
84
|
# Fires the upstream transitions.
|
41
85
|
#
|
42
86
|
def fire_upstream
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Place instance methods concerned with state and/or simulation features.
|
4
|
+
#
|
5
|
+
module YPetri::Place::Features
|
6
|
+
# Expects an array of transitions, and +:net+ named argument. Returns a single
|
7
|
+
# gradient feature belonging to the net for this place, and those upstream T
|
8
|
+
# transitions, that are also in the included in the array. If no ordered
|
9
|
+
# arguments are given, complete set of upstream T transitions is assumed. If
|
10
|
+
# no +:net+ is given, +Top+ is assumed.
|
11
|
+
#
|
12
|
+
def Gradient array, net: world.net( :Top )
|
13
|
+
fail TypeError, "#{self} must be included in the net!" unless
|
14
|
+
net.include? self
|
15
|
+
transitions = upstream_arcs.select { |t| array.include? t }.select( &:T? )
|
16
|
+
net.State.Feature.Gradient( self, transitions: transitions )
|
17
|
+
end
|
18
|
+
|
19
|
+
# Expects an arbitrary number of transitions, and +:net+ named argument.
|
20
|
+
# Returns a single gradient feature belonging to the net for this place,
|
21
|
+
# and those upstream T transitions, that are also in the included among
|
22
|
+
# the arguments. If no ordered arguments are given, complete set of upstream
|
23
|
+
# T transitions is assumed. If no +:net+ is given, +Top+ is assumed.
|
24
|
+
#
|
25
|
+
def gradient *transitions, net: world.net( :Top )
|
26
|
+
return Gradient upstream_arcs, net: net if transitions.empty?
|
27
|
+
Gradient transitions, net: net
|
28
|
+
end
|
29
|
+
|
30
|
+
# Expects an array of transitions, and +:net+ named argument. Returns a
|
31
|
+
# feature set belonging to the net, consisting of the features for this
|
32
|
+
# place, and those upstream T transitions, that are also included in the
|
33
|
+
# array. If no +:net+ is given, +Top+ is assumed.
|
34
|
+
#
|
35
|
+
def Gradients array, net: world.net( :Top )
|
36
|
+
fail TypeError, "#{self} must be included in the net!" unless
|
37
|
+
net.include? self
|
38
|
+
transitions = upstream_arcs.select { |t| array.include? t }.select( &:T? )
|
39
|
+
net.State.Features( transitions.map { |t| gradient t, net: net } )
|
40
|
+
end
|
41
|
+
|
42
|
+
# Expects an arbitrary number of transitions, and +:net+ named argument.
|
43
|
+
# Returns a feature set belonging to the net, constisting of the features
|
44
|
+
# for this place, and those upstream T transitions, that are also included
|
45
|
+
# in the array. If no ordered arguments are given, complete set of upstream
|
46
|
+
# T transitions is assumed. If no +:net+ is given, +Top+ is assumed.
|
47
|
+
#
|
48
|
+
def gradients *transitions, net: world.net( :Top )
|
49
|
+
return Gradients upstream_arcs, net: net if transitions.empty?
|
50
|
+
Gradients transitions, net: net
|
51
|
+
end
|
52
|
+
|
53
|
+
# Expects an array of transitions, and +:net+ named argument. Returns a single
|
54
|
+
# delta feature belonging to the net for this place, and those upstream T
|
55
|
+
# transitions, that are also in the included in the array. If no ordered
|
56
|
+
# arguments are given, complete set of upstream T transitions is assumed. If
|
57
|
+
# no +:net+ is given, +Top+ is assumed.
|
58
|
+
#
|
59
|
+
def Delta array, net: world.net( :Top )
|
60
|
+
fail TypeError, "#{self} must be included in the net!" unless
|
61
|
+
net.include? self
|
62
|
+
transitions = upstream_arcs.select { |t| array.include? t }.select( &:T? )
|
63
|
+
net.State.Feature.Delta( self, transitions: transitions )
|
64
|
+
end
|
65
|
+
|
66
|
+
# Expects an arbitrary number of transitions, and +:net+ named argument.
|
67
|
+
# Returns a single delta feature belonging to the net for this place,
|
68
|
+
# and those upstream T transitions, that are also in the included among
|
69
|
+
# the arguments. If no ordered arguments are given, complete set of upstream
|
70
|
+
# T transitions is assumed. If no +:net+ is given, +Top+ is assumed.
|
71
|
+
#
|
72
|
+
def delta *transitions, net: world.net( :Top )
|
73
|
+
return Delta upstream_arcs, net: net if transitions.empty?
|
74
|
+
Delta transitions, net: net
|
75
|
+
end
|
76
|
+
|
77
|
+
# Expects an array of transitions, and +:net+ named argument. Returns a
|
78
|
+
# feature set belonging to the net, consisting of the features for this
|
79
|
+
# place, and those upstream T transitions, that are also included in the
|
80
|
+
# array. If no +:net+ is given, +Top+ is assumed.
|
81
|
+
#
|
82
|
+
def Deltas array, net: world.net( :Top )
|
83
|
+
fail TypeError, "#{self} must be included in the net!" unless
|
84
|
+
net.include? self
|
85
|
+
transitions = upstream_arcs.select { |t| array.include? t }.select( &:T? )
|
86
|
+
net.State.Features( transitions.map { |t| delta t, net: net } )
|
87
|
+
end
|
88
|
+
|
89
|
+
# Expects an arbitrary number of transitions, and +:net+ named argument.
|
90
|
+
# Returns a feature set belonging to the net, constisting of the features
|
91
|
+
# for this place, and those upstream T transitions, that are also included
|
92
|
+
# in the array. If no ordered arguments are given, complete set of upstream
|
93
|
+
# T transitions is assumed. If no +:net+ is given, +Top+ is assumed.
|
94
|
+
#
|
95
|
+
def deltas *transitions, net: world.net( :Top )
|
96
|
+
return Deltas upstream_arcs, net: net if transitions.empty?
|
97
|
+
Deltas transitions, net: net
|
98
|
+
end
|
99
|
+
|
100
|
+
# Convenience method. Prints gradients under curent simulation.
|
101
|
+
#
|
102
|
+
def pg simulation=world.simulation, precision: 8, **nn
|
103
|
+
( gradients >> gradients % simulation )
|
104
|
+
.pretty_print_numeric_values precision: precision, **nn
|
105
|
+
end
|
106
|
+
|
107
|
+
# Convenience method. Prints deltas under current simulation.
|
108
|
+
#
|
109
|
+
def pd simulation=world.simulation, precision: 8, **nn
|
110
|
+
nn.may_have :delta_time, syn!: :Δt
|
111
|
+
delta_time = nn.delete( :delta_time ) || world.simulation.step
|
112
|
+
( deltas >> deltas % [ simulation, delta_time: delta_time ] )
|
113
|
+
.pretty_print_numeric_values precision: precision, **nn
|
114
|
+
end
|
115
|
+
end # class YPetri::Place::Features
|