Click here to Skip to main content
Email Password   helpLost your password?

BinaryRuleVisualization

Introduction

This article shows a WPF application that takes a set of simple rules, some input data to be processed by those rules, and then allows us to visualize the result of applying those rules to the input data. The rules and input data are stored in XML files, allowing you to have various configurations with which to experiment.

Background

At work the other day, I was talking with a good friend of mine, Grant Hinkson. Grant mentioned that he has been reading Stephen Wolfram’s book, “A New Kind of Science”. He explained the idea of Cellular Automaton to me, which caught my interest and got my imagination going. The idea of having a simple set of rules that apply to basic building blocks, and then seeing what large-scale phenomena can arise out of applying those rules repeatedly, is very intriguing to me.

Now, before going one step further, I must make something very clear. I have not studied Wolfram’s work, I do not claim to understand his ideas, nor is my program in any way trying to demonstrate his concepts. His Mathematica product does an excellent job of that. I was simply inspired by a discussion about Cellular Automaton, and built a simple program based on that inspiration.

The Idea of a Binary Rule System

The idea is simple: take a sequence of numbers, apply some rules to those numbers, and get a new sequence of numbers. Each number in the input sequence results in one number in the output sequence. The rules can contain any logic that you want. The simplest rule would be to return the input value. In my program, each rule returns the same output value for a given input value, but that output value is configurable.

So, why do I call it a “binary” rule system? My rule system only works with the values zero through seven. Those eight numbers can be represented by the first three binary values (i.e., 000 through 111 in binary). When we render the numbers later, we will display each number as a visualization of its binary representation.

Visual Explanation

Let’s start with the simplest example. In the demo project, the simple1.xml file contains this configuration:

<?xml version="1.0" encoding="utf-8" ?>
<config iterations="8">
  <rules>
    <rule input="0" output="1" />
    <rule input="1" output="2" />
    <rule input="2" output="3" />
    <rule input="3" output="4" />
    <rule input="4" output="5" />
    <rule input="5" output="6" />
    <rule input="6" output="7" />
    <rule input="7" output="0" />
  </rules>
  <numbers>
    <number value="0" />
  </numbers>
</config>

The configuration seen above shows the fundamentals. The <rules> section specifies how to map an input value to an output value. The mappings in this example simply walk up the number line in ascending order. The <numbers> section only has one number, zero. This means that the application will only display one number and start applying the rules to just that number. How many times will the rules be applied? As you can see in the <config> element, the rules will be applied eight times, as specified by the ‘iterations’ attribute.

Running the program using the configuration above will create a visualization of these numbers, in decimal:

0
1
2
3
4
5
6
7

You could also say that it is a visualization of those same numbers, but in binary:

000
001
010
011
100
101
110
111

Here is a screenshot of the program running when this configuration is applied, where a black cell represents 0 and a white cell represents 1. Each "row" of cells in the image represents a number, and the numbers increase as you move down from row to row.

simple1.png

It is also possible to specify how each bit in a number should render. As seen above, by default, a bit is black if its value is 0, and white if its value is 1. The simple2.xml file in the demo project shows how you can specify the colors of each bit when it is 1. Here is that file:

<?xml version="1.0" encoding="utf-8" ?>
<config 
  color1="White" 
  color2="LightGray" 
  color3="Gray"
  iterations="8"
  >
  <rules>
    <rule input="0" output="1" />
    <rule input="1" output="2" />
    <rule input="2" output="3" />
    <rule input="3" output="4" />
    <rule input="4" output="5" />
    <rule input="5" output="6" />
    <rule input="6" output="7" />
    <rule input="7" output="0" />
  </rules>
  <numbers>
    <number value="0" />
  </numbers>
</config>

Running the program with that configuration file loaded looks like this:

simple2.png

So far, we have only seen an example with one number in the <numbers> section. The visualizations become more interesting as we add more input numbers. The next configuration, in the simple3.xml file, has eight input numbers. Each of those numbers renders side-by-side in the same row. Here is the next configuration:

<?xml version="1.0" encoding="utf-8" ?>
<config 
  color1="White" 
  color2="LightGray" 
  color3="Gray"
  iterations="8"
  >
  <rules>
    <rule input="0" output="1" />
    <rule input="1" output="2" />
    <rule input="2" output="3" />
    <rule input="3" output="4" />
    <rule input="4" output="5" />
    <rule input="5" output="6" />
    <rule input="6" output="7" />
    <rule input="7" output="0" />
  </rules>
  <numbers>
    <number value="0" />
    <number value="1" />
    <number value="2" />
    <number value="3" />
    <number value="4" />
    <number value="5" />
    <number value="6" />
    <number value="7" />
  </numbers>
