I have an input file with about ~5000 lines and 1 to 9 nodes per line.
Many edges are not unique and I would like to only show the unique ones.
A more simple example.
graph {
a -- b
a -- b
a -- b
}
Yields
Is there a way to make the above graph yield something like
I know I could change the sample input to
graph {
a -- b
}
But it would not be easy to do that for my real input.
There actually is a way: Use the strict keyword:
strict graph G {
a -- b [label="First"];
a -- b [label="Second"];
a -- b [label="Third"];
}
Result:
Without strict, all three edges would be shown. Note that it only takes the first edge's attributes, contrary to what the documentation suggests.
Try strict:
strict graph {
a -- b
a -- b
a -- b
}
This yields
and should work for any size of graph.
In case you want to get a clean file, which doesn't contain any of the duplicate edges, you can use the graph processing tool gvpr.
Here is a snippet, which does just that:
BEG_G { graph_t g = graph($G.name,"U") }
E {
node_t h = clone(g,$.head);
node_t t = clone(g,$.tail);
if(isEdge(t,h,"")==NULL){
edge_t e = clone(g,$);
}
}
END_G { $O = g; }
save this as something like gvpr_rm_dupl_edges and run $ gvpr -f gvpr_rm_dupl_edges input.dot -o output.dot. gvpr comes preinstalled with graphviz.
In case of directed graphs, change the "U" in the beginning of the code snippet to "D"
I wrote this snippet for a simple graph, without sub-graphs. It might not work on something more sophisticated.
I wrote code that executes a function it receives from the (future) client, in a loop with some parameters. will call it func(name it).
Inside the function the client usually generate expression in the same variables(by GetUncertainty - each variable must be cleared before use). To do so , the simple idea is to use Block. Later , a code is executed that handles di and i outside the function.So, di and i must be globals(there could be more, it is flexible).
BTW, I know it is not efficient, but efficiency is not an issue.
func[v_, a_, r_] :=
(V = v; A = a; R = r;
Block[{V, A, R},i = V A + A 10 + R 100; di = GetUncertainty[i, {V, A, R}];] ;
Print[di])
The problem is that the client must reset the vars by hand. That means that the function parameters can't be V_,A_,R_ , otherwise The vars in the block will be replace by the values. I didn't manage to overcome this in any other way.
Another question in a similar issue. if I have
vars = {V,A,R,DR} , then
Block[vars , ..code.. ] , throws error that it is not a list.whereas Block[ {V,A,R,DR},..code..] works. How to overcome this?
Thanks.
its hard to unravel what you are trying to do, but the best approach may be to simply never assign values to symbols that need to be used as pure symbols in some context. Then you don't even need the Block[].
func[v_, a_, r_] := (
i = V A + A 10 + R 100;
di = GetUncertainty[i, {V, A, R}];
Print[di /. {V->v,A->a,R->r])
starting your own symbol names with Caps is frowned upon by the way as you risk conflict with built in symbols.
Note also there is a dedicated site mathematica.stackexchange.com
If I understand your application what you need are Formal Symbols. These are a set of Symbols with the Attribute Protected so that they cannot accidentally be assigned a value. They may be entered with e.g. Esc$AEsc for Formal Capital A. You can then use ReplaceAll (short form /.) as george showed to substitute your desired values.
Your code would be something like this:
func[v_, a_, r_] :=
Module[{i, di},
i = \[FormalCapitalV] \[FormalCapitalA] + \[FormalCapitalA] 10 + \[FormalCapitalR] 100;
di = GetUncertainty[i, {\[FormalCapitalV], \[FormalCapitalA], \[FormalCapitalR]}];
di /. {\[FormalCapitalV] -> v, \[FormalCapitalA] -> a, \[FormalCapitalR] -> r}
]
That looks horrible here but in a Notebook it looks like this:
I included Module to show how you should properly localize utility Symbols such as i and di but this particuarly simple function could also be written without them:
Your second question regarding "vars = {V,A,R,DR} then Block[vars , ..code.. ]" is answered here: How to set Block local variables by code?
Dedicated StackExchange site:
I am trying to understand if its possible in any reasonable way to establish a set of non-repeating paths through a given process diagram.
here are some basic facts about the process diagrams i have:
they have one or more start points
they have one or more end points
all start points have one connector leading from them
all steps have at least one or more inbound connectors and one or more outbound
connectors
if there is more than one of the following each must be
named:
Start terminators
End Terminators
Connections leading from a step
I have access to all of the data I can imagine being required (finding all start points, getting all connections, names of connections etc).
I basically want to find as many unique paths through the process from start point to end point where you don't go round in a circle repeatedly. so you can go through the same step several times but you cannot repeat a complete circuit more than once in any given route through.
This seems like the type of thing people would have written papers about and have proofs for why it can or cannot be done, I just dont know the magic words I need to google that ;-) Sudo code or similar would be ideal (and amazing) but I am happy to do my own reading if someone can point me in the right direction.
ANY SEARCH TERMS SUGGESTIONS VERY WELCOME AND GREATLY APPRECIATED
Note I would be interested solutions that suggest lots of extra "silly" possibilities that have to be reviewed by a human afterwards - it would still be interesting to see what it generated.
An bit of an example to clarify things:
G<--2-E<--1-F-2--|
| | ^ |
| 1 | |
| | 2 |
\/ \/ | \/
start--->A--->B---->C-1->D---end
some routes through:
start,A,B,C:1,D,end
start,A,B,C:2,F:1,E:1,B,C:1,D,end
start,A,B,C:2,F:1,E:2,G,A,B,C:1,D,end
start,A,B,C:2,F:2,D,end
nice but what about a more interesting one:
start,A,B,C:2,F:1,E:2,G,A,B,C:2,F:1,B,C:2,F:2,D,end
I hit C three times and each time I choose option two and there is no repeating.
Extra points: I was thinking that I can mark some of the nodes with multiple outbound connectors as being consistent within any given execution of a process.. e.g. if there is a "write code" process that has a decision point "language" with two outbound connectors "c#" and "java" I could say that within any given execution of this process it will always be either c# or java - that will never change during the execution of the process. as opposed to something that may change like "are there bugs?" which on first pass through might have a yes, then on the second pass through (after some fix bugs steps ;-) might have the outcome no.
Do you know any terms or techniques relating to this type of extra analysis / processing / definition?
EDIT: I added a example solution implemented in JS as an ansewer based on #Ishtar's answer.
How about a depth first search? This would walk through all the possible paths. The only difficult part is ignoring paths that would lead to the same cycle again. If you're at a node, you check if you been there before (a cycle), and make sure the same sequence isn't in the path already.
For example
start,A,B,C:2,F:1,E:1,B,C:2,F:1,E:1,B
From here, we can only go to C. Looking back(the last 4 nodes), we find the cycle C:2,F:1,E:1,B. The cycle exists already, so we can't go to node c. Since we can't go anywhere else, this branch doesn't give a correct path.
Pseudocode:
allpaths(path,node)
cycle = path.substring(path.lastIndex(node)) + node
if path.contains(cycle)
return
path = path + node
if node.isEndNode
print path
return
for child in node.children
allpaths(path, child)
is this relevant? finding all the elementary circuits of a directed graph. even if it's not the algorithm you use, it may help with appropriate definitions and names.
a complete example in a web page of #Ishtars solution, the graph is the one from the question... It seems to work, not extensively tested it. Its a far simpler solution than I was expecting ;-)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
function connection(name, endPoint) {
this.name = name;
this.endPoint = endPoint;
}
function node(name) {
this.name = name;
this.connections = [];
this.addConnection = function (conn) {
this.connections[this.connections.length] = conn;
}
}
function printPath(path) {
document.getElementById('output').innerHTML =
document.getElementById('output').innerHTML
+ path + '<br />';
}
function allPaths(path, node) {
if (node.name == "end") {
printPath(path + ',' + node.name);
return;
}
cycle = path.substring(path.lastIndexOf(node.name)) + ',' + node.name;
if (cycle.length > 1 && path.indexOf(cycle) > 0) {
return;
}
for (var i = 0; i < node.connections.length; i++) {
allPaths(path + ',' + node.name + ":" +
node.connections[i].name
,node.connections[i].endPoint);
}
}
var start = new node("start");
var a = new node("A");
var b = new node("B");
var c = new node("C");
var d = new node("D");
var e = new node("E");
var f = new node("F");
var g = new node("G");
var end = new node("end");
start.addConnection(new connection("1", a));
a.addConnection(new connection("1", b));
b.addConnection(new connection("1", c));
c.addConnection(new connection("1", d));
c.addConnection(new connection("2", f));
d.addConnection(new connection("1", end));
f.addConnection(new connection("1", e));
f.addConnection(new connection("2", d));
e.addConnection(new connection("1", b));
e.addConnection(new connection("2", g));
g.addConnection(new connection("1", a));
</script>
</head>
<body onload="javascript:allPaths('start', a)";>
<div id="output"></div>
</body>
</html>
and here is the output (just in case anyone can spot a mistake ;-):
start,A:1,B:1,C:1,D:1,end
start,A:1,B:1,C:2,F:1,E:1,B:1,C:1,D:1,end
start,A:1,B:1,C:2,F:1,E:1,B:1,C:2,F:1,E:2,G:1,A:1,B:1,C:1,D:1,end
start,A:1,B:1,C:2,F:1,E:1,B:1,C:2,F:1,E:2,G:1,A:1,B:1,C:2,F:2,D:1,end
start,A:1,B:1,C:2,F:1,E:1,B:1,C:2,F:2,D:1,end
start,A:1,B:1,C:2,F:1,E:2,G:1,A:1,B:1,C:1,D:1,end
start,A:1,B:1,C:2,F:1,E:2,G:1,A:1,B:1,C:2,F:1,E:1,B:1,C:1,D:1,end
start,A:1,B:1,C:2,F:1,E:2,G:1,A:1,B:1,C:2,F:1,E:1,B:1,C:2,F:2,D:1,end
start,A:1,B:1,C:2,F:1,E:2,G:1,A:1,B:1,C:2,F:2,D:1,end
start,A:1,B:1,C:2,F:2,D:1,end
Guess I didn't know about jsFiddle when I wrote this, here is a fiddle with the above code in it:
http://jsfiddle.net/6bWMp/1/