y_petri 2.4.6 → 2.4.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 22a302201ca7709ed6061786b211385f5c1ae7a1
4
- data.tar.gz: d8d30ab9b582179a79d69a541076a135a62fe32a
3
+ metadata.gz: 7d3c0ff2334a05d996f1a735b660efd890de6c81
4
+ data.tar.gz: d994bc1a0f2a7f38966482f5abdf9db7b8dbec5b
5
5
  SHA512:
6
- metadata.gz: 583d5b7651ac596dc211a148d630dc5949ce52e7ef302e827e4bc13315fad8394aa8314a29a3763e13a94a56b2829c1c856d02f1f5fedc21268c98bce123c88c
7
- data.tar.gz: f8e18341fdc25dcb6cf99751ebc11dc3feb2b400cbb516931ff6654562dc065bd1845c8b320669abf6bab8b8811aeff63ed721d4ddd0dd4e6d3049c1f2bba941
6
+ metadata.gz: 32baae30b3f9e610fc483a0557c2f0309666bdbe65155f309002389290fb384979f106a2d7f7c78efc29ea6c94a9acb523cfc032e197ae3b9b0973db932c105a
7
+ data.tar.gz: 6b2a8788679308f900331d12f553108ce1801289b674530a76e0767be773c78b086560193f2c86a35c6e22a9ed40d67118ecf12c1937f0ac511e86661fdda0e8
@@ -30,6 +30,26 @@
30
30
  # from it or otherwise integrate with it for the purposes of +DataSet+.
31
31
  #
32
32
  class YPetri::Net::DataSet < Hash
33
+ # FIXME: User story:
34
+ #
35
+ # I ran a long simulation (Virginia Tech cell cycle) and then
36
+ # I found that instead of 200_000 time units, I ran it for
37
+ # 360_000 time units. As we know, method recording (or
38
+ # simulation.recording is of DataSet type. I had troubles
39
+ # cutting down the recording to 200_000 time units.
40
+ # I had these troubles because there is no special select
41
+ # method defined for DataSet, or no way to only select
42
+ # the keys within certain time range, and Hash#select and
43
+ # other built-in Hash methods return Hash type which no
44
+ # longer can be plotted easily. Add a way of taking only
45
+ # certain records, or certain time section
46
+ #
47
+ # Finally, I found that #plot method directly accepts
48
+ # :time alias :time_range parameter, which can be used
49
+ # to do what I want. But I still think DataSet should have
50
+ # a method for cutting itself down to only certain lines.
51
+ # We cannot rely on Gnuplot :x_range parameter only...
52
+
33
53
  class << self
34
54
  alias __new__ new
35
55
 
@@ -345,20 +365,28 @@ class YPetri::Net::DataSet < Hash
345
365
  map { |lbl, rec| [ lbl, *rec ].join ',' }.join( "\n" )
346
366
  end
347
367
 
348
- # Plots the dataset. Takes several optional arguments: The list of nodes can be
349
- # supplied as optional first ordered argument, which are then converted into
350
- # features using +Net::State::Features.infer_from_nodes+ method. Similarly,
351
- # the features to exclude can be specifies as a list of nodes (or a
352
- # feature-specifying hash) supplied under +except:+ keyword. Otherwise, feature
353
- # specification can be passed to the method as named arguments. If no feature
354
- # specification is explicitly provided, it is assumed that all the features of
355
- # this dataset are meant to be plotted.
368
+ # Plots the dataset using Ruby Gnuplot gem. Takes several
369
+ # optional arguments: The list of nodes to plot can be
370
+ # supplied as optional first ordered argument. If supplied,
371
+ # the nodes are converted into features using
372
+ # +Net::State::Features.infer_from_nodes+ method. Similarly,
373
+ # the features to exclude can be specified as a list of
374
+ # nodes supplied under +except:+ parameter. Under +except:+
375
+ # parameter, it is also possible to supply a
376
+ # feature-specifying hash. Otherwise, feature specification
377
+ # can be passed to the method via named arguments. By
378
+ # default, it is assumed that the caller means to plot all
379
+ # the features of this dataset.
380
+ #
381
+ # Named arguments admit Gnuplot keywords that control the
382
+ # plot. These parameters include +title:+, +xlabel:+ and
383
+ # +ylabel:+.
356
384
  #
357
385
  def plot( nodes=nil, except: [], **named_args )
358
386
  nn = named_args
359
387
  time = nn.may_have :time, syn!: :time_range
360
388
  events = events()
361
- # Figure out features.
389
+ # Figure out the features to plot.
362
390
  ff = if nodes.nil? then
363
391
  nn_ff = nn.slice [ :marking, :flux, :firing,
364
392
  :gradient, :delta, :assignment ]
@@ -366,7 +394,8 @@ class YPetri::Net::DataSet < Hash
366
394
  else
