[Pharo-users] Dynamic graph exploration - seeking input on idiomatic smalltalk [LONG]

Patrik Sundberg patrik.sundberg at gmail.com
Fri Jul 6 06:38:48 EDT 2012

```Hi,

First of all, sorry for the long email as my first email to the list.
Hopefully some people will find it an interesting discussion :)

I'm a long time programmer that has been studying smalltalk and pharo over
the last year. It's a beautiful language I'm liking the image style of
development a whole lot. I've been looking for a good test case to try out
in pharo and I've got something in mind. I've used ruby since around 2000
and given how much it has been inspired by smalltalk it's not a big leap.

My real job is being a commodities trader but I build my own tools and
something I'm always working on is improved risk and pricing tools. Lots of
that comes down to 2 things:
1. evaluating a "function" (in a general sense) with inputs that are picked
depending on time. e.g. I want to price a security and I want to pick up
prices for time X as inputs to the pricing model.
2. calculating a derivative of the "function" above with respect to inputs

What I tend to do in order to keep things consistent by design, plus add
natural caching, is create a calculation graph. I define all the
dependencies and create an in-memory graph where each node is unique using
an identity map. I then perform a calculation where the calculations trickle
down the graph starting from the node I'm interested in down all it's
dependencies. To calculate the derivative I then find the node representing
the input I want the derivative with respect to and use finite differences,
e.g. move it's value, and recalculate the top level node. On the second
valuation of the graph only the parts that are affected by me changing that
1 value will need to be evaluated, the rest is cached an unaffected. It
makes it very easy to ask questions like "How much will I be affected by X
changing by Y?" since I can take the top level node of the graph, search for
X, and if found change it by Y and recalculate.

How the graph is constructed in memory depends on time (and a few other
things). I always store all previous states of the world so that I can
recreate any calculation I did in the past. Very useful for diagnosing
problem. Hence if I for example change what model I use to model something,
that change is recorded in a way such that if I set my "time" to before the
change happened the graph will get created as it would have with the old
model, and for a time after the change it'll create a different graph
reflecting the new model. Hence the graph can only be known at runtime when
the "time" etc is known.

I currently have a ruby mockup of this. It's a DSL that looks like this:

----------- EXAMPLE

class ExampleObject
include GraphEntity # includes a module with functionality for objects
participating in the graph, including #property and #calc used below

property :foo do
123 # this is the default value for this property which will be used
before a value has been set and saved
end

calc :bar do |arg|
foo.value + arg     # take the value of the arg property and add the
argument given to the calculation node
end
end

o = ExampleObject.new
# this will kick of the graph being built in memory and setup the dependency
between bar and foo nodes
o.bar(1).value  # -> 124
# this will be a "cache lookup" since nothing in the graph that bar depends
on has changed (i.e. the "expensive" calculation is not performed again
o.bar(1).value  # -> 124

o.foo.set_value(2)
o.bar(1).value  # -> 125, realizes that foo changed and performs a recalc
--------------------------------------------------------

To accomplish this I use dynamic code generation like the below for
#property and similar for other types of nodes:

# NOTE: it's a class level method, hence how I can call it when
defining the class in the example

def property(name, time = CdrEnv.instance.time, &block)
clear_property(name)
getter_method_body = <<-EOF
def #{name}
init_block = self.class.property_init_block_for(:#{name})
time_for_property =
self.class.property_time_dependency_for(:#{name})
if init_block.nil?
CdrEnv.instance.get_property_node(self, :#{name},
time_for_property)
else
CdrEnv.instance.get_property_node(self, :#{name},
time_for_property, &init_block)
end
end
EOF
setter_method_body = <<-EOF
def #{name.to_s}=(value)
#{name.to_s}.mutate(value)
end
EOF
class_eval getter_method_body
class_eval setter_method_body
register_property_node(name, time, &block)
end

Don't worry about the details or all the unfamiliar ruby, the main point is
that it creates an instance method that uses the singleton CdrEnv.instance
to either get or create the node representing the property from the graph
identity cache depending on if it exists or not.

>From a tooling point of view I think I'd love to work with this kind of
thing in pharo. Building my own browsers for inspecting and debugging my
dynamic graph should be very good fit. However, I'd appreciate some pointers
to idiomatic smalltalk to attack this kind of problem in terms of
implementing the graph itself - I obviously want the user (even if it's me)
to just have to focus on the domain model and hide as much as possible of
the graph bits under the covers the same way I've done with the code
generation stuff in my ruby example.

Any input into this would be much appreciated,
Patrik

P.S.
Btw, the persistence backend for this is the neo4j graph database, but it's
fronted by a service slotting into my own service framework built using
ZeroMQ and services exchanging messages in protobuf format. One can use it
from any language as long as one can send protobuf messages over zeromq. I
see there's a zeromq ffi library available on SS that I'll check out, but
I'm not finding a protobuf implementation. It'd be easy enough for me to
port a ruby protobuf implementation but I may as well ask if someone has
already done any work on protobuf for smalltalk?

--
View this message in context: http://forum.world.st/Dynamic-graph-exploration-seeking-input-on-idiomatic-smalltalk-LONG-tp4638702.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.

```