</config>

The above configuration renders like this:

simple3.png

The final example in this section is a configuration that takes the previous input numbers and creates a mirror symmetry of them, uses more exciting colors, and increases the number of times that the rules are applied. The resultant visualization is visually appealing, especially if you view it at a larger size. The simple4.xml configuration file is shown below:

<?xml version="1.0" encoding="utf-8" ?>
<config 
  color1="DodgerBlue" 
  color2="Orange" 
  color3="Lime"
  iterations="200"
  >
  <rules>
    <rule input="0" output="1" />
    <rule input="1" output="2" />
    <rule input="2" output="3" />
    <rule input="3" output="4" />
    <rule input="4" output="5" />
    <rule input="5" output="6" />
    <rule input="6" output="7" />
    <rule input="7" output="0" />
  </rules>
  <numbers>
    <number value="0" />
    <number value="1" />
    <number value="2" />
    <number value="3" />
    <number value="4" />
    <number value="5" />
    <number value="6" />
    <number value="7" />
    <number value="6" />
    <number value="5" />
    <number value="4" />
    <number value="3" />
    <number value="2" />
    <number value="1" />
    <number value="0" />
  </numbers>
</config>

The configuration seen above looks like this:

simple4.png

How the Rule System Works

The rule system is very simple. It consists of a class that represents a number and a class that represents a rule. Each of those two classes has a corresponding collection class. Here is the BinaryNumber class, which represents a number:

public class BinaryNumber
{
    byte _value;

    public BinaryNumber(byte value)
    {
        if (value < 0 || 7 < value)
            throw new ArgumentOutOfRangeException("value");

        _value = value;
    }

    public bool Bit1
    {
        get { return _value % 2 == 1; }
    }

    public bool Bit2
    {
        get { return (_value >> 1) % 2 == 1; }
    }

    public bool Bit4
    {
        get { return (_value >> 2) % 2 == 1; }
    }

    public byte Value
    {
        get { return _value; }
    }
}

This class is a wrapper around a byte value. The Bit1, Bit2, and Bit4 properties come into play later, when we create a visualization for this class. Each of those properties return true if the bit they represent is “on” for the BinaryNumber’s value. For example, if the value is five (101 in binary), Bit4 returns true, Bit2 returns false, and Bit1 returns true.

We create a sequence of BinaryNumbers by adding them to a BinaryNumberCollection. That class also provides the logic for getting the output values created by applying the rules to its sequence of values. Here is that class:

public class BinaryNumberCollection : ReadOnlyCollection<BinaryNumber>
{
    readonly BinaryRuleCollection _rules;

    public BinaryNumberCollection(IList<BinaryNumber> list, BinaryRuleCollection rules)
        : base(list)
    {
        _rules = rules;
    }

    public BinaryNumberCollection OutputNumbers
    {
        get
        {
            var outputQuery =
                from number in base.Items
                select _rules.ApplyRule(number);

            return new BinaryNumberCollection(outputQuery.ToList(), _rules);
        }
    }
}

The BinaryRule class represents a rule, which is quite simple:

public class BinaryRule
{
    public BinaryRule(byte input, byte output)
    {
        this.Input = new BinaryNumber(input);
        this.Output = new BinaryNumber(output);
    }

    public BinaryNumber Input { get; private set; }
    public BinaryNumber Output { get; private set; }
}

Rules are added to a BinaryRuleCollection, an instance of which is shared by all BinaryNumberCollection objects. The collection of rules provides a way to get the output value created by a rule for an input value. That class is listed below:

public class BinaryRuleCollection : ReadOnlyCollection<BinaryRule>
{
    public BinaryRuleCollection(IList<BinaryRule> list)
        : base(list)
    {
    }

    public BinaryNumber ApplyRule(BinaryNumber input)
    {
        BinaryRule rule = 
            base.Items.FirstOrDefault(r => r.Input.Value == input.Value);

        if (rule == null)
        {
            Debug.Fail("Missing rule for input value " + input.Value);
            return null;
        }

        return rule.Output;
    }
}

How the Visualization Works

So far, we have not talked about how I created the visualizations. We have focused only on what a binary rule system is and how it works. Now, it is time to turn our attention to the rendering aspect of this program.

