How to implement decision matrix in c#

Aether McLoud picture Aether McLoud · Jun 3, 2013 · Viewed 8.6k times · Source

I need to make a decision based on a rather large set of 8 co-dependent conditions.

           | A | B | C | D | E | F | G | H
-----------+---+---+---+---+---+---+---+---
Decision01 | 0 | 1 | - | 1 | 0 | 1 | - | 1
Decision02 | 1 | 0 | - | 0 | 0 | - | 1 | -
    ...   
Decision11 | 1 | 0 | 1 | 1 | 1 | - | 1 | 1

Each of the conditions from A to H can be true (1), false (0) or non-relevant (-) for the decision.

So with a given input of

A B C D E F G H 
1 0 1 0 0 1 1 1

it should evaluate to Decision02.

The decisions are unambiguous so from any given set of input conditions it's clear which decision has to be made (and in a case that isn't covered by the decision matrix, an exception shall be thrown).

The developer who worked before me on this project tried to implement this as a 500 line long nested-if behemoth which of course is buggy as hell and isn't maintainable.

So I searched for the best way to implement such a piece of logic and I've come upon decision tables/lookup tables/control tables.

I've found a lot of decision table generators, but not a single piece of code on how to implement the decision making process :(

I can make the decision table in the underlying MSSQL database, or in code, or xml, or whatever it takes. I just need some pointers on how to implement this at all.

What's the best practice to implement this logic? Dictionary? Multidimensional array? Something completely different?

Answer

Jan Thomä picture Jan Thomä · Jun 3, 2013

You could do it with arrays of Func.

static Func<bool,bool> isTrue = delegate(bool b) { return b; };
static Func<bool,bool> isFalse = delegate(bool b) { return !b; };
static Func<bool,bool> isIrrelevant = delegate(bool b) { return true; };

Now you could put your matrix into a Dictionary like this:

Dictionary<string,Func<bool,bool>[]> decisionMatrix = new Dictionary<string,Func<bool,bool>[]>();
// 0 | 1 | - | 1 | 0 | 1 | - | 1
matrix.Add("Decision01", new Func<bool,bool>{isFalse, isTrue, isIrrelevant, isTrue, isFalse, isTrue, isIrrelevant, isTrue});

Finally for every given input array:

bool[] input = new bool[]{ false, true, false, true, false, true, false, true}

string matchingRule = null;
foreach( var pair in matrix ) {
    bool result = true;
    for( int i = 0; i < input.Length; i++) {
       // walk over the function array and call each function with the input value
       result &= pair.Value[i](input[i]);
    }

    if (result) { // all functions returned true
        // we got a winner
        matchingRule = pair.Key;
        break;
    }
}

// matchingRule should now be "Decision01"

This should probably get some more checks (e.g. checking that the input array has the correct size) but should give you some idea. Using Funcs also gives you some more flexibility in case you get a fourth state.