Logic-Grid: An Elegant Alternative to Your If-Else Nightmare!

Introduction

Deeply nested if-else and giant switch statements are a common sight in any complex logic implementation. Maintaining such a messy chunk of code is really a nightmare. In this article, I will describe a very effective technique that I call a logic-grid technique. This technique comes in very handy in implementing rule engines and finite state machines (FSM).

Typically, any logic has a set of boolean predicates that are evaluated to obtain a result or to perform an action. In the logic-grid approach, the results are stored in an array and the index of the array is calculated from a bitwise combination of boolean predicates. The key to this approach is that the logic is embedded into data instead of sequence of logic statements. Thinking beyond the bits and bytes, the approach draws parallel with the way people make decisions. We evaluate all the inputs available at a moment and make the best possible decision.

Description

Start by understanding the technique, implementing it, and comparing it to the standard logic statement approaches and also highlight its merits and limitations.

As you can see, the result or output depends on the values of variables a, b, and c. Observe that variable a is a priority input. Usually, logic statements are constructed in a way that priority inputs are evaluated first. To convert the logic into a logic-grid, create a table with variables a, b, c, and result as columns. There are three boolean variables; hence, you can have 2^3 = 8 combinations and therefore 8 possible outcomes.

After evaluating each combination and obtaining the results (shown in Table 1):

Table 1

a

b

c

result

1

1

0

1

1

1

1

1

1

0

0

2

1

0

1

2

0

1

1

3

0

0

1

4

0

0

0

5

0

1

0

5

Note that input a, being a priority input, is entered into the left-most columns in the table or made the most significant bit. Now, re-arrange the table as follows (shown in Table 2)

Table 2

a

b

c

result

0

0

0

5

0

0

1

4

0

1

0

5

0

1

1

3

1

0

0

2

1

0

1

2

1

1

0

1

1

1

1

1

Observe the re-arranged table. You can easily deduce that each of a, b, and c can be encoded as a bit (1 - true and 0 - false) and the combination of these bits form an index to the array of results.

Here, I have taken a simple scenario only to provide insight into the technique without bogging you down with a complex interplay of logic. In reality, this technique scales superbly with the increase in logical complexity.

The right candidates for applying this technique are finite state machines (FSM), rule engines, and other logic-intensive applications. When I think of an FSM, the electromechanical switch comes to my mind, very much like a hello world program. An electromechanical switch has two states—on-state and off-state—and there can be two possible inputs: on-pressed and off-pressed.

You can model the switch's function by using three inputs and two outputs. The inputs are press-on, press-off, and current-state. The current state of the switch is considered an input because of the next state and output/action dependent on it. The outputs are action taken and next state (shown in Table 3).

Table 3

Press-on

Press-off

Current state

Action

Next state

0

0

OFF

Don't care

OFF

0

0

ON

Don't care

ON

0

1

OFF

Do nothing

OFF

0

1

ON

Switch OFF

OFF

1

0

OFF

Switch ON

ON

1

0

ON

Do nothing

ON

1

1

OFF

Don't care

OFF

1

1

ON

Don't care

ON

The "Don't care" action is specified for invalid inputs and "Do nothing" indicates that the inputs are valid but that there is no need to change state or do any action. Note that don't care and do nothing actions are used synonymously just to simplify the implementation.

For any usable finite state machine, there are obviously more than two states. In the logic-grid approach, each input can have only two values: 0 or 1. If there are more than two states, you need more than one bit to represent each state. A workaround would be to represent each state as a bit. Now, there are four inputs because the Current state is divided into two inputs, OFF-STATE and ON-STATE (shown in Table 4). This approach requires a 16-byte array as opposed to an 8-byte array in the previous approach.

Table 4

Press-on

Press-off

Current stateOFF

Current stateON

Action

Next state

0

0

0

0

Invalid

Invalid

0

0

0

1

Invalid

ON

0

0

1

0

Invalid

OFF

0

0

1

1

Invalid

Invalid

0

1

0

0

Invalid

Invalid

0

1

0

1

Switch OFF

OFF

...

...

...

...

...

...

...

...

...

...

...

...

Encoding each state as a bit will lend the logic-grid incomprehensible. The large number of invalid inputs proves this. Moreover, it does not make sense to encode each state as a bit because a system will be in only one state at any one time.

A better approach is to create a 2-dimensional array with states as rows and inputs as columns. If there are 6 states and 4 inputs/signals, you can have a maximum possible 6 * 2^4 = 96 inputs. Otherwise, if you model each state as an input bit, we end up with 2^10 (6+4) inputs, a 1024 combination of inputs. Such an approach is discarded for obvious reasons.

Summary

Logic-grid is an attractive solution for logic-intensive applications. Because logic is embedded in data as opposed to code, future modifications in logic is a matter of changing the grid data. If the logic involving the existing parameters changes, the logic-grid is easier to maintain. However, adding new parameters or inputs requires expanding and re-evaluating the whole grid. For trivial logic, one is better off using a bunch of if-else statements. As a rule of thumb, use the technique for logic involving more than three parameters.

About the Author

Narendra Venkataraman

senior software engineer at Hewlett Packard Telecom Division. In his spare time, he blogs.

Comments

excellent and maintainable solution for logic intense code

Posted by mpaut
on 08/26/2008 10:27pm

I had 3 inputs and an output that requires different kind of sequential action (no states). I have drawn already a table but did not know how to put it into the machine without if-then's. Then i found this article - now i got this bitmasking stuff! Made for the output sequence another table and bitmasked this again. Only a few lines of code and i can change actions/sequences with a wink! Great!

embedding logic into data

Posted by cilu
on 07/01/2005 05:37pm

Just after reading your article, some time ago, I had this great idea of embedding the logic into data (though with a different approach) in a project and it simplified so much the design. So thanks for the spark.

that's nice!

Posted by vnaren
on 07/02/2005 11:55am

guess other folks would benefit if you can say a few words on how you applied:-)

Top White Papers and Webcasts

U.S. companies are desperately trying to recruit and hire skilled software engineers and developers, but there is simply not enough quality talent to go around. Tiempo Development is a nearshore software development company. Our headquarters are in AZ, but we are a pioneer and leader in outsourcing to Mexico, based on our three software development centers there. We have a proven process and we are experts at providing our customers with powerful solutions. We transform ideas into reality.

When individual departments procure cloud service for their own use, they usually don't consider the hazardous organization-wide implications. Read this paper to learn best practices for setting up an internal, IT-based cloud brokerage function that service the entire organization. Find out how this approach enables you to retain top-down visibility and control of network security and manage the impact of cloud traffic on your WAN.