Mai 2006 - Posts

Iridium Release: MAY 2006 [v2006.5.2a]
25 Mai 06 10:07 | Christoph Rüegg | 1 comment(s)
I finally published a new Iridium release a few days ago: Iridium Release MAY 2006 [v2006.5.2a].

Last release was tagged as version v0.3. I've changed the way I assign version numbers. From now on, all Math.NET package version numbers consist of four parts:

YYYY.M.Vx
  • YYYY: The release year
  • M: The release month
  • V: an increasing number, indexing releases. Developer releases are always odd (that is, whenever I work on the code, I compile to odd numbers. "nightly builds" will have odd numbers), and published releases are even.
Why? First, you see immediately how old a release actually is. Second, I don't have to think about version numbers anymore (shall this be a major release? or just a minor?). Third, I don't really want to continue producing only zero-version releases all the times. ;) There are also some other pros, but of course also some disadvantages: mainly that you don't see the importance of a release any more (a release changing the major version number is probably more "important" than one changing only the build number). But this might not really be a problem if I release more often...
Filed under: , ,
Yttrium Insights, part 4: Core Components
18 Mai 06 01:51 | Christoph Rüegg | 5 comment(s)
To ensure we understand the same thing when talking about signals, ports and architectures in the yttrium context, I try to give a short high-level introduction in this article.

Mathematical Expressions in Yttrium

In a classical computer algebra system (CAS), expressions are organized in trees. For example, the infix expression "A*(B+2)" is represented as a tree with "*" as root element and children "A" and "B+2", where the second child is represented as a subtree with "+" as root and "B" and "2" as children. In a simple case, all the leafs of the tree are symbols (variables and numbers) and the other non-leaf nodes define arithmetic operations on their children. Evaluating such a tree is simple: For every operation you first evaluate its children and then execute it on the actual child values, in a recursive way.

Yttrium replaces those trees with graphs. There's no root node anymore, all nodes are equal. Nodes are stateful, so they always have and know their value, you don't have to walk through the whole tree to evaluate its current value. Instead, if a value is changed, it automatically propagates through the graph. Therefore yttrium uses a push model for evaluation, instead of a pull model like classic CAS. In yttrium, these nodes are called Signals; the graph is called a System. Instead of expression manipulation, yttrium is all about system manipulation and simulation. Of course, an algebraic tree-like expression may be represented as a system, too.

From Signals to a System

A signal may have a value and various properties and constraints, but does not have any information about operations and relations to other signals. Instead, signals are connected by Ports. A port maintains a set of input and output signals, and a set of buses.

While signals may drive lots of ports (may be connected to more than one port input), a signal may be driven by at most one port only (connected to at most one port output). Buses on the other hand are bidirectional and may be attached to as many ports as needed.

What kind of operation or relation a port stands for is defined by its Entity, a contract specifying the port interface (number of input and output signals, and attached buses) and its symbol and type (e.g. '+' & Std.Add, or 'sin' & Std.Sine).



Evaluation and Architectures

However, neither port nor entity actually implement those operations for simulation. That's where Architectures come in. Architectures are type-specific evaluation implementations of operations and responsible for propagating values from signal to signal. Note that you don't need architectures to manipulate a system with operations like derivation, integration or simplification, because those operations are defined for entities, not architectures.

Ports load architectures dynamically. For example, there is only one addition entity, Std.Add. But you may want to add not only real numbers but also matrices and your own data types. If  all the input signals of a port with the Std.Add entity are real-valued, the port will load an architecture capable of adding real numbers. But if you decide to push matrices instead, the port will look for an architecture capable of adding matrices. Ports may replace their architecture from time to time!

Notes about the naming

Some of you may have noticed that the naming is quite similar to VHDL (btw, there are also processes in yttrium, just like VHDL processes). It's not only the naming: the simulation scheduler should be able to simulate whole VHDL models, too. However, there are some important differences, so you better not relay too much on your VHDL experience when working with yttrium.

If you speak German, you may also checkout another more detailed article on the yttrium website.
Licence Annoyance
06 Mai 06 01:56 | Christoph Rüegg | 4 comment(s)
I was just browsing for the newest wintellect power collections to maybe replace some of my own collections in Math.NET with better tested and optimized ones. Unfortunately they don't seem to like gpl-ed opensource (although they pretend it to be a "community project"), by not allowing me to use it in my projects. Sad.

