Friday, March 7, 2008

ShapeLogic 1.0 with stream based rules released

Here are the release notes for ShapeLogic 1.0

Changes

  • Rule for image processing have been migrated, previously they were implemented as goal driven tasks with sub tasks. Version 1.0 uses lazy streams which are simpler and more powerful.
  • Letter match example now matches all polygons instead of just the first found.
  • When running ShapeLogic as ImageJ plugin, it is now easy for users to define rules for matching in external Java files.
  • New number matcher to demonstrate how to define rules for matching in an external Java file in 130 lines of code.
  • Enabled use of Java 6 Scripting for rule database, which gives the user access to the 25 scripting languages that are supported
  • ShapeLogic now has beta development status
  • Many unit tests added for Lazy Stream library
  • Fixed bugs in Lazy Stream library
  • Fixed bugs in vectorizer

Lazy streams features

  • Lazy streams can be named and defined based on other lazy streams
  • They work similarly to UNIX pipes or calculation Legos
  • They serve as your query construct, you can directly query them
  • A stream can be wrapped around an Iterator
  • A stream can be created from an input stream and a Calculation
  • They can be instantiated lazily, so you can load calculation networks independently
The lazy stream worked very well with the letter match. It started out as a functional construct, but with the named streams they got a more declarative feel to them.

The Calculation in the stream is using the same signature as Neal Grafter's Java 7 closure prototype. This might make integration with Java 7 easier.

User defined rules for number match

The most significant change is that it has become a lot simpler for users to define rules. Here is the start of DigitStreamVectorizer_ the number matchre in 130 lines of code. Notice that there is barely any setup code. It is almost only rules, defined in a very simple format.

public class DigitStreamVectorizer_ extends StreamVectorizer_ {

@Override
public void matchSetup(ImageProcessor ip) {
loadDigitStream();
}

public static void loadDigitStream() {
LoadPolygonStreams.loadStreamsRequiredForLetterMatch();
makeDigitStream();
String[] digits = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
LoadLetterStreams.makeLetterXOrStream(digits);
}

public static void makeDigitStream() {

rule("0", HOLE_COUNT, "==", 1.);
rule("0", T_JUNCTION_POINT_COUNT, "==", 0.);
rule("0", END_POINT_COUNT, "==", 0.);
rule("0", MULTI_LINE_COUNT, "==", 1.);
rule("0", CURVE_ARCH_COUNT, ">", 0.);
rule("0", HARD_CORNER_COUNT, "==", 0.);
rule("0", SOFT_POINT_COUNT, ">", 0.);

rule("1", HOLE_COUNT, "==", 0.);
rule("1", T_JUNCTION_LEFT_POINT_COUNT, "==", 0.);
rule("1", T_JUNCTION_RIGHT_POINT_COUNT, "==", 0.);
rule("1", END_POINT_BOTTOM_POINT_COUNT, "==", 1.);
rule("1", HORIZONTAL_LINE_COUNT, "==", 0.);
rule("1", VERTICAL_LINE_COUNT, "==", 1.);
rule("1", END_POINT_COUNT, "==", 2.);
rule("1", MULTI_LINE_COUNT, "==", 0.);
rule("1", SOFT_POINT_COUNT, "==", 0.);
rule("1", ASPECT_RATIO, "<", 0.4);

ShapeLogic's 3 different approaches to declarative programming

Here is a chronological listing of ShapeLogic's 3 different approaches declarative logic:
  1. Declarative goal driven logic engine. From ShapeLogic 0.2.
  2. Logic filter language. From ShapeLogic 0.8 The syntax and development of the logic language is better described in Logic language.
  3. Lazy streams. From ShapeLogic 0.9.

Result of different approaches so far

For the letter matching example, the lazy stream approach has been both simpler and more powerful than the goal driven logic engine.

The Artificial Intelligence choice tree is built into the logical structure of goal driven logic engine, so this approach might work well when reasoning under uncertainty.

The logic filter language is used with both lazy streams and goal driven approach.

ShapeLogic is a toolkit, all 3 approaches are available with unit tests.

For now development is focused on the lazy stream approach.

JSR 223 scripting surprise

I had put a lot of energy into making it easy to create a stream from a Scripting snippet in either Groovy, JRuby or JavaScript. This was clearly superior to text snippet rules defined using Apache Commons JEXL under the Declarative goal driven approach, but using the new Stream it turned out not to be necessary. The rules could easily be defined in plain Java. I still think that good integration with streams and Scripting from ShapeLogic might turn out to be useful.

Download ShapeLogic 1.0

-Sami Badawi
http://www.shapelogic.org