There are many ways that I could have implemented the rendering. I wanted to keep it simple, and use data binding and data templates as much as possible. I know there are other ways that would perform marginally faster, but performance is not a priority for me. I would rather keep it simple and easy to configure in XAML.

The program has two data templates. One template renders a BinaryNumber object. It displays three Rectangles in a StackPanel, each representing a binary bit in the number. That template is shown below:

<DataTemplate DataType="{x:Type model:BinaryNumber}">
  <StackPanel Orientation="Horizontal">
    <StackPanel.Resources>
      <Style TargetType="Rectangle">
        <Setter Property="Height" Value="1" />
        <Setter Property="Width" Value="1" />            
      </Style>
    </StackPanel.Resources>
    <Rectangle x:Name="bit4" />
    <Rectangle x:Name="bit2" />
    <Rectangle x:Name="bit1" />
  </StackPanel>
  <DataTemplate.Triggers>
    <DataTrigger Binding="{Binding Bit1}" Value="True">
      <Setter 
        TargetName="bit1" 
        Property="Fill" 
        Value="{DynamicResource color3}" 
        />
    </DataTrigger>
    <DataTrigger Binding="{Binding Bit2}" Value="True">
      <Setter 
        TargetName="bit2" 
        Property="Fill" 
        Value="{DynamicResource color2}" 
        />
    </DataTrigger>
    <DataTrigger Binding="{Binding Bit4}" Value="True">
      <Setter 
        TargetName="bit4" 
        Property="Fill" 
        Value="{DynamicResource color1}" 
        />
    </DataTrigger>
  </DataTemplate.Triggers>
</DataTemplate>

The brushes used to paint each Rectangle come from a dynamic resource reference. Those brushes are placed into the Application.Resources collection. That logic exists in the Configuration class’ constructor, as shown below:

XDocument xdoc = XDocument.Load(configFilePath);
XElement configElem = xdoc.Element("config");
BrushConverter converter = new BrushConverter();
for (int i = 1; i <= 3; ++i)
{
    string colorName = "color" + i;

    XAttribute attr = configElem.Attribute(colorName);
    Brush brush;
    if (attr == null)
        brush = Brushes.White;
    else
        brush = converter.ConvertFromString(attr.Value) as Brush;

    App.Current.Resources[colorName] = brush;
}

The BinaryNumberCollection class also has a data template. That template displays all of the collection’s BinaryNumber objects in an ItemsControl. Each of those ItemsControls can be thought of as a “row” in the visualization. That template declaration looks like this:

<DataTemplate DataType="{x:Type model:BinaryNumberCollection}">
  <ItemsControl ItemsSource="{Binding}">
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal" />
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
  </ItemsControl>
</DataTemplate>

The container for all of the BinaryNumberCollections is an ItemsControl, whose ItemsSource property is set to a List<BinaryNumberCollection> in the code-behind. That ItemsControl is wrapped in a Viewbox so that it renders nicely no matter what size the Window happens to be. Those elements are shown below:

<Border 
  Background="Black"
  BorderBrush="Black" 
  BorderThickness="3" 
  Margin="6" 
  Padding="1"
  >
  <Viewbox Stretch="Fill">
    <ItemsControl x:Name="itemList"  />
  </Viewbox>
</Border>

Conclusion

This might not be the most useful program or article out there, but I think it is fun and interesting. The simple, declarative way that WPF can create an appealing visualization of this data is, in itself, appealing. I hope you enjoyed this article and, perhaps, learned a thing or two along the way. Happy coding!

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralGood Article
BlitzPackage
7:04 29 Jun '08  
Josh,

Excellent article. The topic stretches my understanding so it must be good.

I do have an additional question. I noticed an article you wrote on dynamically loading content (e.g. Grids, ListBoxes, FlowDocumentReaders, etc...). Is there a good place where I can find information on how to dynamically load then discard certain items?

Thanks,
BP
GeneralRe: Good Article
Josh Smith
15:46 1 Jul '08  
BlitzPackage wrote:
Is there a good place where I can find information on how to dynamically load then discard certain items?

I'm not sure what you mean. Please clarify...

:josh:
My WPF Blog[^]
All of life is just a big rambling blog post.

GeneralRe: Good Article
BlitzPackage
2:38 2 Jul '08  
Hey Josh,

Thanks for replying.