367
395
  net.State.Features.infer_from_nodes( nodes )
368
396
  end
369
- # Figure out the features not to plot ("except" features).
397
+ # Figure out the features to exclude from plotting
398
+ # ("except" features).
370
399
  xff = case except
371
400
  when Array then net.State.Features.infer_from_nodes( except )
372
401
  when Hash then net.State.Features( except )
@@ -8,18 +8,50 @@ module YPetri::Net::OwnState
8
8
  # class (a subclass of Array), containing marking owned by the net's places.
9
9
  #
10
10
  def state
11
- State().new( marking )
11
+ State().new( m )
12
+ end
13
+
14
+ # Like #m method, but instead of returning an array of markings, it returns
15
+ # a string of the form "A: 1, B: 2, ...", where A, B, ... are the places
16
+ # and 1, 2, ... their marking. This method is intended to produce output
17
+ # easy to read by humans, while #m method produces regular output (an
18
+ # Array) suitable for further processing. Method accepts arbitrary number
19
+ # of optional arguments, each of which must be a place identifier. If
20
+ # no arguments are given, full marking of the net is described. If
21
+ # arguments are given, only marking of the places identified by the
22
+ # arguments is described.
23
+ #
24
+ def marking *place_ids
25
+ return pp.size == 0 ? "" : marking( *pp ) if place_ids.empty?
26
+ a = [ place_ids.map { |id| place( id ) },
27
+ m( place_ids ) ].transpose
28
+ a.map { |pair| pair.join ": " }.join ', '
12
29
  end
13
30
 
14
31
  # If no argument is supplied, the method returns the array of the markings
15
32
  # owned by the net's places. If an array of place identifiers is supplied,
16
33
  # the return value is the array of the markings owned by those places.
17
- #
18
- def marking place_ids=nil
19
- return marking( pp ) if place_ids.nil?
34
+ #
35
+ def m place_ids=nil
36
+ return m( pp ) if place_ids.nil?
20
37
  place_ids.map { |id| place( id ).marking }
21
38
  end
22
- alias m marking
39
+
40
+ # If no argument is supplied, the method resets its places to their default
41
+ # marking. If an array of place identifiers is supplied, only the specified
42
+ # places are reset. Attempts to reset places that have no default marking
43
+ # result in +TypeError+.
44
+ #
45
+ def reset! place_ids=nil
46
+ return reset!( pp ) if place_ids.nil?
47
+ place_ids.map { |id|
48
+ begin
49
+ place( id ).reset_marking
50
+ rescue TypeError => err
51
+ raise TypeError, "Unable to reset the net! " + err.message
52
+ end
53
+ }
54
+ end
23
55
 
24
56
  # Takes an array of tS transition identifiers as an optional argument, and
25
57
  # returns the array of their firing under current net state. If no argument
@@ -55,7 +87,7 @@ module YPetri::Net::OwnState
55
87
  fail NotImplementedError
56
88
  end
57
89
 
58
- # Takes an array of place identifier, and a named argument +:transitions+,
90
+ # Takes an array of place identifiers, and a named argument +:transitions+,
59
91
  # and returns the array of the place delta contribution by the indicated
60
92
  # transitions.
61
93
  #
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  # A feature set. In other words, a set of state features, such as marking,
4
- # flux etc.
4
+ # flux etc. The supported features are:
5
5
  #
6
6
  # marking:: Applicable to all places, all places have marking.
7
7
  # firing:: Applicable to all stoichiometric transitions, but delta time has
data/lib/y_petri/net.rb CHANGED
@@ -171,7 +171,7 @@ class YPetri::Net
171
171
  # Networks are equal when their places and transitions are equal.
172
172
  #
173
173
  def == other
174
- return false unless other.class_complies?( self.class )
174
+ return false unless other.class_complies? self.class
175
175
  places == other.places && transitions == other.transitions
176
176
  end
177
177
 
data/lib/y_petri/place.rb CHANGED
@@ -151,6 +151,8 @@ class YPetri::Place
151
151
  # instance variable).
152
152
  #
153
153
  def reset_marking
154
+ fail TypeError, "No default marking was specified for #{self}!" unless
155
+ has_default_marking?
154
156
  @marking = guard.( @default_marking )
155
157
  end
156
158
 
@@ -353,29 +353,34 @@ module YPetri::Simulation::Timed
353
353
 
354
354
  rk_core.step! Δt
355
355
 
356
- # TODO: In the above lines, setting rec = recorder and then calling rec!.alert in
357
- # the block is a bit weird. It would be nicer to use recorder.alert!, but maybe
356
+ # TODO: In the above lines, setting rec = recorder and then calling
357
+ # rec!.alert in the block is a bit weird. It would be nicer to use
358
+ # recorder.alert!, but maybe
358
359
  # wise Ruby closure mechanism does not allow it...
