Skip to content

Ruby Binding

Kenneth Yrke Jørgensen edited this page Jun 14, 2021 · 8 revisions

Ruby Modules

The DBM library has now a binding to the popular Ruby language (see www.rubycentral.com or www.ruby-doc.org to start with Ruby). The binding offers several modules as different layers on top of the DBM library, depending on what the user wants to do. The different modules are:

  • udbm:
    This is the core binding that provides the classes Constraint to define constraints <=c or <c, Matrix to enter specific DBM matrices, Relation to type results of relations between federations (inclusion checking), and Fed that wraps the C++ fed_t type in a Ruby friendly manner. Try (UDBM::Fed.public_instance_methods-Object.public_instance_methods).sort to get a taste of what is supported. Documentation will come later, this is a pre-release. For now, you can check fed.h to see what these methods are doing and check udbm.cpp to see how they are wrapped (pretty straight-forward).
  • udbm-callback:
    This is a light wrapper that uses Ruby magic to callback a user defined function whenever a modifying method (of the form name!) is called. It's a change listener facility.
  • udbm-gtk:
    This is a graphical viewer binding to gtk. You'll obviously need ruby-gtk to have this work. Main commands are UDBM::Fed.show(name), UDBM::Fed.hide, and UDBM::hide(name) to show and hide federations under a named tab in the viewer. If the federation instance changes, its view is updated on-the-fly. The viewer is a particular listener attached to a federation instance. If you want it to work properly, be careful with your references, e.g, a.show('me') followed by a = something new will stop further updates like a.up!. This module is using udbm-mdi, a nifty graphical component found on Ruby site. We only renamed it and modified it slightly. You don't have to worry about this module at all.
  • udbm-sys:
    This offers a higher level view of federations as systems of constraints. This needs documentation, I know, but it is written in Ruby and it is therefor easy to read ;). It offers the possibility to manipulate sets (of clock valuations) as constraints between clocks that you define within contexts. Say you have a = Context.create('a',:x,:y,:z), this gives you access to the clocks x, y, and z. Now you can use sets defined like (a.x < a.y) & (a.y > 3) or (a.x > 4) | (a.y > 5), compute intersections, relations, unions, whatever you can do on federations, but with sets instead. It is another view of federations.

Release

Documentation is still work-in-progress. The draft manual is now available in the distribution. Some examples are also provided, e.g., a simple reachability algorithm for Fisher's mutual exclusion protocol.

Download (linux binaries + source): ruby-udbm-0.11.tgz
Download (Windows binaries): ruby-udbm-0.11-win.zip
Note: Please do not try to compile for Windows, you will certainly suffer.
Known issue: Ruby multi-threading under Windows is terrible and the Gtk window is definitely not responsive. Try to move your console away from it and avoid causing expose/redraw events on the window.

Installing Under Windows

Please follow the steps given on this page. In short you need to download and install:

  1. Ruby for Windows.
  2. Ruby/Gtk2 for Windows.
  3. Glade runtime for Windows.
  4. This Ruby-DBM binding for Windows. Installation is manual (copy files), or automatic depending if you have a unix shell emulation or not under Windows. Please INSTALL.TXT. Please choose default paths for the installations.

Getting Started

Now that you've installed painlessly Ruby and this binding (plus Gtk and Glade for Windows), you want to try it quickly. Let's get started. Fire irb, the Ruby interpreter.

prompt>_irb_  
irb(main):001:0>

Let's try the most user friendly access, via sets. Of course we want the Gtk module loaded in too, and we include the module in the top-level, which is like using the namespace.

