How can textual "logic" be represented in a data structure - data-structures

Given the string
{A} AND ({B} OR {C} OR ({D} AND {E}))
How can this be represented in a data structure?

The "natural" representation is a tree. Each non-leaf node is an operator and its children are the operands. In your example, you'd have a root node labeled "AND" with two children. The left child is {A} and the right one is labeled "OR". This "OR" has three children, one labeled {B}, one labeled {C} and one labeled "AND". This last "AND" has two children, {D} and {E}.
If you wish "OR" to be a binary operator (rather than ternary or n-ary), you can have the "OR" with two children: one is {B} and the other is another "OR" whose children are {C} and the "AND".

It's a circuit. If I were to wire up that equation on a breadboard with some transistors and LED's I'd draw the following schematic:
A
/
output-----[AND] B
\ /
[OR]--C
\ D
\ /
[AND]
\
E
Coincidentally, this can even be structured as a simple map of arrays of maps. Let's use JSON as an example format for this data:
{AND:[
A,
{OR:[
B,
C,
{AND:[
D,
E
]}
]}
]}
This is basically a graph. In the simplest case like in this example it is a tree but be warned: that is only an artefact of this example. In general it is a graph because you can have cycles in the structure (one element appearing in more than one place).
Here's an example of an equation that is not a neat tree:
{A} OR ({B} AND (NOT {A}))
This translates to:
A-------------.
/ |
output----[OR] [NOT]<--'
\ /
[AND]
\
B

Related

Algorithm for enumerating all permutations of algebraic expressions

