y_petri 2.0.15 → 2.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/lib/y_petri/{manipulator → agent}/hash_key_pointer.rb +2 -2
  3. data/lib/y_petri/agent/petri_net_related.rb +115 -0
  4. data/lib/y_petri/{manipulator → agent}/selection.rb +2 -1
  5. data/lib/y_petri/{manipulator/simulation_related_methods.rb → agent/simulation_related.rb} +93 -110
  6. data/lib/y_petri/agent.rb +22 -0
  7. data/lib/y_petri/core/timed/euler.rb +20 -0
  8. data/lib/y_petri/core/timed/pseudo_euler.rb +31 -0
  9. data/lib/y_petri/core/timed/quasi_euler.rb +23 -0
  10. data/lib/y_petri/core/timed.rb +70 -0
  11. data/lib/y_petri/core/timeless/pseudo_euler.rb +20 -0
  12. data/lib/y_petri/core/timeless.rb +12 -0
  13. data/lib/y_petri/core.rb +100 -0
  14. data/lib/y_petri/dsl.rb +66 -0
  15. data/lib/y_petri/fixed_assets.rb +7 -0
  16. data/lib/y_petri/net/element_access.rb +239 -0
  17. data/lib/y_petri/net/state/feature/delta.rb +88 -0
  18. data/lib/y_petri/net/state/feature/firing.rb +57 -0
  19. data/lib/y_petri/net/state/feature/flux.rb +58 -0
  20. data/lib/y_petri/net/state/feature/gradient.rb +75 -0
  21. data/lib/y_petri/net/state/feature/marking.rb +62 -0
  22. data/lib/y_petri/net/state/feature.rb +79 -0
  23. data/lib/y_petri/net/state/features/dataset.rb +135 -0
  24. data/lib/y_petri/net/state/features/record.rb +50 -0
  25. data/lib/y_petri/net/state/features.rb +126 -0
  26. data/lib/y_petri/net/state.rb +121 -0
  27. data/lib/y_petri/net/timed.rb +8 -0
  28. data/lib/y_petri/net/visualization.rb +3 -3
  29. data/lib/y_petri/net.rb +73 -77
  30. data/lib/y_petri/place.rb +8 -3
  31. data/lib/y_petri/simulation/dependency.rb +107 -0
  32. data/lib/y_petri/simulation/element_representation.rb +20 -0
  33. data/lib/y_petri/simulation/elements/access.rb +57 -0
  34. data/lib/y_petri/simulation/elements.rb +45 -0
  35. data/lib/y_petri/simulation/feature_set.rb +21 -0
  36. data/lib/y_petri/simulation/initial_marking/access.rb +55 -0
  37. data/lib/y_petri/simulation/initial_marking.rb +15 -0
  38. data/lib/y_petri/simulation/marking_clamps/access.rb +34 -0
  39. data/lib/y_petri/simulation/marking_clamps.rb +18 -0
  40. data/lib/y_petri/simulation/marking_vector/access.rb +106 -0
  41. data/lib/y_petri/simulation/marking_vector.rb +156 -0
  42. data/lib/y_petri/simulation/matrix.rb +64 -0
  43. data/lib/y_petri/simulation/place_mapping.rb +62 -0
  44. data/lib/y_petri/simulation/place_representation.rb +74 -0
  45. data/lib/y_petri/simulation/places/access.rb +121 -0
  46. data/lib/y_petri/simulation/places/clamped.rb +8 -0
  47. data/lib/y_petri/simulation/places/free.rb +8 -0
  48. data/lib/y_petri/simulation/places/types.rb +25 -0
  49. data/lib/y_petri/simulation/places.rb +41 -0
  50. data/lib/y_petri/simulation/recorder.rb +54 -0
  51. data/lib/y_petri/simulation/timed/recorder.rb +53 -0
  52. data/lib/y_petri/simulation/timed.rb +161 -261
  53. data/lib/y_petri/simulation/timeless/recorder.rb +25 -0
  54. data/lib/y_petri/simulation/timeless.rb +35 -0
  55. data/lib/y_petri/simulation/transition_representation/A.rb +58 -0
  56. data/lib/y_petri/simulation/transition_representation/S.rb +45 -0
  57. data/lib/y_petri/simulation/transition_representation/T.rb +80 -0
  58. data/lib/y_petri/simulation/transition_representation/TS.rb +46 -0
  59. data/lib/y_petri/simulation/transition_representation/Ts.rb +32 -0
  60. data/lib/y_petri/simulation/transition_representation/a.rb +30 -0
  61. data/lib/y_petri/simulation/transition_representation/s.rb +29 -0
  62. data/lib/y_petri/simulation/transition_representation/t.rb +37 -0
  63. data/lib/y_petri/simulation/transition_representation/tS.rb +38 -0
  64. data/lib/y_petri/simulation/transition_representation/ts.rb +32 -0
  65. data/lib/y_petri/simulation/transition_representation/types.rb +62 -0
  66. data/lib/y_petri/simulation/transition_representation.rb +79 -0
  67. data/lib/y_petri/simulation/transitions/A.rb +40 -0
  68. data/lib/y_petri/simulation/transitions/S.rb +24 -0
  69. data/lib/y_petri/simulation/transitions/T.rb +34 -0
  70. data/lib/y_petri/simulation/transitions/TS.rb +57 -0
  71. data/lib/y_petri/simulation/transitions/Ts.rb +60 -0
  72. data/lib/y_petri/simulation/transitions/a.rb +8 -0
  73. data/lib/y_petri/simulation/transitions/access.rb +186 -0
  74. data/lib/y_petri/simulation/transitions/s.rb +9 -0
  75. data/lib/y_petri/simulation/transitions/t.rb +22 -0
  76. data/lib/y_petri/simulation/transitions/tS.rb +55 -0
  77. data/lib/y_petri/simulation/transitions/ts.rb +58 -0
  78. data/lib/y_petri/simulation/transitions/types.rb +98 -0
  79. data/lib/y_petri/simulation/transitions.rb +21 -0
  80. data/lib/y_petri/simulation.rb +176 -781
  81. data/lib/y_petri/transition/assignment.rb +7 -5
  82. data/lib/y_petri/transition/construction.rb +119 -187
  83. data/lib/y_petri/transition/init.rb +311 -0
  84. data/lib/y_petri/transition/ordinary_timeless.rb +8 -6
  85. data/lib/y_petri/transition/timed.rb +11 -18
  86. data/lib/y_petri/transition.rb +104 -132
  87. data/lib/y_petri/version.rb +1 -1
  88. data/lib/y_petri/world/dependency.rb +40 -0
  89. data/lib/y_petri/world/petri_net_related.rb +61 -0
  90. data/lib/y_petri/{workspace/simulation_related_methods.rb → world/simulation_related.rb} +42 -49
  91. data/lib/y_petri/world.rb +27 -0
  92. data/lib/y_petri.rb +47 -99
  93. data/test/{manipulator_test.rb → agent_test.rb} +19 -17
  94. data/{lib/y_petri → test/examples}/demonstrator.rb +0 -0
  95. data/{lib/y_petri → test/examples}/demonstrator_2.rb +1 -0
  96. data/{lib/y_petri → test/examples}/demonstrator_3.rb +0 -0
  97. data/{lib/y_petri → test/examples}/demonstrator_4.rb +0 -0
  98. data/test/examples/example_2.rb +16 -0
  99. data/test/{manual_examples.rb → examples/manual_examples.rb} +0 -0
  100. data/test/net_test.rb +126 -121
  101. data/test/place_test.rb +1 -1
  102. data/test/sim_test +565 -0
  103. data/test/simulation_test.rb +338 -264
  104. data/test/transition_test.rb +77 -174
  105. data/test/world_mock.rb +12 -0
  106. data/test/{workspace_test.rb → world_test.rb} +19 -20
  107. data/test/y_petri_test.rb +4 -5
  108. metadata +101 -26
  109. data/lib/y_petri/dependency_injection.rb +0 -45
  110. data/lib/y_petri/manipulator/petri_net_related_methods.rb +0 -74
  111. data/lib/y_petri/manipulator.rb +0 -20
  112. data/lib/y_petri/net/selections.rb +0 -209
  113. data/lib/y_petri/simulation/collections.rb +0 -460
  114. data/lib/y_petri/workspace/parametrized_subclassing.rb +0 -22
  115. data/lib/y_petri/workspace/petri_net_related_methods.rb +0 -88
  116. data/lib/y_petri/workspace.rb +0 -16
  117. data/test/timed_simulation_test.rb +0 -153
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+
3
+ class YPetri::Net::State
4
+ class Feature
5
+ # Marking of a Petri net place.
6
+ #
7
+ class Marking < Feature
8
+ attr_reader :place
9
+
10
+ class << self
11
+ def parametrize *args
12
+ Class.instance_method( :parametrize ).bind( self ).( *args ).tap do |ç|
13
+ ç.instance_variable_set( :@instances,
14
+ Hash.new do |hsh, id|
15
+ case id
16
+ when Marking then
17
+ hsh[ id.place ]
18
+ when ç.net.Place then
19
+ hsh[ id ] = ç.__new__( id )
20
+ else
21
+ hsh[ ç.net.place( id ) ]
22
+ end
23
+ end )
24
+ end
25
+ end
26
+
27
+ attr_reader :instances
28
+
29
+ alias __new__ new
30
+
31
+ def new id
32
+ instances[ id ]
33
+ end
34
+
35
+ def of id
36
+ new id
37
+ end
38
+ end
39
+
40
+ def initialize place
41
+ @place = net.place( place )
42
+ end
43
+
44
+ def extract_from arg, **nn
45
+ case arg
46
+ when YPetri::Simulation then
47
+ arg.m( [ place ] ).first
48
+ else
49
+ fail TypeError, "Argument type not supported!"
50
+ end
51
+ end
52
+
53
+ def to_s
54
+ place.name
55
+ end
56
+
57
+ def label
58
+ ":#{place.name}"
59
+ end
60
+ end # class Marking
61
+ end # class Feature
62
+ end # YPetri::Net::State
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+
3
+ class YPetri::Net::State
4
+ # A feature of a Petri net.
5
+ #
6
+ class Feature
7
+ require_relative 'feature/marking'
8
+ require_relative 'feature/firing'
9
+ require_relative 'feature/gradient'
10
+ require_relative 'feature/flux'
11
+ require_relative 'feature/delta'
12
+
13
+ class << self
14
+ def parametrize parameters
15
+ Class.new( self ).tap do |ç|
16
+ parameters.each_pair { |symbol, value|
17
+ ç.define_singleton_method symbol do value end
18
+ }
19
+ sç = ç.State
20
+ ç.instance_variable_set :@Marking, Marking.parametrize( State: sç )
21
+ ç.instance_variable_set :@Firing, Firing.parametrize( State: sç )
22
+ ç.instance_variable_set :@Gradient, Gradient.parametrize( State: sç )
23
+ ç.instance_variable_set :@Flux, Flux.parametrize( State: sç )
24
+ ç.instance_variable_set :@Delta, Delta.parametrize( State: sç )
25
+ end
26
+ end
27
+
28
+ delegate :net,
29
+ to: "State()"
30
+
31
+ def Marking id=L!
32
+ return @Marking if id.local_object?
33
+ case id
34
+ when Marking() then id
35
+ when Marking then Marking().of( id.place )
36
+ else Marking().of( id ) end # assume it's a place
37
+ end
38
+
39
+ def Firing id=L!
40
+ return @Firing if id.local_object?
41
+ case id
42
+ when Firing() then id
43
+ when Firing then Firing().of( id.transition )
44
+ else Firing().of( id ) end # assume it's a place
45
+ end
46
+
47
+ def Gradient id=L!, transitions: net.T_tt
48
+ return @Gradient if id.local_object?
49
+ case id
50
+ when Gradient() then id
51
+ when Gradient then
52
+ Gradient().of( id.place, transitions: id.transitions )
53
+ else Gradient().of( id, transitions: transitions ) end # assume it's a place
54
+ end
55
+
56
+ def Flux id=L!
57
+ return @Flux if id.local_object?
58
+ case id
59
+ when Flux() then id
60
+ when Flux then Flux().of( id.transition )
61
+ else Flux().of( id ) end # assume it's a place
62
+ end
63
+
64
+ def Delta id=L!, transitions: net.tt
65
+ return @Delta if id.local_object?
66
+ case id
67
+ when Delta() then id
68
+ when Delta then
69
+ Delta().of( id.place, transitions: id.transitions )
70
+ else Delta().of( id, transitions: transitions ) end # assume it's a place
71
+ end
72
+ end # class << self
73
+
74
+ delegate :net,
75
+ :State,
76
+ :Marking, :Firing, :Gradient, :Flux, :Delta,
77
+ to: "self.class"
78
+ end # class Feature
79
+ end # YPetri::Net::State
@@ -0,0 +1,135 @@
1
+ # encoding: utf-8
2
+
3
+ class YPetri::Net::State
4
+ class Features
5
+ # Dataset is a collection of labeled state records.
6
+ #
7
+ class Dataset < Hash
8
+ class << self
9
+ alias __new__ new
10
+
11
+ def new
12
+ __new__ do |hsh, missing|
13
+ case missing
14
+ when Float then nil
15
+ else hsh[ missing.to_f ] end
16
+ end
17
+ end
18
+ end
19
+
20
+ alias events keys
21
+ alias records values
22
+
23
+ delegate :features, to: "self.class"
24
+ delegate :net, to: :features
25
+ delegate :State, to: :net
26
+
27
+ # Revives records from values.
28
+ #
29
+ def records
30
+ values.map { |value| features.Record.new( value ) }
31
+ end
32
+
33
+ # Recreates the simulation at a given event label.
34
+ #
35
+ def reconstruct event: event, **settings # settings include marking clampls
36
+ interpolate( event ).reconstruct **settings
37
+ end
38
+
39
+ # Interpolates the recording an the given point (event).
40
+ #
41
+ def interpolate( event )
42
+ # TODO: This whole interpolation thing is unfinished.
43
+ begin
44
+ record( event )
45
+ rescue KeyError => msg
46
+ timed? or raise TypeError, "Event #{event} does not have a record!"
47
+ f_time, floor = floor( event ) # timed datasets support floor, ceiling
48
+ c_time, ceiling = ceiling( time )
49
+ floor + ( ceiling - floor ) / ( c_time - f_time ) * ( time - f_time )
50
+ end
51
+ end
52
+
53
+ # Returns the data series for the specified features.
54
+ #
55
+ def series arg=nil
56
+ return records.transpose if arg.nil?
57
+ reduce_features( State().features( arg ) ).series
58
+ end
59
+
60
+ # Expects a hash of features (:marking (alias :state) of places, :firing
61
+ # of tS transitions, :delta of places and/or transitions) and returns the
62
+ # corresponding mapping of the recording.
63
+ #
64
+ def reduce_features features
65
+ rf = net.State.features( features )
66
+ rr_class = rf.Record
67
+ rf.new_dataset.tap do |ds|
68
+ ( events >> records ).each_pair { |event, record|
69
+ ds.update event => rr_class.load( rf.map { |f| record.fetch f } )
70
+ }
71
+ end
72
+ end
73
+
74
+ def marking *args
75
+ return reduce_features features.select { |f| f.is_a? YPetri::Net::State::Feature::Marking } if args.empty?
76
+ reduce_features marking: args.first
77
+ end
78
+
79
+ def firing *args
80
+ return reduce_features features.select { |f| f.is_a? YPetri::Net::State::Feature::Firing } if args.empty?
81
+ reduce_features firing: args.first
82
+ end
83
+
84
+ def flux *args
85
+ return reduce_features features.select { |f| f.is_a? YPetri::Net::State::Feature::Flux } if args.empty?
86
+ reduce_features flux: args.first
87
+ end
88
+
89
+ def gradient *args
90
+ return reduce_features features.select { |f| f.is_a? YPetri::Net::State::Feature::Gradient } if args.empty?
91
+ reduce_features gradient: args
92
+ end
93
+
94
+ def delta *args
95
+ return reduce_features features.select { |f| f.is_a? YPetri::Net::State::Feature::Delta } if args.empty?
96
+ reduce_features delta: args
97
+ end
98
+
99
+ # Outputs the current recording in CSV format.
100
+ #
101
+ def to_csv
102
+ map { |lbl, rec| [ lbl, *rec ].join ',' }.join "\n"
103
+ end
104
+
105
+ # Plots the dataset.
106
+ #
107
+ def plot time: nil, **nn
108
+ events = events()
109
+ data_ss = series
110
+ x_range = if time.is_a? Range then
111
+ "[#{time.begin}:#{time.end}]"
112
+ else
113
+ "[-0:#{SY::Time.magnitude( time ).amount rescue time}]"
114
+ end
115
+
116
+ Gnuplot.open do |gp|
117
+ Gnuplot::Plot.new gp do |plot|
118
+ plot.xrange x_range
119
+ plot.title nn[:title] || "#{net} plot"
120
+ plot.ylabel nn[:ylabel] || "Values"
121
+ plot.xlabel nn[:xlabel] || "Time [s]"
122
+
123
+ features.labels.zip( data_ss )
124
+ .each { |label, data_array|
125
+ plot.data << Gnuplot::DataSet.new( [ events, data_array ] ) { |ds|
126
+ ds.with = "linespoints"
127
+ ds.title = label
128
+ }
129
+ }
130
+ end
131
+ end
132
+ end
133
+ end # class Dataset
134
+ end # class Features
135
+ end # YPetri::Simulation::State
@@ -0,0 +1,50 @@
1
+ class YPetri::Net::State
2
+ class Features
3
+ # A collection of values for a given set of state features.
4
+ #
5
+ class Record < Array
6
+ class << self
7
+ delegate :State,
8
+ :net,
9
+ to: "Features()"
10
+
11
+ # Construcs a new Record object from a given collection of values.
12
+ #
13
+ def load values
14
+ new( values.dup )
15
+ end
16
+ end
17
+
18
+ delegate :Features,
19
+ :State,
20
+ :net,
21
+ :features,
22
+ to: "self.class"
23
+
24
+ # Outputs the record as a plain array.
25
+ #
26
+ def dump precision: nil
27
+ features.map { |f| fetch( f ).round( precision ) }
28
+ end
29
+
30
+ # Returns an identified feature, or fails.
31
+ #
32
+ def fetch feature
33
+ super begin
34
+ Integer( feature )
35
+ rescue TypeError
36
+ features.index State().feature( feature )
37
+ end
38
+ end
39
+
40
+ # Returns the state instance implied by the receiver record, and a set of
41
+ # complementary marking clamps supplied as the argument.
42
+ #
43
+ def state marking_clamps: {}
44
+ State.new self, marking_clamps: marking_clamps
45
+ end
46
+
47
+ delegate :reconstruct, to: :state
48
+ end # class Record
49
+ end # class Features
50
+ end # YPetri::Net::State
@@ -0,0 +1,126 @@
1
+ # encoding: utf-8
2
+
3
+ class YPetri::Net::State
4
+ # A set of state features.
5
+ #
6
+ class Features < Array
7
+ require_relative 'features/record'
8
+ require_relative 'features/dataset'
9
+
10
+ class << self
11
+ # Customization of the parametrize method for the Features class: Its
12
+ # dependents Record and Dataset are also parametrized.
13
+ #
14
+ def parametrize parameters
15
+ Class.new( self ).tap do |subclass|
16
+ parameters.each_pair { |symbol, value|
17
+ subclass.define_singleton_method symbol do value end
18
+ }
19
+ subclass.param_class( { Record: Record, Dataset: Dataset },
20
+ with: { Features: subclass } )
21
+ end
22
+ end
23
+
24
+ delegate :net,
25
+ :Feature,
26
+ :feature,
27
+ to: "State()"
28
+
29
+ delegate :Marking,
30
+ :Firing,
31
+ :Gradient,
32
+ :Flux,
33
+ :Delta,
34
+ to: "Feature()"
35
+
36
+ delegate :load, to: :Record
37
+
38
+ alias __new__ new
39
+
40
+ def new features
41
+ ff = features.map &method( :feature )
42
+ __new__( ff ).tap do |inst|
43
+ # Parametrize them <em>one more time</em> with Features instance.
44
+ # Banged version of #param_class! ensures that #Record, #Dataset
45
+ # methods are shadowed.
46
+ inst.param_class!( { Record: Record(), Dataset: Dataset() },
47
+ with: { features: inst } )
48
+ end
49
+ end
50
+
51
+ def marking places=net.pp
52
+ new net.pp( places ).map { |p| Marking( p ) }
53
+ end
54
+
55
+ def firing transitions=net.tS_tt
56
+ new net.tS_tt( transitions ).map { |t| Firing( t ) }
57
+ end
58
+
59
+ def gradient places=net.pp, transitions: net.T_tt
60
+ tt = net.T_tt( transitions )
61
+ new net.pp( places ).map { |p|
62
+ Gradient( p, transitions: tt )
63
+ }
64
+ end
65
+
66
+ def flux transitions=net.TS_tt
67
+ new net.TS_tt( transitions ).map { |t| Flux( t ) }
68
+ end
69
+
70
+ def delta places=net.pp, transitions: net.tt
71
+ transitions = net.tt( transitions )
72
+ new net.pp( places ).map { |p|
73
+ Delta( p, transitions: transitions )
74
+ }
75
+ end
76
+ end
77
+
78
+ delegate :State,
79
+ :net,
80
+ :Feature,
81
+ :feature,
82
+ :Marking,
83
+ :Firing,
84
+ :Gradient,
85
+ :Flux,
86
+ :Delta,
87
+ :load,
88
+ to: "self.class"
89
+
90
+ # Extracts the features from a given target
91
+ #
92
+ def extract_from target, **nn
93
+ Record().new( map { |feature| feature.extract_from( target, **nn ) } )
94
+ end
95
+
96
+ # Constructs a new dataset from these features.
97
+ #
98
+ def new_dataset
99
+ Dataset().new
100
+ end
101
+
102
+ # Feature summation -- of feature class.
103
+ #
104
+ def + other
105
+ self.class.new( super )
106
+ end
107
+
108
+ # Feature summation -- of feature class.
109
+ #
110
+ def - other
111
+ self.class.new( super )
112
+ end
113
+
114
+ # Feature summation -- of feature class.
115
+ #
116
+ def * other
117
+ self.class.new( super )
118
+ end
119
+
120
+ # Feature labels.
121
+ #
122
+ def labels
123
+ map &:label
124
+ end
125
+ end # class Features
126
+ end # YPetri::Net::State
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+
3
+ class YPetri::Net
4
+ # Petri net state (marking of all its places).
5
+ #
6
+ class State < Array
7
+ require_relative 'state/feature'
8
+ require_relative 'state/features'
9
+
10
+ class << self
11
+ # Customization of the parametrize method for the State class: Its
12
+ # dependents Feature and Features (ie. feature set) are also parametrized.
13
+ #
14
+ def parametrize net: (fail ArgumentError, "No owning net!")
15
+ Class.new( self ).tap do |subclass|
16
+ subclass.define_singleton_method :net do net end
17
+ subclass.param_class( { Feature: Feature,
18
+ Features: Features },
19
+ with: { State: subclass } )
20
+ end
21
+ end
22
+
23
+ delegate :Marking,
24
+ :Firing,
25
+ :Gradient,
26
+ :Flux,
27
+ :Delta,
28
+ to: "Feature()"
29
+
30
+ alias __new__ new
31
+
32
+ # Revives a state from a record and a given set of marking clamps.
33
+ #
34
+ def new record, marking_clamps: {}
35
+ cc = marking_clamps.with_keys { |k| net.place k }.with_values! do |v|
36
+ case v
37
+ when YPetri::Place then v.marking
38
+ when ~:call then v.call
39
+ else v end
40
+ end
41
+
42
+ record = features( marking: net.pp - cc.keys ).load( record )
43
+
44
+ __new__ net.pp.map do |p|
45
+ begin; cc.fetch p; rescue IndexError
46
+ record.fetch Marking().of( p )
47
+ end
48
+ end
49
+ end
50
+
51
+ # Returns the feature identified by the argument.
52
+ #
53
+ def feature id
54
+ case id
55
+ when Feature() then id
56
+ when Feature then id.class.new( id )
57
+ else
58
+ features( id ).tap do |ff|
59
+ ff.size == 1 or fail ArgumentError, "Argument #{id} must identify " +
60
+ "exactly 1 feature!"
61
+ end.first
62
+ end
63
+ end
64
+
65
+ # If the argument is an array of features, or another Features instance,
66
+ # a feature set based on this array is returned. But the real purpose of
67
+ # this method is to allow hash-type argument, with keys +:marking+,
68
+ # +:firing+, +:gradient+, +:flux+ and +:delta+, specifying the respective
69
+ # features. For +:marking+, an array of places (or Marking features) is
70
+ # expected. For +:firing+ and +:flux+, an array of transitions (or Firing
71
+ # / Flux features) is expected. For +:gradient+ and +:delta+, a hash value
72
+ # is expected, containing keys +:places+ and +:transitions+, specifying
73
+ # for which place set / transition set should gradient / delta features
74
+ # be constructed. More in detail, values supplied under keys +:marking+,
75
+ # +:firing+, +:gradient+, +:flux+ and +:delta+ are delegated to
76
+ # +Features.marking+, +Features.firing+, +Features.gradient+ and
77
+ # +Features.flux+ methods, and their results are joined into a single
78
+ # feature set.
79
+ #
80
+ def features arg
81
+ case arg
82
+ when Features(), Array then Features().new( arg )
83
+ else # the real job of the method
84
+ marking = arg[:marking] || []
85
+ firing = arg[:firing] || [] # array of tS transitions
86
+ gradient = arg[:gradient] || [ [], transitions: [] ]
87
+ flux = arg[:flux] || [] # array of TS transitions
88
+ delta = arg[:delta] || [ [], transitions: [] ]
89
+ [ Features().marking( marking ),
90
+ Features().firing( firing ),
91
+ Features().gradient( *gradient ),
92
+ Features().flux( flux ),
93
+ Features().delta( *delta ) ].reduce :+
94
+ end
95
+ end
96
+
97
+ delegate :marking, :firing, :gradient, :flux, :delta, to: "Features()"
98
+ end
99
+
100
+ # For non-parametrized vesion of the class, the class instance variables
101
+ # hold the non-parametrized dependent classes.
102
+ #
103
+ @Feature, @Features = Feature, Features
104
+
105
+ delegate :net,
106
+ :Feature,
107
+ :Features,
108
+ :features,
109
+ :marking, :firing, :gradient, :flux, :delta,
110
+ to: "self.class"
111
+
112
+ # Reconstructs a simulation from the current state instance, given marking
113
+ # clamps and other simulation settings.
114
+ #
115
+ def reconstruct marking_clamps: {}, **settings
116
+ net.simulation marking: to_hash,
117
+ marking_clamps: marking_clamps,
118
+ **settings
119
+ end
120
+ end # class State
121
+ end # YPetri::Net
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ class YPetri::Net
4
+ # A mixin for timed nets, used by +#extend+ call during init.
5
+ #
6
+ module Timed
7
+ end # module Timed
8
+ end # class YPetri::Net
@@ -19,10 +19,10 @@ class YPetri::Net
19
19
  ꜧ[tr] = γ.add_nodes tr.name.to_s,
20
20
  shape: 'box',
21
21
  fillcolor: if tr.assignment? then 'yellow'
22
- elsif tr.basic_type == :SR then 'lightcyan'
22
+ elsif tr.type == :TS then 'lightcyan'
23
23
  else 'ghostwhite' end,
24
24
  color: if tr.assignment? then 'goldenrod'
25
- elsif tr.basic_type == :SR then 'cyan'
25
+ elsif tr.type == :TS then 'cyan'
26
26
  else 'grey' end,
27
27
  style: 'filled'
28
28
  end
@@ -35,7 +35,7 @@ class YPetri::Net
35
35
  ( tr.domain - tr.codomain ).each { |pl|
36
36
  γ.add_edges tr_node, place_nodes[pl], color: 'grey', arrowhead: 'none'
37
37
  }
38
- elsif tr.basic_type == :SR then
38
+ elsif tr.type == :TS then
39
39
  tr.codomain.each { |pl|
40
40
  if tr.stoichio[pl] > 0 then # producing arc
41
41
  γ.add_edges tr_node, place_nodes[pl], color: 'cyan'