Traverse as many edges as possible between two vertices in a directed graph - graph-algorithm

I'd like to find a set of paths from a start node to and an end node so that those paths collectively contain as many edges of the graph as possible.
Or more precisely: Given a directed graph which may contain cycles, and two vertices u and v, I would like to find a finite set P of paths from u to v, such that for any path q between u and v that is not in P, and any edge e in q, there is a path p in P that contains e. The vertices u and v may be the same.
In fact, an almost identical question has been asked: Directed Graph Traversal - All paths, but the very plausible answer has never been accepted or received an upvote, so I was wondering.
That answer involves using a variant of Dijkstra or A* to iterate over all paths between u and v ordered by length.
From Is there a well-studied optimization to find the shortest path traversing every weighted edge through a graph? it seems that my question is also almost identical to the "Chinese Postman Problem", except I don't need to visit all the edges, just as many as I can, and I'm not interested in shortest paths, just any paths, and my edges are not weighed.
I was thinking of doing something like the first answer. Or perhaps condense the graph using Kosaraju, use straight Dijkstra to find all paths between u and v, and expand the "condensed" vertices by finding all cycles in the strongly connected components. But I haven't really got anywhere.
What would be the best plan to follow?

Here is a case where the set of paths that contain as many edges as possible is smaller than the set of all distinct paths.
So if you use an algorithm to find all paths, then you will require an extra step to discard paths that do not add more edges.

Related

Using List.map to create a list of odd numbers

My professor is having us create a series of functions relating to approximating pi and e based on continuing fractions. In order to set this up, he is having us create a function that takes an integer and maps that many odd numbers squared, starting from 1. For instance, here is the desired behavior:
oddSquares 6;;
val it : int list = [1.0; 9.0; 25.0; 49.0; 81.0; 121.0]
I can see that one mapping will likely be used to square all the values in the list, but I can't figure out a way to map the number to a list of numbers. I don't want to ask anybody to write code for me, but methodically, what am I trying to do when I'm assembling the base list?
It feels like the best method is to work backwards, starting from the base number of 6 terms. We then evaluate the 6th odd term (11, or 2x-1 practically), but then require some method of recursion to continue to evaluate smaller values of oddSquares. I also think this is against the spirit of trying to map the number into these values. Can someone give me some guidance as to the first translation from the number into the list form?
F# offers special neat syntax for creating lists of successive numbers:
let oneToSix = [1..6]
This is a special case of something called "list comprehension". They can be more complex than just successive numbers - they can include multiple generators, filters, projections, Cartesian products, etc. In particular, your whole task of generating first N odd numbers can be expressed as one list comprehension. However, since you explicitly asked not to write the code for you, I won't.

Cypher: which assignment operator

