0

I had some first experience with creating and traversing graphs. But now I have a problem, of which I don't now, if boost::graph has some algorithms to solve it.

Here is my graph-definition:

const int _AND   = 1001;
const int _OR    = 1002;
const int _ITEM  = 1003;

struct gEdgeProperties
{
  string label;
};

struct gVertexProperties
{
   string label;
   int typ; // _AND, _OR, ITEM
};

typedef adjacency_list< vecS, vecS, undirectedS, gVertexProperties, gEdgeProperties>      
BGraph;

So BGraph contains items and logical relations between them. Now I would like to transform this graph into multiple graphs, each of which should contains NO or-relations, but represent all by the OR-vertices defind combinatorial alternates of items and their AND-relations.

An example: if there are three items A, B, C related so: A AND ( B OR C) then the result of the traversal should be two graphs, containing the following combinations: (1) A AND B (2) A AND C

My (simple) idea now is to traverse the graph, and each time the traversal finds an OR-vertex, to copy the whole graph and follow from there on each part of the OR-node recursive:

if graph[vertex] == OR {
for (... // each child vertex of vertex BGraph newGraph = copy(Graph); traverse(newGraph,childVertex); } }

This won't work correctly, because my recursive call of each child would miss the stack structure (the information, how to come back upwards in the graph). This means: the traversal would climb down correct, but not upwards again.

I have no idea, if there is a more (or at all) efficient way to solve such a problem with boost::graph and its embedded algorithms.

But to me it seems to be an interesting problem, so I would like to discuss it here, maybe it leads to a deeper insight of boost::graph.

Thank you!

Mike75
  • 504
  • 3
  • 18

2 Answers2

0

My overall approach would be to do a depth-first walk of the input graph, and construct the output graphs bottom-up. Because you want to construct an arbitrary number of graphs, the traversal function has to return a list of graphs.

So here's an algorithm in pseudo-code

-- syntax: [xxx,xxx,...] is a list, and (xxx AND yyy) is a node.

traverse (node):
    if typeof(node) == term
        return [ node ]
    else
        leftlist = traverse(node.left)
        rightlist = traverse(node.right)
        if node.condition == OR
            result = leftlist .appendAll( rightlist )
        else if node.condition == AND
            result = [ ]
            foreach left in leftlist
                foreach right in rightlist
                    result .append( (left AND right) )
        else
            panic("unknown condition")
    return result

For example: pass in ((A OR B) AND (C OR D))

The individual terms compile to simple lists:

A -> [A]
B -> [B]
C -> [C]
D -> [D]

The OR conditions simply become parallel queries:

(A OR B) -> [A] OR [B] -> [A, B]
(C OR D) -> [C] OR [D] -> [C, D]

The AND condition must be combined in all possible permutations:

(... AND ...) -> [A, B] AND [C, D] -> 
    [(A AND C), (A AND D), (B AND C), (B AND D)]

Hope this helps. If you cast it into C++, you'll have to take care of housekeeping, i.e., destroying intermediate list objects after they are no longer needed.

Peter Raynham
  • 647
  • 3
  • 6
  • Thank you. This is very helpful. I will try to port your code to python first, cause it has the list structures as in your code. Is this MatLab? Thank you for your solution!!! – Mike75 Sep 26 '14 at 23:55
0

Here the adoption to python as addition (Thanks again, it works great!!!):

    _AND        = 1
    _OR         = 2
    _ITEM       = 3

    class Node:
        def __init__(self, name):
            self.name = name
            self.condition = _ITEM
            self.left = None
            self.right = None

    def showList(aList):
        for node in aList:
            print " elem cond: " , node.condition, " left: ", node.left.name, " right: ", node.right.name

    def traverse (node):
        leftlist = None
        if node.condition == _ITEM:
            return [ node ]
        else:
            leftlist = traverse(node.left)
            rightlist = traverse(node.right)
            found = 0
            if node.condition == _OR:
                found = 1
                result = leftlist
                for right in rightlist:
                    result.append(right)
            else:
                if node.condition == _AND:
                    found = 1
                    result = [ ]
                    for left in leftlist:
                        for right in rightlist:
                            newNode = Node(left.name + "_AND_" + right.name)
                            newNode.left = left
                            newNode.right = right
                            result.append(newNode)                      
            if (found != 1):
                print "unknown condition"
                raise Exception("unknown condition")
        return result

    #EXAMPLE ((A OR B) AND (C OR D)):

    node1 = Node("A")
    node2 = Node("B")
    node3 = Node("C")
    node4 = Node("D")

    node12 = Node("A_or_B")
    node12.condition = _OR;
    node12.left = node1
    node12.right = node2

    node34 = Node("C_or_D")
    node34.condition = _OR;
    node34.left = node3
    node34.right = node4

    root = Node("root")
    root.condition = _AND;
    root.left = node12
    root.right = node34

    aList = traverse(root)

    showList(aList)
Mike75
  • 504
  • 3
  • 18