y_nelson 0.1.5

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0d19c1eb4d0fca009913f2c4632ea803aafee8a0
4
+ data.tar.gz: 2ae45a24959f7041a7017a0ef44ee1f5023f4b44
5
+ SHA512:
6
+ metadata.gz: e42a83132fbecca38473d47c05ef1e7ecb3d1e134e517c7eda1c18b79b10df80d1d1340eae7e1e896e0027a3dca2339c35b703fb472ea38c5cf7a1874fd29b19
7
+ data.tar.gz: 51d15c79f5210d76e936dc0777285dccf7447b2a5faa59013822429798776c06ee092771f285af058d0c302a8cff0e9912fed75b4b87238cf32ba7fc4b344f2b
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *~
2
+ .#*
3
+ \#*#
4
+ *.gem
5
+ *.rbc
6
+ .bundle
7
+ .config
8
+ .yardoc
9
+ Gemfile.lock
10
+ InstalledFiles
11
+ _yardoc
12
+ coverage
13
+ doc/
14
+ lib/bundler/man
15
+ pkg
16
+ rdoc
17
+ spec/reports
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in y_nelson.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 boris
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # YNelson
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'y_nelson'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install y_nelson
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,43 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Zz dimension can in principle be any object, in YNelson, special class
3
+ # Dimension is used.
4
+ #
5
+ class YNelson::Dimension
6
+ class << self
7
+ alias __new__ new
8
+
9
+ # Presents class-owned instances (array).
10
+ #
11
+ def instances
12
+ return @instances ||= []
13
+ end
14
+
15
+ # The #new constructor is changed, so that same instance is returned for
16
+ # same constructor arguments.
17
+ #
18
+ def new *args
19
+ instances.find { |ɪ| ɪ.object == args } or
20
+ __new__( *args ).tap { |ɪ| instances << ɪ }
21
+ end
22
+ end
23
+
24
+ attr_reader :object
25
+
26
+ # Simply assigns array of arguments to @object atrribute.
27
+ #
28
+ def initialize *args
29
+ @object = args
30
+ end
31
+
32
+ # Short instance description string.
33
+ #
34
+ def to_s
35
+ "#<YNelson::Dimension [#{object.join ', '}]>"
36
+ end
37
+ end # class YNelson::Dimension
38
+
39
+ # Convenience constructor.
40
+ #
41
+ def YNelson.Dimension *args
42
+ YNelson::Dimension.new *args
43
+ end
@@ -0,0 +1,15 @@
1
+ #encoding: utf-8
2
+
3
+ # A pointer to a zz dimension.
4
+ #
5
+ class YNelson::DimensionPoint
6
+ attr_accessor :dimension
7
+
8
+ def initialize dimension
9
+ @dimension = dimension
10
+ end
11
+
12
+ def default_dimension
13
+ YNelson.default_dimension
14
+ end
15
+ end # class YTed::DimensionPoint
@@ -0,0 +1,360 @@
1
+ # -*- coding: utf-8 -*-
2
+ # YNelson user inteface. Ted Nelson, in his introduction of zz structures, has
3
+ # remarks regarding a desired UI, such as:
4
+ #
5
+ # <em>Selection</em> is a pointer to a collection of cells.
6
+ # <em>View</em> consists of selection and a coordinate system.
7
+ # <em>Field<em> is a connected (contiguous) selection.
8
+ # <em>Coordinate system</em> is a collection of oriented dimensions.
9
+ #
10
+ # Apart from that, this manipulator should offer similar functionality as
11
+ # YPetri::Manipulator - that is, should allow constructing a Petri net
12
+ # without much ado about zz aspect, just like YPetri does.
13
+ #
14
+ class YNelson::Manipulator
15
+ attr_reader :workspace
16
+
17
+ include YPetri::Manipulator::PetriNetRelatedMethods
18
+ include YPetri::Manipulator::SimulationRelatedMethods
19
+
20
+ def initialize
21
+ # For YNelson manipulators, the workspace is always YNelson itself.
22
+ @workspace = ::YNelson
23
+ super
24
+ # A hash of sheets. For the moment being, YNelson acts as a spreadsheet.
25
+ @sheets = {}
26
+ # Default dimension of this manipulator.
27
+ @default_dimension = YNelson.Dimension :row
28
+ # Zz object pointers of this manipulator.
29
+ @primary_point = YNelson::ZzPoint.new
30
+ @secondary_point = YNelson::ZzPoint.new
31
+ # Zz dimension pointers of this manipulator.
32
+ @primary_dimension_point =
33
+ YNelson::DimensionPoint.new YNelson.Dimension( :row )
34
+ @secondary_dimension_point =
35
+ YNelson::DimensionPoint.new YNelson.Dimension( :column )
36
+ end
37
+
38
+ # Now the part related to the zz structure itself, like in
39
+ # module YNelson::Manipulator::ZzRelatedMethods
40
+ # blah blah
41
+ # end
42
+ # include YNelson::Manipulator::ZzRelatedMethods
43
+
44
+ attr_reader :sheets
45
+
46
+ # Dimension convenience constructor from
47
+ delegate( :Dimension,
48
+ to: :workspace )
49
+
50
+ # Creation of a single-output formula known well from spreadseets. Given a
51
+ # place, it creates a new assignment transition.
52
+ #
53
+ def ϝ &block
54
+ new_place = YNelson::Place.new
55
+ new_transition = YNelson::Transition.new assignment: true,
56
+ codomain: new_place,
57
+ action: block
58
+ return new_place, new_transition
59
+ end
60
+
61
+ # Now let's look into the graph visualization.
62
+
63
+ def default_dimension; @default_dimension end
64
+
65
+ def primary_point; @primary_point end
66
+ alias p1 primary_point
67
+
68
+ def secondary_point; @secondary_point end
69
+ alias p2 secondary_point
70
+
71
+ def primary_dimension_point; @primary_dimension_point end
72
+ alias d1 primary_dimension_point
73
+
74
+ def secondary_dimension_point; @secondary_dimension_point end
75
+ alias d2 secondary_dimension_point
76
+
77
+ # Define function to display it with kioclient
78
+ def visualize *args, &block; graphviz *args, &block end
79
+
80
+ # Define graphviz places
81
+ def graphviz dim1=primary_dimension_point, dim2=secondary_dimension_point
82
+ γ = GraphViz.new :G, type: :digraph # Create a new graph
83
+
84
+ # main = γ.add_nodes( "main", shape: "box" )
85
+ # parse = γ.add_nodes( "parse", fillcolor: "yellow", style: "rounded,filled", shape: "diamond" )
86
+ # execute = γ.add_nodes( "execute", shape: "record", label: "{ a | b | c }", style: "rounded" )
87
+ # init = γ.add_nodes( "init", fillcolor: "yellow", style: "filled" )
88
+
89
+ # set global node options
90
+ γ.node[:color] = "#ddaa66"
91
+ γ.node[:style] = "filled"
92
+ γ.node[:shape] = "box"
93
+ γ.node[:penwidth] = "1"
94
+ γ.node[:fontname] = "Trebuchet MS"
95
+ γ.node[:fontsize] = "8"
96
+ γ.node[:fillcolor] = "#ffeecc"
97
+ γ.node[:fontcolor] = "#775500"
98
+ γ.node[:margin] = "0.0"
99
+
100
+ # set global edge options
101
+ γ.edge[:color] = "#999999"
102
+ γ.edge[:weight] = "1"
103
+ γ.edge[:fontsize] = "6"
104
+ γ.edge[:fontcolor] = "#444444"
105
+ γ.edge[:fontname] = "Verdana"
106
+ γ.edge[:dir] = "forward"
107
+ γ.edge[:arrowsize] = "0.5"
108
+
109
+ # add zz objects
110
+ place_nodes = places.map.with_object Hash.new do |place, ꜧ|
111
+ ꜧ[place] = γ.add_nodes place.name.to_s
112
+ end
113
+ transition_nodes = transitions.map.with_object Hash.new do |transition, ꜧ|
114
+ ꜧ[transition] = γ.add_nodes transition.name.to_s
115
+ end
116
+ nodes = place_nodes.merge transition_nodes
117
+ # add edges for selected dimensions
118
+ nodes.each { |instance, node|
119
+ negward_neighbor = instance.( dim1 ).negward.neighbor
120
+ nodes[ negward_neighbor ] << node if negward_neighbor # color 1
121
+ negward_neighbor = instance.( dim2 ).negward.neighbor
122
+ nodes[ negward_neighbor ] << node if negward_neighbor # color 2
123
+ }
124
+
125
+ γ.output png: "zz.png" # Generate output image
126
+ YSupport::KDE.show_file_with_kioclient File.expand_path( '.', "zz.png" )
127
+
128
+ # main = γ.add_nodes( "main", shape: "box" )
129
+ # parse = γ.add_nodes( "parse", fillcolor: "yellow", style: "rounded,filled", shape: "diamond" )
130
+ # execute = γ.add_nodes( "execute", shape: "record", label: "{ a | b | c }", style: "rounded" )
131
+ # init = γ.add_nodes( "init", fillcolor: "yellow", style: "filled" )
132
+ end
133
+
134
+ # graphviz [:domain, 0 ], [:codomain, 0]
135
+
136
+ # Cell side referencers with r. to primary and secondary point
137
+ def ξ_posward_side dim=nil; ::YTed::POINT.posward_side dim end
138
+ alias :ξp :ξ_posward_side
139
+ def ξ_negward_side dim=nil; ::YTed::POINT.negward_side dim end
140
+ alias :ξn :ξ_negward_side
141
+ def ξ2_posward_side dim=nil; ::YTed::POINT2.posward_side dim end
142
+ alias :ξ2p :ξ2_posward_side
143
+ def ξ2_negward_side dim=nil; ::YTed::POINT2.negward_side dim end
144
+ alias :ξ2n :ξ2_negward_side
145
+
146
+ # Point walkers
147
+ def ξ_step_posward dim=nil; ::YTed::POINT.step_posward dim end
148
+ alias :ξp! :ξ_step_posward
149
+ def ξ_step_negward dim=nil; ::YTed::POINT.step_negward dim end
150
+ alias :ξn! :ξ_step_negward
151
+ def ξ2_step_posward dim=nil; ::YTed::POINT2.step_posward dim end
152
+ alias :ξ2p! :ξ2_step_posward
153
+ def ξ2_step_negward dim=nil; ::YTed::POINT2.step_negward dim end
154
+ alias :ξ2n! :ξ2_step_negward
155
+
156
+ # Point rank rewinders
157
+ # (rewinders without exclamation mark expect block or return enumerator
158
+ def ξ_rewind_posward *aa, &b; ::YTed::POINT.rewind_posward *aa, &b end
159
+ alias :ξrp :ξ_rewind_posward
160
+ def ξ_rewind_negward *aa, &b; ::YTed::POINT.rewind_negward *aa, &b end
161
+ alias :ξpp :ξ_rewind_posward
162
+ def ξ2_rewind_posward *aa, &b; ::YTed::POINT.rewind_posward *aa, &b end
163
+ alias :ξ2rp :ξ2_rewind_posward
164
+ def ξ2_rewind_negward *aa, &b; ::YTed::POINT.rewind_negward *aa, &b end
165
+ alias :ξ2pp :ξ2_rewind_posward
166
+
167
+ # Point rak rewinters with exclamation mark (no block or enum, just do it)
168
+ def ξ_rewind_posward! dim=nil; ::YTed::POINT.rewind_posward! dim end
169
+ alias :ξrn! :ξ_rewind_posward!
170
+ alias :ξnn! :ξ_rewind_posward!
171
+ def ξ_rewind_negward! dim=nil; ::YTed::POINT.rewind_negward! dim end
172
+ alias :ξrn! :ξ_rewind_negward!
173
+ alias :ξnn! :ξ_rewind_negward!
174
+ def ξ2_rewind_posward! dim=nil; ::YTed::POINT2.rewind_posward! dim end
175
+ alias :ξ2rp! :ξ2_rewind_posward!
176
+ alias :ξ2pp! :ξ2_rewind_posward!
177
+ def ξ2_rewind_negward! dim=nil; ::YTed::POINT2.rewind_negward! dim end
178
+ alias :ξ2rn! :ξ2_rewind_negward!
179
+ alias :ξ2nn! :ξ2_rewind_negward!
180
+
181
+ # Neighbor referencers
182
+ def ξ_posward_neighbor dim=nil; ::YTed::POINT.posward_neighbor dim end
183
+ alias :ξP :ξ_posward_neighbor
184
+ def ξ_negward_neighbor dim=nil; ::YTed::POINT.negward_neighbor dim end
185
+ alias :ξN :ξ_negward_neighbor
186
+ def ξ2_posward_neighbor dim=nil; ::YTed::POINT2.posward_neighbor dim end
187
+ alias :ξ2P :ξ2_posward_neighbor
188
+ def ξ2_negward_neighbor dim=nil; ::YTed::POINT2.negward_neighbor dim end
189
+ alias :ξ2N :ξ2_negward_neighbor
190
+
191
+ # Neighbor redefinition
192
+ def ξ_redefine_posward_neighbor *args
193
+ ::YTed::POINT.redefine_posward_neighbor *args end
194
+ alias :ξP! :ξ_redefine_posward_neighbor
195
+ def ξ_redefine_negward_neighbor *args
196
+ ::YTed::POINT.redefine_negward_neighbor *args end
197
+ alias :ξN! :ξ_redefine_negward_neighbor
198
+ def ξ2_redefine_posward_neighbor *args
199
+ ::YTed::POINT2.redefine_posward_neighbor *args end
200
+ alias :ξ2P! :ξ2_redefine_posward_neighbor
201
+ def ξ2_redefine_negward_neighbor *args
202
+ ::YTed::POINT2.redefine_negward_neighbor *args end
203
+ alias :ξ2N! :ξ2_redefine_negward_neighbor
204
+
205
+
206
+ # FIXME these methods do not work well
207
+ # #rank method creates a rank of connected cells along the given
208
+ # dimension (named arg :dimension, alias :dΞ ), from values given as array
209
+ # (named arg :array, alias :ᴀ). The rank is returned as a cell array.
210
+ def zz_rank( array, dimension )
211
+ array.map{ |e| ZzCell( e ) }.each_consecutive_pair{ |a, b|
212
+ a.redefine_neighbors( dimension: dimension, posward: b )
213
+ }
214
+ end
215
+
216
+ # Zips an array of ZzCells (receiver) with another array of ZzCells
217
+ # in a given dimension. That is, each cell in the first array is made
218
+ # to point (have posward neighbor) to the corresponding cell in the
219
+ # second array.
220
+ def zz_zip( cell_array, dimension )
221
+ cell_array.a℈_all_∈( ::YTed::ZzCell )
222
+ self.a℈_all_∈( ::YTed::ZzCell ).each.with_index{|cell, i|
223
+ cell.redefine_neighbors( dimension: dimension,
224
+ posward: cell_array[i] )
225
+ }
226
+ end
227
+
228
+ # All we need right now is use Zz as a spreadsheet, writing data in rows.
229
+
230
+ # FIXME: Zz properites not used at all - classical Ruby data structures
231
+ # are used instead. ξ is just a holder for sheet name
232
+
233
+ # Creates a new row (rank along :row dimension) zipped to current row
234
+ # along ξ.dim, using the supplied arguments as new row's cell values.
235
+ def new_zz_row *args
236
+ args = args[0].first if args.size == 1 and args[0].is_a? Hash
237
+ previous_row = ( ::YTed::SHEETS[@current_sheet_name][-1] || [] ).dup
238
+ row = args.map{ |a| ZzCell( a ) }
239
+ row.each_consecutive_pair{ |a, b| a.P! x: b } # connect along :x
240
+ row.each{ |e| e.N! y: previous_row.shift } # zip to previous row
241
+ ::YTed::SHEETS[@current_sheet_name] << row
242
+ if row[0].value.is_a? Symbol then
243
+ ::YTed::SHEETS[@current_sheet_name]
244
+ .define_singleton_method args[0] { row[1].aE_kind_of ::YPetri::Place }
245
+ end
246
+ end
247
+ alias :→ :new_zz_row
248
+
249
+ # #new_zz_sheet creates a new sheet with a single cell holding the sheet's
250
+ # name and sets main point to it in :col dimenion sheet name as its value
251
+ def new_zz_sheet( name )
252
+ @current_sheet_name = name
253
+ ::YTed::SHEETS[name] = []
254
+ ::YTed::SHEETS
255
+ .define_singleton_method name.to_sym do ::YTed::SHEETS[name] end
256
+ return ::YTed::SHEETS[name]
257
+ end
258
+
259
+ def make_transitions
260
+ # require 'debug'
261
+ # LATER: When walking around the sheets, currently, there is no
262
+ # protection against references to empty cells
263
+ @transitions_to_make.map { |prescription|
264
+ sheet = prescription[:sheet]
265
+ type = prescription[:type]
266
+ place = prescription[:place]
267
+ block = prescription[:assignment_closure]
268
+
269
+ case type
270
+ when :unary_codomain_w_magic_block
271
+ # PARAMETER MAGIC:
272
+ # Blocks with specially named input arguments
273
+ domain = block.parameters.map{ |e| e[1].to_s }.map{ |param|
274
+ point = ZzPoint.new( place )
275
+ if SHEETS.keys.include? sheet_name = param.split('_')[0] then
276
+ # if the name consists of a sheet and parameter name, then ok
277
+ rest = param[sheet_name.size + 1..-1]
278
+ point = ZzPoint.new( SHEETS[sheet_name][0][0] )
279
+ col = [*('a'..'z')].index rest[0]
280
+ point.rewind_negward! :x
281
+ if rest.size > 1 then # also change row, asssuming "a0" style
282
+ point.rewind_negward! :y
283
+ row = rest[1..-1].to_i
284
+ row.times { point.step_posward :y }
285
+ end
286
+ col.times { point.step_posward :x }
287
+ point.cell
288
+ elsif [*('a'..'z')].include? param[0] then
289
+ # if the name consists of an alphabetic letter...
290
+ col = [*('a'..'z')].index param[0]
291
+ point.rewind_negward! :x
292
+ if param.size > 1 then # also change row, assuming "a0" style
293
+ point.rewind_negward! :y
294
+ row = param[1..-1].to_i
295
+ row.times { point.step_posward :y }
296
+ end
297
+ col.times { point.step_posward :x }
298
+ point.cell
299
+ elsif param[0] = '_' then
300
+ # Params named '_1', '_2', ... refer to different rows, same :col,
301
+ # param named '__' refers to same cell
302
+ if param == '__' then cell else
303
+ i = param[1..-1].to_i
304
+ point.rewind_negward! :y
305
+ i.times { point.step_posward :x }
306
+ point.cell
307
+ end
308
+ else
309
+ raise TypeError, "unrecognized magic block parameter: #{param}"
310
+ end
311
+ } # block.parameters.map
312
+
313
+ # Instantiate the new transition (do not fire it yet):
314
+ Transition( domain: domain,
315
+ codomain: [ place ],
316
+ action_closure: block,
317
+ assignment_action: true )
318
+ when :downstream_copy
319
+ # DOWNSTREAM COPY
320
+ # A single transition assigning upstream value to the downstream cell
321
+ Transition( domain: prescription[:domain],
322
+ codomain: [ place ],
323
+ action_closure: λ {|v| v },
324
+ assignment_action: true )
325
+ else raise "Unknown transition prescription type: #{prescription[:type]}"
326
+ end
327
+ } # @transitions_to_make.map
328
+ end
329
+
330
+ # Places an order for a spreadsheet-like assignment transition. The order
331
+ # will be fullfilled later when #make_transitions method is called.
332
+ #
333
+ def new_downstream_cell &block
334
+ # The place can be instatiated right away
335
+ place = ZzCell( nil )
336
+
337
+ # Transition making requests get remembered in @transitions_to_make:
338
+ ( @transitions_to_make ||= [] ) <<
339
+ { place: place,
340
+ sheet: @current_sheet_name,
341
+ assignment_closure: block,
342
+ type: :unary_codomain_w_magic_block }
343
+ return place
344
+ end
345
+ alias :ϝ :new_downstream_cell
346
+
347
+ # Places an order for a spreadsheet-lie pure reference to another cell.
348
+ #
349
+ def new_downstream_copy( cell )
350
+ # Again, the place can be instantiated immediately
351
+ p = ZzCell( nil )
352
+
353
+ # And put the transition making request to @transitions_to_make:
354
+ ( @transitions_to_make ||= [] ) <<
355
+ { place: p, sheet: @current_sheet_name, domain: cell,
356
+ type: :downstream_copy }
357
+ return p
358
+ end
359
+ alias :↱ :new_downstream_copy
360
+ end
@@ -0,0 +1,12 @@
1
+ # Represents Petri nets inside the Nelson net.
2
+ #
3
+ class YNelson::Net < YPetri::Net
4
+
5
+ private
6
+
7
+ # Place, Transition, Net class
8
+ #
9
+ def Place; ::YNelson::Place end
10
+ def Transition; ::YNelson::Transition end
11
+ def Net; ::YNelson::Net end
12
+ end # class YNelson::Net
@@ -0,0 +1,28 @@
1
+ # YNelson::Place is analogical to a spreadsheet cell. It is based on
2
+ # YPetri::Place and offers simlar interace.
3
+ #
4
+ class YNelson::Place < YPetri::Place
5
+ include YNelson::Yzz
6
+ alias call along # .( :dim ) instead of .along( :dim )
7
+
8
+ class << self
9
+ end
10
+
11
+ # Subclass of YTed::Zz::Side.
12
+ #
13
+ class Side < Side
14
+ # "Budding": creation of new cells from the cell sides
15
+ def bud( value: L!, f: nil )
16
+ # FIXME
17
+ end
18
+ alias :>> :bud
19
+ end
20
+
21
+ private
22
+
23
+ # Place, Transition, Net class
24
+ #
25
+ def Place; ::YNelson::Place end
26
+ def Transition; ::YNelson::Transition end
27
+ def Net; ::YNelson::Net end
28
+ end
@@ -0,0 +1,38 @@
1
+ # YNelson::Transition is based on YPetri::Transition and offers similar
2
+ # interface. "Functions", on which transitions of a functional Petri net
3
+ # are based, are analogical to 'formulas' of a spreadsheet.
4
+ #
5
+ class YNelson::Transition < YPetri::Transition
6
+ include YNelson::Yzz
7
+ alias call along # .( :dim ) rather than .along( :dim )
8
+
9
+ private
10
+
11
+ # YNelson extends this YPetri::Transition private method, so that a zz
12
+ # connection is automatically created along dimension [:domain, i] for
13
+ # i-th domain place of the transition.
14
+ #
15
+ def inform_upstream_places
16
+ upstream_places.each_with_index { |p, i|
17
+ along( YNelson.Dimension self, :domain, i ) >> p
18
+ }
19
+ super
20
+ end
21
+
22
+ # YNelson extends this YPetri::Transition private method, so that a zz
23
+ # connection is autimatically created along along dimension [:codomain, i]
24
+ # for i-th codomain place of the transition.
25
+ #
26
+ def inform_downstream_places
27
+ downstream_places.each_with_index { |p, i|
28
+ along( YNelson.Dimension self, :codomain, i ) >> p
29
+ }
30
+ super
31
+ end
32
+
33
+ # Place, Transition, Net class.
34
+ #
35
+ def Place; ::YNelson::Place end
36
+ def Transition; ::YNelson::Transition end
37
+ def Net; ::YNelson::Net end
38
+ end
@@ -0,0 +1,4 @@
1
+ module YNelson
2
+ DEBUG = false
3
+ VERSION = "0.1.5"
4
+ end
@@ -0,0 +1,11 @@
1
+ # Represents Petri nets inside the Nelson net.
2
+ #
3
+ module YNelson::Yzz
4
+ include Yzz
5
+
6
+ def along *args
7
+ return super( args[0] ) if
8
+ args.size == 1 && args[0].is_a?( ::YNelson::Dimension )
9
+ super( ::YNelson.Dimension *args )
10
+ end
11
+ end # module YzzPrepend
Binary file
@@ -0,0 +1,136 @@
1
+ #encoding: utf-8
2
+
3
+ # A pointer to a Zz object. A glorified variable, basically.
4
+ #
5
+ class YNelson::ZzPoint
6
+ attr_accessor :zz
7
+
8
+ # Initialization has one optional argument :zz -- zz object at which the
9
+ # point should be initialized.
10
+ #
11
+ def initialize( zz: nil )
12
+ @zz = zz
13
+ end
14
+
15
+ delegate :marking, :value, :υ,
16
+ :marking=, :value=, :υ=,
17
+ :test_arcs, :codomain, :downstream_transitions,
18
+ :action_arcs, :domain, :upstream_transitions, :ϝ, # digamma: ϝ
19
+ :arcs, # :connectivity alias not delegated to avoid confusion
20
+ :upstream_places, # :precedents, :← not delegated, same reason
21
+ :downstream_places, # :dependents, :→ aliases not delegated
22
+ to: :zz
23
+ alias :v :value
24
+
25
+ def default_dimension; YNelson.primary_dimension end
26
+
27
+ # Quasi-delegation to zz
28
+
29
+ def along dimension=default_dimension
30
+ zz.along dimension
31
+ end
32
+
33
+ def posward( along: default_dimension )
34
+ along( along ).posward
35
+ end
36
+ alias p posward
37
+
38
+ def negward( along: default_dimension )
39
+ along( along ).negward_side
40
+ end
41
+ alias n negward
42
+
43
+ def posward_neighbor( along: default_dimension )
44
+ posward( along: along ).neighbor
45
+ end
46
+ alias P posward_neighbor
47
+
48
+ def negward_neighbor( along: default_dimension )
49
+ negward( along: along ).neighbor
50
+ end
51
+ alias N negward_neighbor
52
+
53
+ def redefine_posward_neighbor( neighbor, along: default_dimension )
54
+ posward( along: along ) << neighbor
55
+ end
56
+ alias P! :redefine_posward_neighbor
57
+
58
+ def redefine_negward_neighbor( neighbor, along: default_dimension )
59
+ negward( along: along ) << neighbor
60
+ end
61
+ alias N! :redefine_negward_neighbor
62
+
63
+ def bud_posward( value=nil, along: default_dimension )
64
+ posward( along: along ).bud value
65
+ end
66
+ alias bud bud_posward
67
+
68
+ def bud_negward( value=nil, along: default_dimension )
69
+ negward( along: along ).bud value
70
+ end
71
+
72
+ def rank( along: default_dimension )
73
+ zz.get_rank along: along
74
+ end
75
+
76
+ # Walkers
77
+
78
+ def step_posward( along: default_dimension )
79
+ neighbor = posward_neighbor along: along
80
+ if neighbor.is_a_zz? then @zz = neighbor else false end
81
+ end
82
+ alias step step_posward
83
+ alias p! step_posward
84
+
85
+ def step_negward( along: default_dimension )
86
+ neighbor = negward_neighbor along: along
87
+ if neighbor.is_a_zz? then @zz = neighbor else false end
88
+ end
89
+ alias n! step_negward
90
+
91
+ # Rewinders
92
+
93
+ def rewind_posward( along: default_dimension )
94
+ origin = zz
95
+ if block_given? then
96
+ loop { yield zz
97
+ return :end unless posward_neighbor( along: along ).is_a_zz?
98
+ return :loop if posward_neighbor( along: along ) == origin
99
+ step_posward along: along }
100
+ else # no block given, returns enumerator
101
+ Enumerator.new { |y|
102
+ loop { y << zz
103
+ break :end unless posward_neighbor( along: along ).is_a_zz?
104
+ break :loop if posward_neighbor( along: along ) == origin
105
+ step_posward along: along }
106
+ }
107
+ end
108
+ end
109
+
110
+ def rewind_negward( along: default_dimension )
111
+ origin = zz
112
+ if block_given? then
113
+ loop { yield zz
114
+ return :end unless negward_neighbor( along: along ).is_a_zz?
115
+ return :loop if negward_neighbor( along: along ) == origin
116
+ step_negward along: along }
117
+ else
118
+ Enumerator.new { |y|
119
+ loop { y << zz
120
+ break :end unless negward_neighbor( along: along ).is_a_zz?
121
+ break :loop if negward_neighbor( along: along ) == origin
122
+ step_negward along: along }
123
+ }
124
+ end
125
+ end
126
+
127
+ # Simple unconditional rewind.
128
+
129
+ def rewind_posward!( along: default_dimension )
130
+ rewind_posward( along: along ) {} # implemented using empty block
131
+ end
132
+
133
+ def rewind_negward!( along: default_dimension )
134
+ rewind_negward( along: along ) {}
135
+ end
136
+ end # class YNelson::ZzPoint
data/lib/y_nelson.rb ADDED
@@ -0,0 +1,146 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'yzz'
3
+ require 'y_petri'
4
+ require 'y_support/kde'
5
+
6
+ require 'graphviz'
7
+
8
+ require_relative 'y_nelson/version'
9
+ require_relative 'y_nelson/yzz'
10
+ require_relative 'y_nelson/dimension'
11
+ require_relative 'y_nelson/place'
12
+ require_relative 'y_nelson/transition'
13
+ require_relative 'y_nelson/net'
14
+ require_relative 'y_nelson/zz_point'
15
+ require_relative 'y_nelson/dimension_point'
16
+ require_relative 'y_nelson/manipulator'
17
+
18
+ # YNelson is an implementation of a cross between Ted Nelson's Zz structure, and
19
+ # a functional Petri net (FPN). The resulting data structure, which combines
20
+ # qualities of FPNs with those of relational databases, I refer to as Nelson net
21
+ # throughout this text.
22
+ #
23
+ # One way to understand Nelson nets is as a genralization of a spreadsheet. In
24
+ # his explanations of Zz structures, Ted Nelson makes wide use of spreadsheet
25
+ # metaphors: cells, ranks, rows, columns, cursors, selections... Nelson net
26
+ # implemented here adds "formulas" to the mix, represented by FPN transitions.
27
+ #
28
+ # Nelson net disposes of the arbitrary constraints on FPNs as well as the
29
+ # orthogonal structure of "cells" seen in most practical spreadsheet
30
+ # implementations:
31
+ #
32
+ # 1. Both places and transitions of the FPN take part in zz structure.
33
+ # 2. Formula-based transitions are upgraded to standalone FPN transitions.
34
+ #
35
+ # The implications of the zz structure differences from ordinary hyperorthogonal
36
+ # structures hav been, to a degree, explained by Ted Nelson himself. There is a
37
+ # growing body of literature on zz structure applications, including in
38
+ # bioinformatics.
39
+ #
40
+ # As for functional Petri nets, their power in computing is well recognized (eg.
41
+ # Funnel, Odersky 2000). FPNs are sometimes just called functional nets, because
42
+ # Petri originally described his nets as timeless and functionless. However, in
43
+ # special-purpose applications, such as biochemical applications, to which I
44
+ # incline, it is appropriate to honor Petri, who designed his nets specifically
45
+ # with chemical modeling in mind as one of their main applications. In
46
+ # biochemistry, it is common to call functional nets Petri nets (Miyano, 200?).
47
+ #
48
+ module YNelson
49
+ # Singleton class of YNelson is partial descendant of YPetri::Workspace. More
50
+ # specifically, it mixes in most YPetri::Workspace instance methods and
51
+ # provides interface, which should be a superset of YPetri::Workspace. The
52
+ # difference is, that while YPetri::Workspace can have multiple instances,
53
+ # representing workdesks, YNelson is a singleton representing relational
54
+ # database.
55
+ #
56
+ class << self
57
+ # YNelson metaclass includes instance methods of YPetri::Workspace.
58
+ include YPetri::Workspace::PetriNetRelatedMethods
59
+ include YPetri::Workspace::SimulationRelatedMethods
60
+
61
+ # Allows summoning DSL by 'include YNelson' (like YPetri does).
62
+ #
63
+ def included receiver
64
+ # receiver.instance_variable_set :@NelsonManipulator, Manipulator.new
65
+ # puts "included in #{receiver}"
66
+ receiver.module_exec {
67
+ define_method :nelson_manipulator do
68
+ singleton_class.instance_variable_get :@NelsonManipulator or
69
+ ( puts "defining Manipulator for #{self} singleton class" if YNelson::DEBUG
70
+ singleton_class.instance_variable_set :@NelsonManipulator, Manipulator.new )
71
+ end
72
+ }
73
+ end
74
+
75
+ def dimensions; @dimensions end
76
+ end # class << self
77
+
78
+ # Instance variables @Place, @Transition, @Net are expected by
79
+ # YPetri::Workspace module.
80
+ @Place, @Transition, @Net = self::Place, self::Transition, self::Net
81
+
82
+ # Atypical call to #initialize in the course of module execution.
83
+ initialize
84
+
85
+ delegate( :workspace, to: :nelson_manipulator )
86
+
87
+ # Petri net aspect.
88
+ delegate( :Place, :Transition, :Net,
89
+ :place, :transition, :pl, :tr,
90
+ :places, :transitions, :nets,
91
+ :pp, :tt, :nn,
92
+ :net_point,
93
+ :net_selection,
94
+ :net, :ne,
95
+ :net_point_reset,
96
+ :net_point_set,
97
+ to: :nelson_manipulator )
98
+
99
+ # Simulation aspect.
100
+ delegate( :simulation_point, :ssc_point, :cc_point, :imc_point,
101
+ :simulation_selection, :ssc_selection,
102
+ :cc_selection, :imc_selection,
103
+ :simulations,
104
+ :clamp_collections,
105
+ :initial_marking_collections,
106
+ :simulation_settings_collections,
107
+ :clamp_collection_names, :cc_names,
108
+ :initial_marking_collection_names, :imc_names,
109
+ :simulation_settings_collection_names, :ssc_names,
110
+ :set_clamp_collection, :set_cc,
111
+ :set_initial_marking_collection, :set_imc,
112
+ :set_simulation_settings_collection, :set_ssc,
113
+ :new_timed_simulation,
114
+ :clamp_cc, :initial_marking_cc, :simulation_settings_cc,
115
+ :simulation_point_position,
116
+ :simulation,
117
+ :clamp_collection, :cc,
118
+ :initial_marking_collection, :imc,
119
+ :simulation_settings_collection, :ssc,
120
+ :clamp,
121
+ :initial_marking,
122
+ :set_step, :set_step_size,
123
+ :set_time, :set_target_time,
124
+ :set_sampling,
125
+ :set_simulation_method,
126
+ :new_timed_simulation,
127
+ :run!,
128
+ :print_recording,
129
+ :plot,
130
+ :plot_selected,
131
+ :plot_state,
132
+ :plot_flux,
133
+ to: :nelson_manipulator )
134
+
135
+ # Zz aspect.
136
+ delegate( :Dimension,
137
+ :ϝ,
138
+ :default_dimension,
139
+ :primary_point, :p1,
140
+ :secondary_point, :p2,
141
+ :primary_dimension_point, :d1,
142
+ :secondary_dimension_point, :d2,
143
+ :visualize,
144
+ :graphviz,
145
+ to: :nelson_manipulator )
146
+ end
@@ -0,0 +1,121 @@
1
+ #! /usr/bin/ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'minitest/spec'
5
+ require 'minitest/autorun'
6
+ # tested component itself
7
+ require './../lib/y_nelson'
8
+
9
+ # **************************************************************************
10
+ # Nelson net test
11
+ # **************************************************************************
12
+ #
13
+ describe YNelson do
14
+ before do
15
+ skip
16
+ @m = YNelson::Manipulator.new
17
+ @p = @m.Place default_marking: 3.2,
18
+ marking: 1.1,
19
+ quantum: 0.1
20
+ end
21
+
22
+ describe YNelson::Dimension do
23
+ it "should give same instance for same object" do
24
+ assert_equal YNelson.Dimension( :xxx ), @m.Dimension( :xxx )
25
+ end
26
+ end
27
+
28
+ describe "new transition form correct zz connections with places" do
29
+ it "should work as expected" do
30
+ assert_equal [], @p.neighbors
31
+ assert_equal [], @p.connectivity # 'connectivity' now exclusively a zz keyword
32
+ t = @m.Transition codomain: @p, action: lambda { 0.1 }, assignment: true
33
+ assert_equal [ @p ], t.neighbors
34
+ dim = @m.Dimension( :codomain, 0 )
35
+ assert_equal @p, t.along( dim ).posward.neighbor
36
+ # And then, it would be the job of dimension reduction to determine if
37
+ # some dimensions should be visualized or otherwise used together.
38
+ end
39
+ end
40
+
41
+ it "should work" do
42
+ # TODO:
43
+ # has point
44
+ # has dimension point
45
+ # can create places
46
+ @m.Place
47
+ # can remove places
48
+ end
49
+
50
+ describe "small Nelson net" do
51
+ before do
52
+ # TODO:
53
+ # Create a net of several places and transition
54
+ end
55
+
56
+ it "should work" do
57
+ # TODO:
58
+ # exercise the created Nelson net to make sure it works
59
+ # #set_posward_neighbor
60
+ # #set_negward_neighbor
61
+ # #along, #posward, #negward, etc...
62
+ end
63
+ end
64
+ end
65
+
66
+ describe YNelson::ZzPoint do
67
+ it "should work" do
68
+ # TODO
69
+ end
70
+ end
71
+
72
+ describe YNelson::DimensionPoint do
73
+ it "should work" do
74
+ # TODO
75
+ end
76
+ end
77
+
78
+ describe "visualization" do
79
+ before do
80
+ @m = YNelson::Manipulator.new
81
+ @m.Place name: :A, m!: 3.2
82
+ @m.Place name: :B, m!: 5
83
+ @m.Transition name: :T1, s: { A: -1, B: 1 }, rate: 1
84
+ @m.Place name: :C, m!: 7.0
85
+ @m.Transition name: :T2, s: { B: -1, C: 1 }, rate: 1
86
+ end
87
+
88
+ it "should work" do
89
+ dim1 = YNelson::Dimension( :domain, 0 )
90
+ dim2 = YNelson::Dimension( :codomain, 1 )
91
+ @m.visualize dim1, dim2
92
+ end
93
+ end
94
+
95
+ # describe "zz structure with a transition or two" do
96
+ # before do
97
+ # new_zz_sheet "koko"
98
+ # @c1, @c2, @c3 = ZzCell( 1 ), ZzCell( 2 ), ZzCell( 3 )
99
+ # new_zz_row @c1, @c2, @c3
100
+ # @c4 = ϝ { |a0, b0, c0| a0 + b0 + c0 }
101
+ # new_zz_row @c4
102
+ # end
103
+
104
+ # it "should have #make_transitions" do
105
+ # tt = make_transitions
106
+ # assert_equal 1, tt.size
107
+ # t = tt[0]
108
+ # assert_kind_of ::YPetri::Transition, t
109
+ # assert t.domain.include? @c1
110
+ # assert t.domain.include? @c2
111
+ # assert t.domain.include? @c3
112
+ # assert_equal nil, @c4.marking
113
+ # t.fire!
114
+ # assert_equal 6, @c4.marking
115
+ # new_zz_sheet "pipi"
116
+ # @c5 = ϝ { |koko_a0, koko_b0| koko_a0 + koko_b0 }
117
+ # tt = make_transitions
118
+ # tt.each &:fire!
119
+ # assert_equal 3, @c5.value
120
+ # end
121
+ # end
data/test/zz.png ADDED
Binary file
data/y_nelson.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'y_nelson/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "y_nelson"
8
+ spec.version = YNelson::VERSION
9
+ spec.authors = ["boris"]
10
+ spec.email = ["\"boris@iis.sinica.edu.tw\""]
11
+ spec.description = %q{Formalization and generalization of a spreadsheet.}
12
+ spec.summary = %q{A fusion of functional Petri net with a zz structure.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'yzz'
22
+ spec.add_dependency 'y_petri'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: y_nelson
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - boris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yzz
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: y_petri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Formalization and generalization of a spreadsheet.
70
+ email:
71
+ - '"boris@iis.sinica.edu.tw"'
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - lib/y_nelson.rb
82
+ - lib/y_nelson/dimension.rb
83
+ - lib/y_nelson/dimension_point.rb
84
+ - lib/y_nelson/manipulator.rb
85
+ - lib/y_nelson/net.rb
86
+ - lib/y_nelson/place.rb
87
+ - lib/y_nelson/transition.rb
88
+ - lib/y_nelson/version.rb
89
+ - lib/y_nelson/yzz.rb
90
+ - lib/y_nelson/zz.png
91
+ - lib/y_nelson/zz_point.rb
92
+ - test/y_nelson_test.rb
93
+ - test/zz.png
94
+ - y_nelson.gemspec
95
+ homepage: ''
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.0.3
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: A fusion of functional Petri net with a zz structure.
119
+ test_files:
120
+ - test/y_nelson_test.rb
121
+ - test/zz.png