I would appreciate some Cypher-specific theory for why there are, effectively, two different assignment operators in the language. I can get things to work, but feel like something is missing...
Let's use Neo4j's movie database with the following query:
match (kr:Person {name:"Keanu Reeves"}), (hw:Person{name:"Hugo Weaving"}), p=shortestPath((kr)-[*]-(hw)) return p
Sure, the query works, but here's the point of my question: 'kr', 'hw' and 'p' are all variables, right? But why is it that the former two are assigned with a colon, but the latter takes an equal sign?
Thanks.
It's important to note that the : used for nodes and relationships really doesn't have anything to do with variable assignment at all, it's instead associated with node labels and relationship types.
A node label and a relationship type always start with a :, even if there isn't a variable present at all. This helps differentiate a node label or relationship type from a variable (a variable will never begin with a :), and the : naturally acts as a divider between the label/type and the variable when both are present. It's also possible to have a variable on a node or label, but omit the type...in that case no : will be present, which again reinforces that it doesn't have anything to do with assignment.
In the context of a map {} (such as a properties map, including when it's inlined within a match on a node or relationship), then the : is used for map key/value pairs, and is common syntax, used in JSON representation.
Actual assignment (such as in SET clauses, and in your example of setting the path variable to a pattern within a match) uses =.
I do not think there is a deep theoretical reason for it. The original idea of Cypher was to provide an ASCII art-style language, where the MATCH part of the query which resembles a graph pattern that you'd draw on a whiteboard.
In many ways, a graph instance is quite similar to a UML Object Diagram (and other common representations), where you would use name : type to denote an object's variable name and type (class) or just use : type for anonymous instances.
Now paths do not really fit into that picture. On a whiteboard, I'd just put the relevant part in a dashed/circled area write p or p= next to it. Definitely not p:.
Note that it is possible to rephrase your query to a more compact form:
match p=shortestPath((kr:Person {name:"Keanu Reeves"})-[*]-(hw:Person {name:"Hugo Weaving"}))
return p
Here, using colons everywhere would look out of place, think: p:shortestPath((kr:Person {name:"Keanu Reeves"})
Remark 1. If you try to use a variable to capture relationships of a variable length pattern, you will get a warning:
Warning. This feature is deprecated and will be removed in future versions.
Binding relationships to a list in a variable length pattern is deprecated. (org.neo4j.graphdb.impl.notification.NotificationDetail$Factory$2#1eb6644d)
MATCH (a)-[rs:REL*]->(b)
^
So you would better use a path and the relationships function to get the same result:
MATCH p=(a)-[:REL*]->(b)
RETURN relationships(p)
Remark 2. I come from an OO background and have been writing Cypher for a few years, so it might just be me getting used the syntax -- it might be odd for newcomers, especially from different fields.
Remark 3. The openCypher project now provides a grammar specification
, which gives you an insight of how a MATCH clause is parsed.

Pre Order, In order, and Post Order Tree Traversals

I am confused about in order, pre-order and post-order traversals, specifically
this one, Pre-Order: ABAB, Post Order: BABA, In Order: AABB.
I understand that the root is the first and last element of Pre and Post, but I fail to understand how to finish constructing the Binary Tree.
Your post is vague, and doesn't make much sense, but I'll explain in, pre, post order and constructing a binary tree for you.
One of the reasons your question doesn't make sense is you haven't established an order to the elements you describe in ordering, ABAB BABA and AABB means absolutely nothing with out a tree to properly show where each element goes (and is each element a letter? why do they duplicate)
Another reason why your question doesn't make sense is that you appear to think that pre, pos and in order have something to do with creating a binary tree, they don't.
Pre ordering, In Ordering, and Post Ordering are all types of Depth First Search algorithms for tree traversal. That is to say they are ways of navigating a tree, not creating one. You may use these algorithms to find elements, or to simply print out all the contents of a tree, this is especially useful to a tree who's nodes are only linked via pointers (as apposed to say, an array based binary heap).
Imagine the following binary tree (the same for all examples)
A
B C
D E F G
Pre order traversal is a type of tree traversal algorithm where you always take the left most path first. When you can't go farther, you take the next most left path, and do the same thing recursively on the next node. In the above example tree, pre order traversal would start at the root, (A) go left (A,B) go left again (D) couldn't go left so then would go right (E) and in the end you would end up with the following traversal sequence: A B D E C F G
In order traversal is similar to pre-order traversal, but instead of displaying at each step, in order traversal goes the deepest left it can go, then displays, and if it can't go deep enough any more, it goes back up, displays (hence 'in' order), and tries the same thing to the right again recursively until its done. In the tree example, we'd actually print D first, go back up to B, and print B, then E, then back up to A, and so on, so the final output would be D B E A F G C. Note Wikipedias example may make more sense as it is more complicated.
In post order, we print from bottom up essentially, we find the deepest node in the left subtree, and print the deepest nodes in there recursively until we're done, go to the right subtree and finally print the root eg: D E B F G C A. Again this example makes more sense with wikipedia, since they have a more complicated tree.
If you want to construct a tree, there are many ways to do so but it depends entirely what kind of ordering structure you want. Do you want to have a binary structure or n-ary structure? Do you care about which element is on top, or do you only want the min/max (like a pairing heap or binary heap priority queue)? Do you have a search condition, such that the roots of each part of a tree must be larger/smaller/other condition relative to the children or their parents? (like a binary search tree)
This post is also good explaining the traversals if this isn't sufficient, it also explains why you need different types of ordering in order to construct a tree from a sequence of nodes with proper connections (if your original intent was to copy a binary tree structure)

XOR, AND Tree in Neo4j Cypher

I have a problem trying to "decypher" a logical tree with Neo4js Cypher.
I have a logical tree of Operation to Leaves. I want to collect valid sets of Leaves.
I am currently trying to collect valid Sets of Leaves on a Valid Configuration Node. So I can later quickly path through that Configuration node.
Example
(1 AND 2) AND (3 AND 4)
Is easy to match (rule)-[AND*]->(leaf) return collect(leaf)
However
(1 XOR 2) AND (3 XOR 4)
Is a problem because whenever I collect 1,2,3,4 in a single variable, I cannot later properly get the cartesian product of the AND Operation. (13,14,23,24) would be valid.
In general I have a tree of variable depth (upto max about 3-4)
Operations are XOR, AND, Not AND, Not XOR
Is there a simple way in Cypher I am missing for navigating such trees?
Is trying to merge Valid Sets in a ValidConfiguration Node a good idea for fast Queries?
Later it should support a query of the form
(:Model)->(:ValidConf)->(:Leaf:Option)->(:Feature)
then return all models that have a certain Feature in a valid configuration.
Or multiple Features at a certain configuration price.
Do I need UDFs or ObjectGraphMapper to get this problem solved?
Are there any UDFs that work with such decision trees which I can use?
Any help would be highly appreciated.
Create Example
CREATE (r:Rule{id:123})-[:COMPOSITION]->
startOp:AndOperation:Operation:Operand)
CREATE (startOp)-[:AND]->(intermediateOp1:OrOperation:Operation:Operand)
CREATE (startOp)-[:AND]->(intermediateOp2:OrOperation:Operation:Operand)
CREATE (intermediateOp1)-[:XOR]->(o1:Option:Operand{id:321})
CREATE (intermediateOp1)-[:XOR]->(o2:Option:Operand{id:564})
CREATE (intermediateOp2)-[:XOR]->(o3:Option:Operand{id:876})
CREATE (intermediateOp2)-[:XOR]->(o4:Option:Operand{id:227})
CREATE (o1)-[:CONSISTS_OF]->(f1:Feature{text:"magicwand"})
....
This tree is symmetric but they usually aren't. I need to make o1 + o4 be valid and o1 + o2 to not be valid. The OR are to be understood as XOR.
I don't think Cypher is going to work for evaluating a boolean binary expression tree. To quote cybersam's answer to a related question:
This is because Cypher has no looping statements powerful enough to
iteratively calculate subresults (in the correct order) for trees of
arbitrary depth.
You're going to have to look for some additional system to do the evaluation.
If you can code Java, you should be able to do this by implementing your own custom procedure to evaluate a boolean expression tree in the correct order.

Trying to get the shortest path (bfs) in directed graph in Erlang

I am looking for a code to find the shortest path a in directed graph.
Is there somewhere I can find one?
(can be based of BFS)
Use Erlang Digraph Library and function get_short_path/3, which takes a directed graph and the start/end vertices couple.

Resources