359
360
  end # def step!
360
- end
361
- else
361
+ end # singleton_class.class_exec
362
+ else # the method is not :runge_kutta
362
363
  @core = if @guarded then
363
- YPetri::Core::Timed.new( simulation: self, method: method, guarded: true )
364
+ YPetri::Core::Timed.new( simulation: self,
365
+ method: method, guarded: true )
364
366
  else
365
- YPetri::Core::Timed.new( simulation: self, method: method, guarded: false )
367
+ YPetri::Core::Timed.new( simulation: self,
368
+ method: method, guarded: false )
366
369
  end
367
- # TODO: But why am I doing it like this? Did I want to emphasize the standalone
368
- # nature of Core class? Maybe... And maybe I did it so that the runge-kutta method
369
- # with its @rk_core instance variable instead of @core does not have @core and #core.
370
- # In this manner, I'm forcing myself to rethink Simulation class.
370
+ # TODO: But why am I doing it like this? Did I want to
371
+ # emphasize the standalone nature of Core class? Maybe... And
372
+ # maybe I did it so that the runge-kutta method with its
373
+ # @rk_core instance variable instead of @core does not have
374
+ # @core and #core. In this manner, I'm forcing myself to
375
+ # rethink Simulation class.
371
376
  singleton_class.class_exec do
372
377
  attr_reader :core
373
378
  delegate :simulation_method, # this looks quite redundant with simulation.rb
374
379
  :step!,
375
380
  :firing_vector_tS,
376
381
  to: :core
377
- end
378
- end
382
+ end # singleton_class.class_exec
383
+ end
379
384
  @recorder = if features_to_record then
380
385
  # we'll have to figure out features
381
386
  ff = case features_to_record
@@ -5,29 +5,49 @@ require_relative 't'
5
5
  require_relative 'A'
6
6
 
7
7
  module YPetri::Transition::Types
8
- # Is this a timed stoichiometric transition?
8
+ # Is this a transition with assignment action? (Transitions with assignment
9
+ # action, or "assignment transitions", completely replace the marking of their
10
+ # codomain with their action closure result, like in spreadsheets.)
9
11
  #
10
- def TS?
11
- type == :TS
12
+ def assignment_action?
13
+ @assignment_action
12
14
  end
15
+ alias assignment? assignment_action?
16
+ alias A? assignment_action?
13
17
 
14
- # Is this a timed non-stoichiometric transition?
18
+ # Is this a non-assignment transition? (Opposite of +#A?+)
15
19
  #
16
- def Ts?
17
- type == :Ts
20
+ def a?
21
+ ! assignment_action?
18
22
  end
19
23
 
24
+ # Is this a timeless non-stoichiometric transition?
25
+ #
26
+ def ts?
27
+ type == :ts
28
+ end
29
+ alias B? ts?
30
+
20
31
  # Is this a timeless stoichiometric transition?
21
32
  #
22
33
  def tS?
23
34
  type == :tS
24
35
  end
36
+ alias C? tS?
25
37
 
26
- # Is this a timeless non-stoichiometric transition?
38
+ # Is this a timed non-stoichiometric transition?
27
39
  #
28
- def ts?
29
- type == :ts
40
+ def Ts?
41
+ type == :Ts
30
42
  end
43
+ alias D? Ts?
44
+
45
+ # Is this a timed stoichiometric transition?
46
+ #
47
+ def TS?
48
+ type == :TS
49
+ end
50
+ alias E? TS?
31
51
 
32
52
  # Is this a stoichiometric transition?
33
53
  #
@@ -78,35 +98,50 @@ module YPetri::Transition::Types
78
98
  not functional?
79
99
  end
80
100
 
81
- # Reports the transition's membership in one of the 4 basic types:
82
- #
83
- # 1. TS .... timed stoichiometric
84
- # 2. tS .... timeless stoichiometric
85
- # 3. Ts .... timed nonstoichiometric
86
- # 4. ts .... timeless nonstoichiometric
101
+ # Reports the transition's membership in one of the 5 basic types
102
+ # using one-letter abbreviation:
87
103
  #
88
- # plus the fifth type
104
+ # 1. A .... assignment
105
+ # 2. B .... timeless nonstoichiometric (ts)
106
+ # 3. C .... timeless stoichiometric (tS)
107
+ # 4. D .... timed nonstoichiometric (Ts)
108
+ # 5. E .... timed stoichiometric (TS)
89
109
  #
90
- # 5. A .... assignment transitions
91
- #
92
- def type
110
+ def t
93
111
  return :A if assignment_action?
94
- timed? ? ( stoichiometric? ? :TS : :Ts ) : ( stoichiometric? ? :tS : :ts )
112
+ timed? ? ( stoichiometric? ? :E : :D ) : ( stoichiometric? ? :C : :B )
95
113
  end