irb(main):001:0> _require 'udbm-sys'_  
=> true  
irb(main):002:0> _require 'udbm-gtk'_  
=> true  
irb(main):003:0> _include UDBM_  
=> Object  
irb(main):004:0>`

Declare a context within which our clocks will exist, say context named 'C' with clocks x, y, and z. Notice that 'c' is the ruby variable holding a reference to our named context. Let's check our clocks.

irb(main):004:0> _c=Context.create('C',:x,:y,:z)_  
=> #<UDBM::Context_C {C.x,C.y,C.z}>  
irb(main):005:0> _c.x_  
=> #<UDBM::Context::Clock C.x>  
irb(main):006:0> _c.y_  
=> #<UDBM::Context::Clock C.y>  
irb(main):007:0> _c.z_  
=> #<UDBM::Context::Clock C.z>  
irb(main):008:0>  

It would have been clearer to use the same variable names. We can fix this easily. Let's declare two sets with constraints on our clocks.

irb(main):008:0> _C=c_  
=> #<UDBM::Context_C {C.x,C.y,C.z}>  
irb(main):009:0> _a=(C.x>C.y)&(C.z<4)&(C.y<3)_  
=> #<UDBM::Context_C::Set_C (((C.x>C.y)&(C.z<4))&(C.y<3))>  
irb(main):010:0> _b=a&((C.x<2)|(C.x>=3))_  
=> #<UDBM::Context_C::Set_C ((((C.x>C.y)&(C.z<4))&(C.y<3))&((C.x<2)|(C.x>=3)))>  
irb(main):011:0>  

You want to see these sets, don't you?

irb(main):011:0> _a.show('a')_  
=> #<UDBM::Context_C::Set_C (C.y<3 & C.y-C.x<0 & C.z<4)>  
irb(main):012:0> _b.show('b')_  
=> #<UDBM::Context_C::Set_C (3<=C.x & C.y<3 & C.z<4)|(C.x<2 & C.y-C.x<0 & C.z<4)>  
irb(main):013:0>`</td>

And you obtain magically these under different views:

Hmm, nice with color blending, isn't it? But wait, our sets changed or what? Let's have a look at them again:

irb(main):013:0> _a_  
=> #<UDBM::Context_C::Set_C (C.y<3 & C.y-C.x<0 & C.z<4)>  
irb(main):014:0> _b_  
=> #<UDBM::Context_C::Set_C (3<=C.x & C.y<3 & C.z<4)|(C.x<2 & C.y-C.x<0 & C.z<4)>  
irb(main):015:0>`</td>

They look slightly different but they correspond to what we asked for. Actually, the library does lazy evaluation whenever possible. The first declaration gave dummy formulas and asking to show the sets evaluates them. Notice the slight bold borders that correspond to non strict constraints. Well, let's play with 'b' now.

irb(main):015:0> _b.up!_  
= > #<UDBM::Context_C::Set_C (3<=C.x & C.y-C.x<0 & C.y-C.z<3 & C.z-C.x<1 & C.z-C.y<4)|(C.x-C.y<2 & C.x-C.z<2 & C.y-C.x<0 & C.z-C.y<4)>  
irb(main):016:0>

The graphical representation gets automagically updated to these, by the way :). The colors are blended, which is more useful to distinguish sets that partially overlap with each other.

All right, let's change the view, do a projection (reset to 1), and up again.

irb(main):016:0> _b.x=1_  
=> 1  
irb(main):017:0> _b.up!_  
=> #<UDBM::Context_C::Set_C (1<=C.x & C.x-C.y<=1 & C.x-C.z<=1 & C.y-C.z<3 & C.z-C.y<4)|(1<=C.x & C.x-C.y<=1 & C.x-C.z<=1 & C.y-C.z<2 & C.z-C.y<4)>  
irb(main):018:0>`</td>

Aha! We could simplify this to one set (notice the overlapping color orange instead of pink). Let's reduce this.

irb(main):018:0> _b.reduce!_  
=> #<UDBM::Context_C::Set_C (1<=C.x & C.x-C.y<=1 & C.x-C.z<=1 & C.y-C.z<3 & C.z-C.y<4)>  
irb(main):019:0>`</td>

Clone this wiki locally