1 /**
2 Copyright: Copyright (c) 2018, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 Port of the rust implementation in graspan1.
7 The dataset is downloaded from [graspan dataset](https://drive.google.com/drive/folders/0B8bQanV_QfNkbDJsOWc2WWk4SkE).
8 
9 The dataformat is: [EDGE SOURCE] [EDGE DESTINATION] [EDGE VALUE].
10 An edge-list format.
11 
12 To run this test the file http_df has to be put in the build directory.
13 Then execute the test with: dub test -- -s -d "shall calculate the dataflow from http_df"
14 */
15 module datacat_test.graspan1;
16 
17 import std.algorithm : filter, map, splitter;
18 import std.array : appender, empty, array;
19 import std.conv : to;
20 import std.datetime.stopwatch : StopWatch;
21 import std.file : thisExePath;
22 import std.path : buildPath, baseName;
23 import std.range : takeExactly;
24 import std.stdio : writeln, writefln, File;
25 import std.typecons : Yes;
26 import std.ascii : isWhite;
27 
28 import datacat;
29 
30 int main(string[] args) {
31     if (args.length < 2) {
32         writefln("Usage: %s DATA_FILE", thisExePath.baseName);
33         return 1;
34     }
35     writeln("Shall calculate the dataflow from the provided file");
36 
37     auto timer = StopWatch(Yes.autoStart);
38     const datafile = args[1];
39 
40     // Make space for input data.
41     auto nodes = appender!(KVTuple!(uint, uint)[])();
42     auto edges = appender!(KVTuple!(uint, uint)[])();
43 
44     // Read input data from a handy file.
45     foreach (line; File(buildPath(datafile)).byLine.filter!(a => !a.empty && a[0] != '#')) {
46         auto elts = line.splitter.filter!"!a.empty".takeExactly(3);
47         auto src = elts.myPopFront.to!uint;
48         auto dst = elts.myPopFront.to!uint;
49         auto ty = elts.myPopFront;
50         switch (ty) {
51         case "n":
52             nodes.put(kvTuple(dst, src));
53             break;
54         case "e":
55             edges.put(kvTuple(src, dst));
56             break;
57         default:
58             assert(0, "should not happen. Unknown type: " ~ ty);
59         }
60     }
61 
62     writefln("%s: Data loaded", timer.peek);
63     timer.reset;
64 
65     // Create a new iteration context, ...
66     Iteration iter;
67 
68     // .. some variables, ..
69     auto variable1 = iter.variable!(uint, uint)("nodes");
70     auto variable2 = iter.variable!(uint, uint)("edges");
71 
72     // .. load them with some initial values, ..
73     variable1.insert(nodes.data);
74     variable2.insert(edges.data);
75 
76     // .. and then start iterating rules!
77     while (iter.changed) {
78         // N(a,c) <-  N(a,b), E(b,c)
79         static auto helper(T0, T1, T2)(T0 b, T1 a, T2 c) {
80             return kvTuple(c, a);
81         }
82 
83         variable1.fromJoin!helper(variable1, variable2);
84     }
85 
86     auto reachable = variable1.complete;
87 
88     timer.stop;
89     writefln("%s: Computation complete (nodes_final: %s", timer.peek, reachable.length);
90 
91     return 0;
92 }
93 
94 auto myPopFront(RT)(ref RT r) {
95     auto v = r.front;
96     r.popFront;
97     return v;
98 }