YAML and NArray

D

Daniel Martin

In the past week, I've been exploring a little problem that by
Wednesday I was ready to sit down and code. Now, the details of the
problem aren't important, but for this problem I was going to need to
have objects that I could read from a file, manipulate a few hundred
times, and then write back to a file.

Now, object serialization is not really what I'd consider "fun" stuff,
so I figured "I'll just throw YAML at it". Unfortunately, my objects
contained several NArray (and NMatrix and NVector) objects, and YAML
initially serialized them as:

irb(main):002:0> NArray.float(3,3).to_yaml
=> "--- !ruby/object:NArray {}\n\n"

Not helpful. Searching the web pulled up a ruby-talk message from a
few years ago, but apparently the YAML api for defining your own YAML
serialization has changed since then. Although this new API appears
to be undocumented (at least, I couldn't find any documentation), I
did find a few blog posts in which people showed examples with other
classes.

So anyway, I finally integrated YAML and NArray, and present the
solution here for other people googling in the future on how to get
these two to work together, as well as now for comment and criticism
by current list subscribers. Note that it handles NArray, NMatrix,
and NVector objects:

########## narray-yaml.rb #########
require 'yaml'
require 'narray'

# First, a yaml utility routine to make the output prettier

module YAML
class YIArray < Array
yaml_as "tag:yaml.org,2002:seq"
def to_yaml_style; :inline; end
end

def YAML.inline_array(arr)
if Array === arr[0] then
arr.map {|s| inline_array(s)}
else
YIArray.new.concat(arr)
end
end
end

class NArray
# I used a tag of my own since I wasn't sure if
# someone else had their own serialization of
# NArray objects
yaml_as "tag:[email protected],2007:narray"
def to_yaml( opts = {} )
YAML::quick_emit( self.object_id, opts ) do |out|
out.map(taguri) do |map|
map.add('typecode', typecode)
map.add('shape', YAML::inline_array(shape))
map.add('data', YAML::inline_array(to_a))
end
end
end

def self.yaml_new(klass, tag, val)
result = klass.new(val['typecode'], *(val['shape']))
result[] = val['data']
result
end
end
__END__

The result looks like this, for a 2 by 2 by 2 NArray:

--- [email protected],2007/narray
typecode: 5
shape: [2, 2, 2]
data: !seq:Array
- !seq:Array
- [0.441292242643088, 0.463176002629107]
- [0.602508503899103, 0.155671031769272]
- !seq:Array
- [0.558707757356912, 0.536823997370893]
- [0.397491496100897, 0.844328968230728]

So I'm pretty happy with the output format, but not happy with how
long it took to get there, both in terms of the amount of code and in
terms of the amount of time spent tracking stuff down, and the amount
of time spent looking at documentation for the wrong API trying to
figure out why my code wasn't working.

Any suggestions on how to clean up my code, and any pointers to
documentation I missed?
 
D

Daniel Martin

Daniel Martin said:
So anyway, I finally integrated YAML and NArray, and present the
solution here for other people googling in the future on how to get
these two to work together, as well as now for comment and criticism
by current list subscribers. Note that it handles NArray, NMatrix,
and NVector objects:

And this is what I get for posting something other than the exact code
I tested with. Apparently there's a bug in Syck such that email-based
tags are treated differently from dns-based tags. Unfortunately, I
don't own a domain name - fortunately, I know the guy who does own
snowplow.org, and I'm pretty sure he'd be okay with me using the tag
prefix shown below.

So here's a fixed version. Note that it is the same as before, except
that the private tag used in the yaml_as line is different.

########## narray-yaml.rb #########
require 'yaml'
require 'narray'

# First, a yaml utility routine to make the output prettier

module YAML
class YIArray < Array
yaml_as "tag:yaml.org,2002:seq"
def to_yaml_style; :inline; end
end

def YAML.inline_array(arr)
if Array === arr[0] then
arr.map {|s| inline_array(s)}
else
YIArray.new.concat(arr)
end
end
end

class NArray
# I used a tag of my own since I wasn't sure if
# someone else had their own serialization of
# NArray objects
yaml_as "tag:snowplow.org,2007:martin/narray"
def to_yaml( opts = {} )
YAML::quick_emit( self.object_id, opts ) do |out|
out.map(taguri) do |map|
map.add('typecode', typecode)
map.add('shape', YAML::inline_array(shape))
map.add('data', YAML::inline_array(to_a))
end
end
end

def self.yaml_new(klass, tag, val)
result = klass.new(val['typecode'], *(val['shape']))
result[] = val['data']
result
end
end
__END__

Hopefully this message will be found by people googling for how to
integrate YAML and NArray.

I'm going to make this file available at
http://snowplow.org/martin/narray/

along with standard verbiage up at the top placing it under some
variant of the MIT license or the no-attribution BSD license.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top