If I have a list of variables, such as {A, B, C} and a list of operators, such as {AND, OR}, how can I efficiently enumerate all permutations of valid expressions?
Given the above, I would want to see as output (assuming evaluation from left-to-right with no operator precedence):
A AND B AND C
A OR B OR C
A AND B OR C
A AND C OR B
B AND C OR A
A OR B AND C
A OR C AND B
B OR C AND A
I believe that is an exhaustive enumeration of all combinations of inputs. I don't want to be redundant, so for example, I wouldn't add "C OR B AND A" because that is the same as "B OR C AND A".
Any ideas of how I can come up with an algorithm to do this? I really have no idea where to even start.
Recursion is a simple option to go:
void AllPossibilities(variables, operators, index, currentExpression){
if(index == variables.size) {
print(currentExpression);
return;
}
foreach(v in variables){
foreach(op in operators){
AllPossibilities(variables, operators, index + 1, v + op);
}
}
}
This is not an easy problem. First, you need a notion of grouping, because
(A AND B) OR C != A AND (B OR C)
Second, you need to generate all expressions. This will mean iterating through every permutation of terms, and grouping of terms in the permutation.
Third, you have to actually parse every expression, bringing the parsed expressions into a canonical form (say, CNF. https://en.wikipedia.org/wiki/Binary_expression_tree#Construction_of_an_expression_tree)
Finally, you have to actually check equivalence of the expressions seen so far. This is checking equivalence of the AST formed by parsing.
It will look loosely like this.
INPUT: terms
0. unique_expressions = empty_set
1. for p_t in permutations of terms:
2. for p_o in permutations of operations:
3. e = merge_into_expression(p_t, p_o)
4. parsed_e = parse(e)
5. already_seen = False
6. for unique_e in unique_expressions:
7. if equivalent(parsed_e, unique_e)
8. already_seen = True
9. break
10. if not already_seen:
11. unique_expressions.add(parsed_e)
For more info, check out this post. How to check if two boolean expressions are equivalent

Number Of Ways To Traverse a Binary Tree

Consider a binary tree of n nodes. For the sake of example consider the following tree:
1
/ \
2 3
/ \ / \
4 5 6 7
\
8
How many different ways can I fully traverse the tree starting from the root (top) node and only moving to un-visited nodes that are directly connected to ones that have already been visited (i.e. I can go from 1 to 2 to 4 but then to 3)?
You might have more luck asking on the Math Stack exchange.
You are asking for the number of linear extensions of the binary tree considered as a poset. Although I can see no general formula, one can solve this recursively as follows:
Find the number of ways of traversing the left and right subtrees (the empty tree is trivially traversed in 1 way). Call these T_L and T_R. Let #L and #R be the cardinality (size) of the left tree and right tree respectively. Then the number of ways of traversing the whole tree is
T_L * T_R * (#L + #R choose #L)
because we can traverse the left tree in T_L ways, the right tree in T_R ways (independent of how we traverse the right tree), and we can interleave the left and right trees in (#L + #R choose #L) ways.
In your example there are two ways of traversing the left tree, and three ways of traversing the right tree and (7 choose 3) is 35, so there are 2*3*35 = 210 ways of traversing the tree.
Programmatic verification of #deinst's answer, with Prolog:
traverse([], []) :- !.
traverse(F, [N|P]) :-
% select a frontier node from F
select(t(N,C), F, Rem),
% append all new accessible children to the frontier
append(C, Rem, NewF),
% traverse the remaining set
traverse(NewF, P).
tree(X) :-
X = t(1,[t(2,[t(4,[]), t(5,[])]),t(3,[t(6,[]), t(7,[t(8,[])])])]).
do :-
tree(X),
findall(P, (traverse([X], P), write_ln(P)), Ps),
length(Ps, L),
write_ln(L).
This does indeed return 210 possibilities, as suggested for your example tree.
?- do.
[1,2,4,5,3,6,7,8]
[1,2,4,5,3,7,8,6]
[1,2,4,5,3,7,6,8]
[1,2,4,3,6,7,8,5]
[1,2,4,3,6,7,5,8]
[1,2,4,3,6,5,7,8]
[1,2,4,3,7,8,6,5]
[1,2,4,3,7,8,5,6]
[1,2,4,3,7,6,8,5]
...
[1,3,2,7,6,4,8,5]
[1,3,2,7,6,4,5,8]
[1,3,2,7,6,5,8,4]
[1,3,2,7,6,5,4,8]
210
true.

Getting all nodes that have atleast 2 nodes connected to them

Having some issues with a Prolog question:
The following clauses represent a directed graph, where nodes are
atoms, and edges are denoted by the connected predicate. Given that
the following clauses are in the database, answer the two questions
below.
connected(a,b).
connected(b,d).
connected(b,e).
connected(b,f).
connected(a,c).
connected(c,f).
connected(c,g).
connected(h,c).
path(X,Y) :- connected(X,Y).
path(X,Z) :- connected(X,Y), path(Y,Z).
Show the Prolog query that returns all nodes having two or more
different incoming edges (i.e., at least two different nodes are
connected to it). Also, show the result of entering the query (asking
for every solution). Your query may return the same node multiple
times, and may printout the values of other variables in the query.
The variable denoting the node in question should be called DNode.
So far I have:
path(DNode,__) , path(__,DNode).
But that only give me b and c
I think the letters with more than one nodes are a, b, c, f.
I tried this to get a, b and c:
path(__,DNode),path(DNode,__) ; path(DNode,__) , path(DNode,__).
But I got a, b, c and h.
I am assuming I'll have to like this to get all the letters I want:
path(__,DNode),path(DNode,__) ; path(DNode,__) , path(DNode,__) ; path(__,DNode) , path(__,DNode).
It gives me a, b, c, e, f, g and h though.
Any advice about how to get the 4 letters I want would be appreciated.
if you display your graph, perhaps with Graphviz
?- writeln('digraph G {'), forall(connected(A,B), writeln(A->B)), writeln('}').
you can see that only [c,f] have 2 incoming edges, and that you don't need path/2. It's sufficient a join on the second argument of connected/2, with a test that the first arguments are different (operator (\=)/2).

Problems with a simple dependency algorithm

In my webapp, we have many fields that sum up other fields, and those fields sum up more fields. I know that this is a directed acyclic graph.
When the page loads, I calculate values for all of the fields. What I'm really trying to do is to convert my DAG into a one-dimensional list which would contain an efficient order to calculate the fields in.
For example:
A = B + D, D = B + C, B = C + E
Efficient calculation order: E -> C -> B -> D -> A
Right now my algorithm just does simple inserts into a List iteratively, but I've run into some situations where that starts to break. I'm thinking what would be needed instead would be to work out all the dependencies into a tree structure, and from there convert that into the one dimensional form? Is there a simple algorithm for converting such a tree into an efficient ordering?
Are you looking for topological sort? This imposes an ordering (a sequence or list) on a DAG. It's used by, for example, spreadsheets, to figure out dependencies between cells for calculations.
What you want is a depth-first search.
function ExamineField(Field F)
{
if (F.already_in_list)
return
foreach C child of F
{
call ExamineField(C)
}
AddToList(F)
}
Then just call ExamineField() on each field in turn, and the list will be populated in an optimal ordering according to your spec.
Note that if the fields are cyclic (that is, you have something like A = B + C, B = A + D) then the algorithm must be modified so that it doesn't go into an endless loop.
For your example, the calls would go:
ExamineField(A)
ExamineField(B)
ExamineField(C)
AddToList(C)
ExamineField(E)
AddToList(E)
AddToList(B)
ExamineField(D)
ExamineField(B)
(already in list, nothing happens)
ExamineField(C)
(already in list, nothing happens)
AddToList(D)
AddToList(A)
ExamineField(B)
(already in list, nothing happens)
ExamineField(C)
(already in list, nothing happens)
ExamineField(D)
(already in list, nothing happens)
ExamineField(E)
(already in list, nothing happens)
And the list would end up C, E, B, D, A.

Seeking algorithm to invert (reverse? mirror? turn inside-out) a DAG

I'm looking for an algorithm to "invert" (reverse? turn inside-out?) a
DAG:
A* # I can't ascii-art the arrows, so just
/ \ # pretend the slashes are all pointing
B C # "down" (south-east or south-west)
/ / \ # e.g.
G E D # A -> (B -> G, C -> (E -> F, D -> F))
\ /
F
The representation I'm using is immutable truly a DAG (there are no
"parent" pointers). I'd like to traverse the graph in some fashion
while building a "mirror image" graph with equivalent nodes, but with
the direction of relations between nodes inverted.
F*
/ \
G* E D # F -> (E -> C -> A, D -> C -> A), G -> B -> A
\ \ / #
B C # Again, arrows point "down"
\ / #
A #
So the input is a set of "roots" (here, {A}). The output should be a
set of "roots" in the result graph: {G, F}. (By root I mean a node
with no incoming references. A leaf is a node with no outgoing
references.)
The roots of the input become the leaves of the output and visa
versa. The transformation should be an inverse of itself.
(For the curious, I'd like to add a feature to a library I'm using to
represent XML for structural querying by which I can map each node in
the first tree to its "mirror image" in the second tree (and back
again) to provide more navigational flexibility for my query rules.)
Traverse the graph building a set of reversed edges and a list of leaf nodes.
Perform a topological sort of the reversed edges using the leaf (which are now root) nodes to start with.
Construct the reversed graph based on the reversed edges starting from the end of the sorted list. As the nodes are constructed in reverse topological order, you are guaranteed to have constructed the children of a given node before constructing the node, so creating an immutable representation is possible.
This is either O(N) if you use structures for your intermediate representation which track all links in both directions associated with a node, or O(NlnN) if you use sorting to find all the links of a node. For small graphs, or languages which don't suffer from stack overflows, you can just construct the graph lazily rather than explicitly performing the topological sort. So it depends a little what you're implementing it all in how different this would be.
A -> (B -> G, C -> (E -> F, D -> F))
original roots: [ A ]
original links: [ AB, BG, AC, CE, EF, CD, DF ]
reversed links: [ BA, GB, CA, EC, FE, DC, FD ]
reversed roots: [ G, F ]
reversed links: [ BA, CA, DC, EC, FE, FD, GB ] (in order of source)
topologically sorted: [ G, B, F, E, D, C, A ]
construction order : A, C->A, D->C, E->C, F->(D,E), B->A, G->B
Just do a depth-first search marking where you have already been, and each time you traverse an arrow you add the reverse to your result DAG. Add the leaves as roots.
My intuitive suggestion would be to perform a Depth First traversal of your graph, and construct your mirrored graph simultaneously.
When traversing each node, create a new node in the mirrored graph, and create an edge between it and its predecessor in the new graph.
If at any point you reach a node which has no children, mark it as a root.
I solved this with a simple graph traversal. Keep in mind topological sorting will only be useful for directed acyclic graphs.
I used an adjacency list, but you can do a similar thing with an adjacency matrix.
In Python it looks like this:
# Basic Graph Structure
g = {}
g[vertex] = [v1, v2, v3] # Each vertex contains a lists of its edges
To find all the edges for v, you then traverse the list g[v] and that will give you all (v, u) edges.
To build the reversed graph make a new dictionary and build it something like this:
reversed = {}
for v in g:
for e in g[v]:
if e not in reversed:
reversed[e] = []
reversed[e].append(v)
This is very memory intensive for large graphs (doubling your memory usage), but it is a very easy way to work with them and quite quick. There may be more clever solutions out there involving building a generator and using a dfs algorithm of some sort, but I have not put a lot of thought into it.
Depth-first search might be able to generate what you're after: Note your path through the tree and each time you traverse add the reverse to the resulting DAG (leaves are roots).

Resources