y_petri 2.4.6 → 2.4.8

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