Where's the problem? Is it me or is it them? As far as I understand both licenses, they're both similar in requiring any software available with sourcecode using it to use the very same license. Would such problems better be evaded by just talking with each other? Would I better stop assigning strict license terms (like GPL, LGPL and BSD) to my opensource projects and leave it to fair use and common sense?
Filed under:
Yttrium Insights, part 3: Yttrium Packages
05 Mai 06 04:16 | Christoph Rüegg | with no comments
One of the more important points in the beginnings of Math.NET Symbolics was extensibility and a dynamic behaviour. You should be able to define your own operations and data structures. To put this to an extreme, the framework core should be seperated and independent from any data types and operations.

The classic symbolics implementation solved this by reflection. All data types and operations were marked with attributes. The core then analyzed the assembly and built a symbol table dynamically. Yttrium still supports dynamic assembly analysis, but uses it as a fallback solution only. In yttrium you define all your extensions in terms of a package. Every package has a name, called the domain, and a package manager class that knows all about the package. To load an external package you hand over an instance of the package manager, and yttrium uses it to update its internal symbol tables. If you don't have an instance but know the assembly, yttrium may look for it by reflection. Only if it doesn't find a package manager it falls back to the old analysis mentioned above. To hand over a package manager use the LoadPackageManager method:

myContext.Library.LoadPackageManager(myPackageManagerInstance);

Package Managers