Based on what the user enters, they will see different screens within the "main area" of the software. I use a grid to layout the GUI. The area in the 2nd column and 1st row is the main area (and is about 1/3rd the size of the entire screen). In this area, I need to dynamically load and discard content. So, for example, if the user is entering information about themselves, I must load a list box, buttons, and a picture. If the user is looking at other information they have entered, then I must load a rich text box or flow document viewer. If the user wants to see data, then I must load some graphs, etc....

I need to know the best way to load what I need - where I need it, then discard them when finished so they are not taking up memory.

Thanks Josh, I appreciate any direction you can provide.
GeneralRe: Good Article
Josh Smith
3:12 2 Jul '08  
There are many ways to do what you describe. The one I would use, assuming I have a relatively clean slate to work with, is as follows. Each View that you display is a custom UserControl. The data and domain logic of the view is baked into a corresponding ViewModel class, to which the View communicates via data binding and executing commands. The ViewModel objects are placed, one at a time, into the Content property of a ContentControl, which is in the main Window/Page. That ContentControl's Resources contains a typed DataTemplate for each type of ViewModel that it might contain. Each DataTemplate simply wraps the UserControl you created for a ViewModel class. You end up with a one-to-one relationship between ViewModel class, UserControl, and typed DataTemplate.

The final result of this approach is quite enticing. When the user wants to view, say, the the Edit My Info screen (as you mentioned) they click perhaps a button on a Toolbar called "Edit My Info". In response to that action, you would load up and place a UserProfileViewModel object into the ContentControl's Content property. Since you previously added a typed DataTemplate for UserProfileViewModel to the ContentControl's Resources, your UserProfileControl will automatically be displayed in the ContentControl and bind itself to the ViewModel object. When the user navigates to another View, the UserProfileControl will be removed and thrown away for you.

:josh:
My WPF Blog[^]
All of life is just a big rambling blog post.

GeneralRe: Good Article
BlitzPackage
5:20 2 Jul '08  
Thanks Josh, that's very helpful. Do you know of any place I can find an example of what you mentioned. It really seems good. Being new to WPF, I think an example would help me out tremendously.

Thanks again.
GeneralRe: Good Article
Josh Smith
5:24 2 Jul '08  
BlitzPackage wrote:
Do you know of any place I can find an example of what you mentioned.

Not off the top of my head. You should search the Web for "ViewModel WPF" and check out some examples. Maybe one day soon I'll throw together an example and write an article about it. I wrote an article[^] about using a ViewModel with the TreeView control. Maybe that will give you a good starting point.

:josh:
My WPF Blog[^]
All of life is just a big rambling blog post.

GeneralRe: Good Article
BlitzPackage
5:26 2 Jul '08  
Thanks Josh, I'm off to get some information.

BP
GeneralStrange but somehow cool
Sacha Barber
22:17 1 Jun '08  
This is a strange one, but still of interest.

Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: Strange but somehow cool
Josh Smith
2:46 2 Jun '08  
Thanks Sacha. I really enjoyed writing this one. Though, I am not surprised that it got low votes right away. I guess some people dislike articles that are not imminently useful, for whatever reason.

:josh:
My WPF Blog[^]
All of life is just a big rambling blog post.

GeneralRe: Strange but somehow cool
Sacha Barber
3:54 2 Jun '08  
Yeah I think you are right

Sacha Barber
  • Microsoft Visual C# MVP 2008
  • Codeproject MVP 2008
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

GeneralRe: Strange but somehow cool
Marc Clifton
5:52 2 Jun '08  
Strange but cool is certainly true! It makes me wonder how a visualization of the movie kiosk distribution system would look like--the whole thing is rule based, whether certain formats exist, whether they've been encoded at different playback rates, whether the movie is corrupted or not, and of course, a realtime visualization of the active movies, their distribution and all that.

Crazy stuff!

(oh, and a 5 from me. I will be perusing your WPF code when I finally get a chance to write my next installment)

Marc


GeneralRe: Strange but somehow cool
Josh Smith
6:03 2 Jun '08  
Thanks Marc. I was hoping that this article would trigger others to apply this visualization idea to "real" data. I'd love to see such an article... Wink

:josh:
My WPF Blog[^]
All of life is just a big rambling blog post.

GeneralPerfect
wanghualiang
20:23 1 Jun '08  
Smile
GeneralRe: Perfect
Josh Smith
2:49 2 Jun '08  
Thank you!

:josh:
My WPF Blog[^]
All of life is just a big rambling blog post.


Last Updated 1 Jun 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010