96
114
 
97
- # Is this a transition with assignment action? (Transitions with assignment
98
- # action, or "assignment transitions", completely replace the marking of their
99
- # codomain with their action closure result, like in spreadsheets.)
115
+ # Reports the transition's membership in one of the 5 basic types
116
+ # using two-letter abbreviation + A for assignment transition.
117
+ # This methods reflects the fact that the new users may take time
118
+ # to memorize the meaning of A, B, C, D, E transition types.
119
+ # Two-letter abbreviations may be easier to figure out.
120
+ #
121
+ # 1. A .... assignment transitions (A-type)
122
+ # 2. ts .... timeless nonstoichiometric (B-type)
123
+ # 3. tS .... timeless stoichiometric (C-type)
124
+ # 4. Ts .... timed nonstoichiometric (D-type)
125
+ # 5. TS .... timed stoichiometric (E-type)
100
126
  #
101
- def assignment_action?
102
- @assignment_action
127
+ def type
128
+ { A: :A, B: :ts, C: :tS, D: :Ts, E: :TS }[ t ]
103
129
  end
104
- alias assignment? assignment_action?
105
- alias A? assignment_action?
106
130
 
107
- # Is this a non-assignment transition? (Opposite of +#A?+)
108
- #
109
- def a?
110
- ! assignment_action?
131
+ # Reports the transition's membership in one of the 5 basic types
132
+ # as a full string.
133
+ #
134
+ # 1. assignment (A-type)
135
+ # 2. timeless nonstoichiometric (B-type)
136
+ # 3. timeless stoichiometric (C-type)
137
+ # 4. timed nonstoichiometric (D-type)
138
+ # 5. timed stoichiometric (E-type)
139
+ #
140
+ def type_full
141
+ { A: "assignment",
142
+ ts: "timeless nonstoichiometric",
143
+ tS: "timeless stoichiometric",
144
+ Ts: "timed nonstoichiometric",
145
+ TS: "timed stoichiometric" }[ type ]
111
146
  end
112
147
  end # class YPetri::Transition::Types
@@ -1,4 +1,4 @@
1
1
  module YPetri
2
- VERSION = "2.4.6"
2
+ VERSION = "2.4.8"
3
3
  DEBUG = false
4
4
  end
data/test/net_test.rb CHANGED
@@ -35,6 +35,24 @@ describe YPetri::Net do
35
35
  @net.Places( [] ).must_equal []
36
36
  @net.places( :A ).must_equal [ p ]
37
37
  end
38
+
39
+ describe "#reset!" do
40
+ it "should work as expected" do
41
+ place_with_default_marking =
42
+ @w.Place.send :new, name: "A", default_marking: 42
43
+ place_without_default_marking =
44
+ @w.Place.send :new, name: "B", marking: 43
45
+ @net.include_place( place_with_default_marking )
46
+ place_with_default_marking.marking = 0
47
+ @net.reset!
48
+ assert place_with_default_marking.marking == 42
49
+ @net.include_place( place_without_default_marking )
50
+ place_with_default_marking.marking = 0
51
+ -> { @net.reset! }.must_raise TypeError
52
+ @net.reset! [ :A ]
53
+ assert place_with_default_marking.marking == 42
54
+ end
55
+ end
38
56
  end
39
57
 
40
58
  describe "world with 3 places" do
@@ -78,10 +96,9 @@ describe YPetri::Net do
78
96
  it "should know its state (marking owned by the places)" do
79
97
  @net.state.must_be_kind_of YPetri::Net::State
80
98
  @net.state.must_equal [ @p1, @p2, @p3 ].map( &:marking )
81
- @net.marking.must_equal [ @p1, @p2, @p3 ].map( &:marking )
82
- @net.marking.must_be_kind_of Array
83
- # User-expected #m alias for #marking
84
- @net.m.must_equal @net.marking
99
+ @net.m.must_equal [ @p1, @p2, @p3 ].map( &:marking )
100
+ # Easy-to-read marking information.
101
+ @net.marking.must_equal "A: 1.1, B: 2.2, C: 3.3"
85
102
  end
86
103
 
87
104
  it "should have standard equipment expected of a class" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: y_petri
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.6
4
+ version: 2.4.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - boris
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-24 00:00:00.000000000 Z
11
+ date: 2016-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -131,9 +131,7 @@ files:
131
131
  - ACKNOWLEDGMENT.txt
132
132
  - Gemfile
133
133
  - Introduction_to_Ruby_for_YPetri_and_YNelson_Users.pdf
134
- - Introduction_to_YNelson_and_YPetri.pdf
135
134
  - LICENSE.txt
136
- - Object_model_of_YNelson_and_YPetri.pdf
137
135
  - README.md
138
136
  - Rakefile
139
137
  - lib/y_petri.rb
Binary file
Binary file