A package manager is a simple class implementing the IPackageManager interface. Beside of defining a domain, it only provides references to serveral servers which finally provide useful information about the packages. Usually the package manager implements all those servers itself:
  • Entities (IEntityServer): Lists all entities of the package
  • Architectures (IArchitectureServer): Lists all architecture factories for constructing architectures implementing any entities defined in this or other packages.
  • Structures (IStructureServer): Extends the data structures table. This is important for the automatic conversion routing (I'll introduce this in a later post)
  • Theorems (ITheoremServer): Lists all theorems the package provides.
The Standard Package

Yttrium defines a standard package (domain "Std") with very basic data structures and operations in the StdPackage namespace. Usually a package also provides a static class for convenience, with the same name as the domain. Except some shortcuts for convenience (e.g. some overloaded operators on the signal class) the framework core and backend neither refer to nor know anything about this package. If you instanciate a project this package is loaded automatically. However, if you work with the core classes directly (Context, Signal, etc.) you have to load it yourself if you intend to use it (you don't have to):

myContext.Library.LoadPackageManager(new MathNet.Symbolics.StdPackage.StdPackageManager(myContext));

The standard package defines the following data structures at the moment:
  • Integer
  • Rational
  • Real
  • Complex
  • Logic (3-value logic, extensible to IEEE1164 9-value logic as used in VHDL)
  • Literal
  • Toggle (useful e.g. for clocks)
  • Undefined
  • ComplexInfinity
  • NegativeInfinity
  • PositiveInfinity
Yttrium Insights, part 2: In and Out - The System Builder
04 Mai 06 01:57 | Christoph Rüegg | with no comments
A recent addition to the Yttrium framework is the system builder. The idea is to define a "command based" description of a math system (MathSystem class) to seperate the construction of such a system from the system itself. In incorporates ideas from the builder design pattern. The central point is the ISystemBuilder interface, defining the description mentioned above.

There are always to parts, communication by the said interface: a director or reader, and a builder or writer. The interesting point is that both parts are interchangeable: any reader works with any writer and vice versa.

Predefined Writers
  • SystemWriter: constructs a complete math system.
  • XmlSystemWriter: describes a complete system in Xml.
  • ExpressionWriter: experimental, describes a system in the Yttrium expression language supported by the parsing infrastructre (kinf of a mixture between the Maple language and VHDL).
Predefined Readers
  • SystemReader: describes a complete math system.
  • XmlSystemReader: describes a complete system based on Xml.
Because the parts may be combined at will, it opens several useful operations:

Cloning a MathSystem


Cloning a system is as simple as combining a SystemReader with a SystemWriter:

SystemWriter writer = new SystemWriter(myContext);
SystemReader reader = new SystemReader(writer);
reader.ReadSystem(mySystem);
MathSystem clone = writer.WrittenSystems.Dequeue();


Shortcut:

MathSystem clone = mySystem.Clone();


Serialize a MathSystem to Xml

Just combine the SystemReader with an XmlWriter:

XmlSystemWriter writer = new XmlSystemWriter(myContext, myWriter);
SystemReader reader = new SystemReader(writer);
reader.ReadSystem(mySystem);
myWriter.Flush();

Shortcut:

mySystem.WriteXml(myWriter);


Deserialize a MathSystem from Xml

SystemWriter writer = new SystemWriter(myContext);
XmlSystemReader reader = new XmlSystemReader(writer);
xreader.ReadSystems(myReader, false);
MathSystem system = writer.WrittenSystems.Dequeue();


Shortcut:

MathSystem
system = MathSystem.ReadXml(myReader, myContext);
Yttrium Insights, part 1: Traversing a Math System
04 Mai 06 11:46 | Christoph Rüegg | 1 comment(s)
Yttrium models basically are arbitrary bibartite directed graphs with ports on one and signals (and buses) on the other side. Signals connect ports with each other in any way, including loops and cycles.
 


The screenshot above shows two cyclic models with three ports each (divide, add, multiply - click on the image to zoom in), where signal E depends on (A, D), signal D depends on (A,C) and signal C depends on (A,B,E), closing the cycle. The lower model is a simplified version of the upper: two pointless operations (adding constant 0 and multiply by a constant 1)  are removed. This was automatically generated by the attached "asimplify" port in the upper model (it generated the lower D as a simplified version of the upper D). Although this sounds simple, it's quite a complex operation. For this and nearly all other operations on a model one needs a proper way to traverse the model. This could be programmed manually for every operation as the signals know their source port (but not their target ports) and the ports know both input and output signals, but that's hardly an option as programming it should be "simple".

Traversing Graphs

Often, traversing is implemented with the iterator pattern. Iterators are perfectly supported by the .NET framework and C# 2.0 (Enumerator classes and interfaces, foreach, yield). However, there are multiple ways to walk through a tree (classical: in-order, pre-order and post-order), and even more to walk though cyclic graphs. Some algorithms just need to iterate though all signals in arbitrary order, others need spanning trees or even all possible (non-cyclic) paths to a given signal or port. Some algorithms want to stop following the current path on some special conditions. In short, there are quite a few ways to iterate a system. To keep it customizable and extensible we move the actual iterator logic to separate classes in terms of the strategy pattern. You may implement your own strategies, but I already implement five strategies:
  • All Signals (every signal only once)
  • All Ports
  • Spanning Tree
  • All Paths (from any node to the given root node)
  • All (completely controllable by the visitor, see below)
Do Something While Traversing

Of course it's only interesting to traverse a graph if you can actually do something with the elements. Because our graph is not homogeneous, the we can't just "yield" any items found. Instead, the strategies take along visitors who visit any elements the strategy passes. This is the classical visitor pattern. Again there are several predefined visitors available:
  • SignalActionVisitor (does something with every signal)
  • PortActionVisitor
  • SignalConditionalActionVisitor
  • PortConditionalActionVisitor
  • CollectVisitor (collects any Signals/Buses/Ports visited)
  • ConditionalCollectVisitor
  • SignalPathCollectVisitor (collects any paths to a signal as a list of signal-lists)
  • PortPathCollectVisitor
  • ExistsSignalVisitor (to check whether a signal matches a predicate)
  • ExistsPortVisitor
  • TrueForAllSignalsVisitor (to check whether all signals match a predicate)
  • TrueForAllPortsVisitor
Manipulation System

In a computer algebra system you may want to substitute some elements, simplify or derive algebraic systems, apply trigonometric conversions and so on. In all this cases you need to manipulate the system, or more exactly build a new signal tree without touching the existing tree but reusing as much as possible. For example, if you substitute a signal only one of the root operands depend on, you don't want to clone the other operands, only the depending one. Most of the complexity of this process is common to all operations, e.g. the handling of cycles and cyclic dependencies.

The Manipulator class provides a solution based on the traversing system introduced above. It introduces a new kind of second order visitors, IManipulationVisitor. You may implement your own manipulation visitors, but often it's easier to provide transformations in terms of the theorems subsystem. transformation theorems (ITransformationTheorem) are executed using the TransformationManipulatorVisitor (implements IManipulationVisitor) and the Manipulator class.

The standard package provides three transformation theorem types at the moment:
  • AutoSimplify (automatic simplification)
  • Derive (algebraic derivation)
  • TrigonometricSubstitute (e.g. transform csc(x) to 1/sin(x))