diff --git a/run.sh b/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..35ab6c2bda16374ddf95079a87083576d36f94c0 --- /dev/null +++ b/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cp $1 build/graph.graph +python3 src/part1/unified.py +java -classpath src/part2/GraphCompress/out/production/GraphCompress Main +python3 src/part3/encode.py +# python3 src/part4/draw.py diff --git a/src/part1/slashburn.py b/src/part1/slashburn.py new file mode 100644 index 0000000000000000000000000000000000000000..bc05b2f0b109ec48106f58351d24ff260e371d95 --- /dev/null +++ b/src/part1/slashburn.py @@ -0,0 +1,60 @@ +import networkx as nx +from math import sqrt + +def add(l,x, key=lambda x:x): + m = min([key(x) for x in l]) + if key(x) <= m: + return + for i in range(len(l)): + if key(l[i]) == m: + l[i] = x + return + + +def k_max(l,k, key=lambda x:x): + if len(l) <= k: + return l + ans = [] + for x in l: + if len(ans) < k: + ans.append(x) + else: + add(ans,x,key) + return ans + +def k_struct(H, k, adaptative=False): + G = H.copy() + while G.order() > k: + while G and nx.is_connected(G): + sorted_degree = sorted(G.degree, key = lambda x: x[1], reverse=True) + k_center = sorted_degree[:k] + # k_center = k_max(G.degree, k, key = lambda x: x[1]) + center = [] + for v, d in k_center: + center.append(v) + G.remove_node(v) + print(">>> removing center (%d nodes), %d remaining" % (k, G.order())) + yield set(center) + if G: + sorted_comp = sorted(list(nx.connected_components(G)), key = len) + bcc = sorted_comp[-1] + spokes = set() + for component in sorted_comp[:-1]: + spokes = spokes.union(component) + yield spokes + + # G.remove_nodes_from([n for n in G if n not in set(bcc)]) + to_remove = [n for n in G if n in spokes] + G.remove_nodes_from(to_remove) + print(">>> removing spokes (%d nodes), %d remaining" % (len(to_remove), G.order())) + if adaptative: + k = max(10,G.order()//1000) + +def k_slashburn(*args, **kwargs): + last = [] + for s in k_struct(*args, **kwargs): + last.append(s) + return last + +def slashburn(G): + return k_slashburn(G, max(10,G.order()//1000), adaptative=True) diff --git a/src/part1/unified.py b/src/part1/unified.py new file mode 100644 index 0000000000000000000000000000000000000000..9c89ff951cf3f07255c67e0e5b5cb2f39e7752fc --- /dev/null +++ b/src/part1/unified.py @@ -0,0 +1,103 @@ +import sys, os + +# Disable print +sys.stdout = open(os.devnull, 'w') + +import networkx as nx +from cdlib import algorithms, readwrite +from json import loads +from math import sqrt + +import matplotlib.cm as cm +import matplotlib.pyplot as plt +import community as community_louvain +import metis + +from slashburn import k_slashburn, slashburn + +# Restore print +sys.stdout = sys.__stdout__ + +PATH = "build/" +GRAPH = PATH + "graph.graph" +OUT = PATH + "struct.txt" + +def myprint(f,x): + print(x) + f.write(x + '\n') + +def list_list_to_string(ll, spec="fc"): + return '\n'.join(map(lambda l: spec + " " + ' '.join(map(str, l)), ll)) + +def map_list_list(f, ll): + return [list(map(f,l)) for l in ll] + +def prune_commu(ll, k): + return [l for l in ll if len(l) >= k] + +def partition_to_commu(p): + n = 1+max(p) + commu = [[] for _ in range(n)] + for i, u in enumerate(p): + commu[u].append(i) + return commu + +######################## + +def decorate_cdlib(algo): + def f(G): + return loads(algo(G).to_json())["communities"] + return f + +@decorate_cdlib +def big_clam(G): + return algorithms.big_clam(G) + +@decorate_cdlib +def louvain(G): + return algorithms.louvain(G) + +@decorate_cdlib +def kcut(G): + return algorithms.kcut(G) + +def sqrt_metis(G): + k = int(sqrt(G.order()/2)) + _, parts = metis.part_graph(G, k) + return partition_to_commu(parts) + +def trivial(G): + return [list(range(G.order()))] + +def unified(): + with open(GRAPH, 'r') as f: + lines = f.readlines() + G = nx.parse_edgelist(lines, nodetype=int, delimiter=",", data=False) + G = nx.convert_node_labels_to_integers(G, label_attribute="old") + threshold = 1 + ''' + Each function in flist takes a Graph G created with networkx such that V = [0..n-1] for some n, + and returns a list of communities. A community is a list of numbers in [0..n-1] + ''' + flist = [ + (slashburn, [], "sl"), + (big_clam, [], "bc"), + (louvain, [], "lv"), + (sqrt_metis, [], "mt"), + ] + print("Part 1") + i = 0 + with open(OUT, 'w') as f: + for algo,args,spec in flist: + commu = algo(G, *args) + pruned = prune_commu(commu, threshold) + reverse = map_list_list(lambda x: G.nodes[x]["old"], pruned) + formated = list_list_to_string(reverse, spec=spec) + f.write(formated + '\n') + i += 1 + print("> Algorithm %d/%d done" % (i, len(flist))) + +def main(): + unified() + +main() diff --git a/src/part2/GraphCompress/.idea/.gitignore b/src/part2/GraphCompress/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..26d33521af10bcc7fd8cea344038eaaeb78d0ef5 --- /dev/null +++ b/src/part2/GraphCompress/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/src/part2/GraphCompress/.idea/.name b/src/part2/GraphCompress/.idea/.name new file mode 100644 index 0000000000000000000000000000000000000000..0c1a9a637b731cbe38c4402e3509ddb2adeab829 --- /dev/null +++ b/src/part2/GraphCompress/.idea/.name @@ -0,0 +1 @@ +GraphCompress \ No newline at end of file diff --git a/src/part2/GraphCompress/.idea/misc.xml b/src/part2/GraphCompress/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..e0844bc7be0a8ca77dcee74dfc4059ee4a9d4a1d --- /dev/null +++ b/src/part2/GraphCompress/.idea/misc.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK"> + <output url="file://$PROJECT_DIR$/out" /> + </component> +</project> \ No newline at end of file diff --git a/src/part2/GraphCompress/.idea/modules.xml b/src/part2/GraphCompress/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..6596e23472d0cb37680807ac92557c4aaf26855b --- /dev/null +++ b/src/part2/GraphCompress/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/GraphCompress.iml" filepath="$PROJECT_DIR$/GraphCompress.iml" /> + </modules> + </component> +</project> diff --git a/src/part2/GraphCompress/.idea/uiDesigner.xml b/src/part2/GraphCompress/.idea/uiDesigner.xml new file mode 100644 index 0000000000000000000000000000000000000000..2b63946d5b31084bbb7dda418ceb3d75eb686373 --- /dev/null +++ b/src/part2/GraphCompress/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="Palette2"> + <group name="Swing"> + <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" /> + </item> + <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true"> + <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" /> + <initial-values> + <property name="text" value="Button" /> + </initial-values> + </item> + <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="RadioButton" /> + </initial-values> + </item> + <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="CheckBox" /> + </initial-values> + </item> + <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="Label" /> + </initial-values> + </item> + <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1"> + <preferred-size width="-1" height="20" /> + </default-constraints> + </item> + <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" /> + </item> + </group> + </component> +</project> \ No newline at end of file diff --git a/src/part2/GraphCompress/.idea/vcs.xml b/src/part2/GraphCompress/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..f1f0a09377b046f00df0ea33544740f0f8688a4c --- /dev/null +++ b/src/part2/GraphCompress/.idea/vcs.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$/../../../../.." vcs="Git" /> + <mapping directory="$PROJECT_DIR$/../../../../../" vcs="Git" /> + <mapping directory="$PROJECT_DIR$/../../.." vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/src/part2/GraphCompress/GraphCompress.iml b/src/part2/GraphCompress/GraphCompress.iml new file mode 100644 index 0000000000000000000000000000000000000000..0181b11c83c3476dfca7f9230ed6ce514c93123d --- /dev/null +++ b/src/part2/GraphCompress/GraphCompress.iml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module-library"> + <library> + <CLASSES> + <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/20.1.0/annotations-20.1.0.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> + </orderEntry> + </component> +</module> \ No newline at end of file diff --git a/src/part2/GraphCompress/out/production/GraphCompress/Block.class b/src/part2/GraphCompress/out/production/GraphCompress/Block.class new file mode 100644 index 0000000000000000000000000000000000000000..0a3c7b1c93607eaa37af8a033e81436a44c2566c Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/Block.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/CompressMath.class b/src/part2/GraphCompress/out/production/GraphCompress/CompressMath.class new file mode 100644 index 0000000000000000000000000000000000000000..3d105f92d4750af7187f08f6bac09f5d28e90515 Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/CompressMath.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/Edge.class b/src/part2/GraphCompress/out/production/GraphCompress/Edge.class new file mode 100644 index 0000000000000000000000000000000000000000..b54c57c9621ba73839a3a6b4bd9561ac191e9dd9 Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/Edge.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/FileIO.class b/src/part2/GraphCompress/out/production/GraphCompress/FileIO.class new file mode 100644 index 0000000000000000000000000000000000000000..1d9c352bded5941d01ee80b1810d290b33df5afc Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/FileIO.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/Graph.class b/src/part2/GraphCompress/out/production/GraphCompress/Graph.class new file mode 100644 index 0000000000000000000000000000000000000000..d8fdfeee77e0c12474b959d8ce6f7dbf01ed5d77 Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/Graph.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/Main.class b/src/part2/GraphCompress/out/production/GraphCompress/Main.class new file mode 100644 index 0000000000000000000000000000000000000000..562dcf712292d0ff6b837971221fe8d9730c9bd0 Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/Main.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/Partition.class b/src/part2/GraphCompress/out/production/GraphCompress/Partition.class new file mode 100644 index 0000000000000000000000000000000000000000..98163a67d7dfad29adb6f5061f5f14044404e7b8 Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/Partition.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/Positional.class b/src/part2/GraphCompress/out/production/GraphCompress/Positional.class new file mode 100644 index 0000000000000000000000000000000000000000..d2551c43bdb924e5d6f84b074f78209eb8d5c2e9 Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/Positional.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/SparseMatrix$1.class b/src/part2/GraphCompress/out/production/GraphCompress/SparseMatrix$1.class new file mode 100644 index 0000000000000000000000000000000000000000..a4e264c6fbed5b8a237bc0ecf1c062f804e0752a Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/SparseMatrix$1.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/SparseMatrix.class b/src/part2/GraphCompress/out/production/GraphCompress/SparseMatrix.class new file mode 100644 index 0000000000000000000000000000000000000000..3cb94e18a860849a539e7198f03971b28051aa1c Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/SparseMatrix.class differ diff --git a/src/part2/GraphCompress/out/production/GraphCompress/Structure.class b/src/part2/GraphCompress/out/production/GraphCompress/Structure.class new file mode 100644 index 0000000000000000000000000000000000000000..721a8aadf2c419762861144c6bb27637ac6adb84 Binary files /dev/null and b/src/part2/GraphCompress/out/production/GraphCompress/Structure.class differ diff --git a/src/part2/GraphCompress/src/Block.java b/src/part2/GraphCompress/src/Block.java new file mode 100644 index 0000000000000000000000000000000000000000..bffd4d4612f8f16cc047bf202337be9099305a25 --- /dev/null +++ b/src/part2/GraphCompress/src/Block.java @@ -0,0 +1,88 @@ +import java.util.ArrayList; +import java.util.Objects; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +public class Block implements Positional{ + private ArrayList<Edge> edgeList; + private int row; + private int column; + private int rowSize; + private int columnSize; + + private int diskSpace; + + public Block(ArrayList<Edge> edgeList, int row, int column, int rowSize, int columnSize) { + this.edgeList = edgeList; + this.row = max(row, column); + this.column = min(row, column); + this.rowSize = rowSize; + this.columnSize = columnSize; + this.diskSpace = -1 ; + } + + public boolean isDiagonal() { + return (this.row == this.column); + } + + public boolean isEmpty() { + return (this.edgeList.size() == 0); + } + + public void addEdge(Edge edge){ + //if (!this.edgeList.contains((edge))) + this.edgeList.add(edge); + this.diskSpace = -1 ; + } + + public ArrayList<Edge> getEdgeList() { + return edgeList; + } + + public int getRow() { + return row; + } + + public int getColumn() { + return column; + } + + public int getDiskSpace(){ + if (this.diskSpace == -1){ + if (isDiagonal()) + this.diskSpace = CompressMath.arithmeticSub(this.edgeList.size(), (long) this.rowSize * (long) this.columnSize / 2); + else + this.diskSpace = CompressMath.arithmeticSub(this.edgeList.size(), (long) this.rowSize * (long) this.columnSize); + } + return this.diskSpace; + } + + public Block clone(){ + return new Block(new ArrayList<Edge>(edgeList), row, column, rowSize, columnSize); + } + + @Override + public String toString() { + String answer = "row: " + row + ", col: " + column + "; "; + answer += edgeList.size() + "/(" + rowSize + "*" + columnSize + ")"; + /* + for (Edge edge : edgeList) + answer += edge.toString(); + */ + return answer; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Block block = (Block) o; + return row == block.row && column == block.column && rowSize == block.rowSize && columnSize == block.columnSize && edgeList.equals(block.edgeList); + } + + @Override + public int hashCode() { + return Objects.hash(edgeList, row, column, rowSize, columnSize); + } +} diff --git a/src/part2/GraphCompress/src/CompressMath.java b/src/part2/GraphCompress/src/CompressMath.java new file mode 100644 index 0000000000000000000000000000000000000000..8ebd7a8f193efc4893b35580afcf4104d9afcb06 --- /dev/null +++ b/src/part2/GraphCompress/src/CompressMath.java @@ -0,0 +1,60 @@ +import static java.lang.Math.log; +import static java.lang.Math.min; +import static java.lang.Math.ceil; + +public class CompressMath { + private static final double log2 = log(2); + + public static int choose(int n, int k){ + if (0 <= k && k <= n){ + int nToken = 1; + int kToken = 1; + int bound = min(k, n-k); + for (int t=1; t <= bound; t++){ + nToken *= n; + kToken *= t; + n -= 1; + } + return nToken / kToken; + } + return 0; + } + + public static double entropy(double x){ + return -(1-x)*log(1-x)/log2 - x*log(x)/log2; + } + + public static double entropy(int p, long q){ + double x = (double) p / (double) q; + return -(1-x)*log(1-x)/log2 - x*log(x)/log2; + } + + public static double intSize(double n){ + if (n < 1){ + return 1; + } + return ceil(log(n)/log2); + } + + public static int arithmetic(int n,int m){ + // n = nbVertices + // m = nbEdges + double nCast = (double) n; + double mCast = (double) m; + double nSquare = (double) (n*n); + double x = 2 * mCast / nSquare; + int term1 = (int) (ceil(entropy(x) * nSquare / 2)); + int term2 = (int) (intSize(nCast)); + int term3 = (int) (2*intSize(intSize(nCast))); + return term1 + term2 + term3; + } + + public static int arithmeticSub(int ones, long total){ + double oneCast = (double) ones; + int term1 = (int) (ceil(entropy(ones, total) * total)); + int term2 = (int) (intSize(oneCast)); + int term3 = (int) (2*intSize(intSize(oneCast))); + return term1 + term2 + term3; + } + +} diff --git a/src/part2/GraphCompress/src/Edge.java b/src/part2/GraphCompress/src/Edge.java new file mode 100644 index 0000000000000000000000000000000000000000..c9460c5348dad377458b74e7709b1b85a945193b --- /dev/null +++ b/src/part2/GraphCompress/src/Edge.java @@ -0,0 +1,78 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Objects; +import java.util.Scanner; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +public class Edge { + private final int u; + private final int v; + + public Edge(int u, int v) { + this.u = max(u,v); + this.v = min(u,v); + } + + public int getU() { + return u; + } + + public int getV() { + return v; + } + + public static ArrayList<Edge> parseString(String edgeString){ + ArrayList<Edge> edgeList = new ArrayList<Edge>(); + String[] separated = edgeString.split(";"); + for (String edge : separated){ + String[] cut = edge.split(","); + int u = Integer.parseInt(cut[0]); + int v = Integer.parseInt(cut[1]); + edgeList.add(new Edge(u,v)); + } + return edgeList; + } + + public static ArrayList<Edge> readFile(String filename){ + ArrayList<Edge> edgeList = new ArrayList<Edge>(); + try { + File myObj = new File(filename); + Scanner myReader = new Scanner(myObj); + while (myReader.hasNextLine()) { + String data = myReader.nextLine(); + if (!data.isEmpty()) { + String[] cut = data.split(","); + int u = Integer.parseInt(cut[0]); + int v = Integer.parseInt(cut[1]); + edgeList.add(new Edge(u, v)); + } + } + myReader.close(); + } catch (FileNotFoundException e) { + System.out.println("An error occurred."); + e.printStackTrace(); + } + return edgeList; + } + + @Override + public String toString() { + return "(" + u + "," + v + ')'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Edge edge = (Edge) o; + return u == edge.u && v == edge.v; + } + + @Override + public int hashCode() { + return Objects.hash(u, v); + } +} diff --git a/src/part2/GraphCompress/src/FileIO.java b/src/part2/GraphCompress/src/FileIO.java new file mode 100644 index 0000000000000000000000000000000000000000..a71135010c26f2757c6390327894959b16fcb3f1 --- /dev/null +++ b/src/part2/GraphCompress/src/FileIO.java @@ -0,0 +1,22 @@ +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public class FileIO { + public static void write(String data, String pathname) { + File file = new File(pathname); + FileWriter f = null; + try { + f = new FileWriter(file); + f.write(data); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + try { + f.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/src/part2/GraphCompress/src/Graph.java b/src/part2/GraphCompress/src/Graph.java new file mode 100644 index 0000000000000000000000000000000000000000..16442b06d12321c0cfb7fdc5e961299b427ddf0c --- /dev/null +++ b/src/part2/GraphCompress/src/Graph.java @@ -0,0 +1,143 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +public class Graph { + private final int nbVertices; + private Partition partition; + private SparseMatrix<Block> blockMatrix; + private Partition copyPartition; + + public Graph(int nbVertices){ + this.nbVertices = nbVertices; + this.partition = null; + this.blockMatrix = null; + this.copyPartition = null; + } + public Graph(ArrayList<Edge> edgeList, int nbVertices){ + Block block = new Block(edgeList, 0, 0, nbVertices, nbVertices); + Structure[] structList = new Structure[0]; + + this.nbVertices = nbVertices; + this.partition = new Partition(nbVertices, structList, this); + this.blockMatrix = new SparseMatrix<Block>(); + this.copyPartition = null; + this.blockMatrix.scale(1); + this.blockMatrix.set(0,0,block); + } + + public static Graph fromFile(String filename){ + ArrayList<Edge> edgeList = Edge.readFile(filename); + int n = 0; + for(Edge edge: edgeList){ + n = max(n, max(edge.getU(), edge.getV())); + } + return new Graph(edgeList, n+1); + } + + /* + The graph clones creates a deep copy of the partition and a shallow copy of the blockMatrix. + Hence, methods like addStructure operates on the new partition and on the original blockMatrix. + This is not a problem, as SparseMatrix<E> is given undo operations to undo those method calls. + */ + public Graph clone(){ + Graph graph = new Graph(this.nbVertices); + graph.partition = this.partition.clone(graph); + graph.blockMatrix = this.blockMatrix; + graph.copyPartition = null; + return graph; + } + + public void addStructure(Structure structure){ + this.partition.addStructure(structure); + } + + @Override + public String toString() { + String answer = this.partition.toString() + "\n"; + String matrix = this.blockMatrix.toString(); + return answer + matrix; + } + + private void deleteBlock(int row, int column){ + this.blockMatrix.delete(row, column); + } + + private void addEdge(Edge edge){ + int u = edge.getU(); + int v = edge.getV(); + int row = this.partition.getVertexAssignment(u); + int column = this.partition.getVertexAssignment(v); + if(this.blockMatrix.hasValue(row, column)){ + this.blockMatrix.get(row, column).addEdge(edge); + } else { + ArrayList<Edge> edgeList = new ArrayList<Edge>(); + edgeList.add(edge); + Block block = new Block(edgeList, row, column, partition.getPartSize(u), partition.getPartSize(v)); + this.blockMatrix.set(row, column, block); + } + } + + public void split(int oldRowIndex, int targetSize) { + int n = this.blockMatrix.getSize(); + int columnIndex; + this.blockMatrix.scale(targetSize); + for (columnIndex = 0; columnIndex < n; columnIndex++) { + if (blockMatrix.hasValue(oldRowIndex, columnIndex)) { + Block block = blockMatrix.get(oldRowIndex, columnIndex); + this.deleteBlock(oldRowIndex, columnIndex); + for (Edge edge : block.getEdgeList()) { + this.addEdge(edge); + } + } + } + } + + public int diskSpace(){ + int answer = 0; + int nbBlock = 0; + for (Block block : this.blockMatrix) { + answer += block.getDiskSpace(); + nbBlock++; + } + answer += CompressMath.arithmetic(this.blockMatrix.getSize(), nbBlock); + return answer; + } + + public void undoInit(){ + this.blockMatrix.undoInit(); + this.copyPartition = this.partition.clone(this); + } + + public void undoAction(){ + this.blockMatrix.undoAction(); + this.partition = this.copyPartition; + this.copyPartition = null; + } + + public boolean check(ArrayList<Edge> edgeList){ + int i = 0; + int x, y; + for(Block block: this.blockMatrix) + for(Edge edge: block.getEdgeList()) { + i++; + x = this.partition.getVertexAssignment(edge.getU()); + y = this.partition.getVertexAssignment(edge.getV()); + if (block.getRow() != max(x,y)) {return false;} + if (block.getColumn() != min(x,y)) {return false;} + if(!edgeList.contains(edge)) {return false;} + } + return (i == edgeList.size()); + } + + public Partition getPartition() { + return partition; + } + + public SparseMatrix<Block> getBlockMatrix() { + return blockMatrix; + } +} diff --git a/src/part2/GraphCompress/src/Main.java b/src/part2/GraphCompress/src/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..5fff43decefda6edc08a0b55273c566072fc7703 --- /dev/null +++ b/src/part2/GraphCompress/src/Main.java @@ -0,0 +1,58 @@ +import java.io.File; +import java.sql.SQLOutput; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; + +public class Main { + public static void greedy(){ + String path; + path = "build/"; + String graphFilename = path + "graph.graph"; + String structFilename = path + "struct.txt"; + String partFilename = path + "partition.txt"; + Graph graph = Graph.fromFile(graphFilename); + ArrayList<Structure> structList = Structure.listFromFile(structFilename); + int i, n; + n = structList.size(); + Structure struct; + ArrayList<Integer> bestStructList= new ArrayList<Integer>(); + int bestCompression = 10*graph.diskSpace(); + int bestStructure; + int currentDiskSpace; + System.out.println("Part 2"); + System.out.println("> Without structure, estimate size is " + graph.diskSpace() + " bits"); + int j = 0; + while (true) { + bestStructure = -1; + for (i = 0; i < n; i++) { + if (!bestStructList.contains(i)) { + struct = structList.get(i); + graph.undoInit(); + graph.addStructure(struct); + currentDiskSpace = graph.diskSpace(); + if (currentDiskSpace < bestCompression) { + bestCompression = currentDiskSpace; + bestStructure = i; + } + graph.undoAction(); + } + } + if(bestStructure >= 0){ + bestStructList.add(bestStructure); + graph.addStructure(structList.get(bestStructure)); + System.out.println("> Selecting structure " + bestStructure + ", estimate size is " + graph.diskSpace() + " bits"); + j++; + } else { + break; + } + } + + FileIO.write(graph.getPartition().toFormattedString(), partFilename); + + } + + public static void main(String[] args) { + greedy(); + } +} \ No newline at end of file diff --git a/src/part2/GraphCompress/src/Partition.java b/src/part2/GraphCompress/src/Partition.java new file mode 100644 index 0000000000000000000000000000000000000000..d24546e492576bf8e0da157a37a65ece213191c1 --- /dev/null +++ b/src/part2/GraphCompress/src/Partition.java @@ -0,0 +1,99 @@ +import java.util.ArrayList; +import java.util.Arrays; + +public class Partition { + private int nbVertices; + private int[] vertexAssignmentList; + private ArrayList<Structure> partList; //assert: partList is a partition of [nbVertices] into Structures + private Graph graph; + + /* + k in partList.get(i).getList() <=> vertexAssignmentList[k] == i + */ + + + public Partition(){ + this.nbVertices = 0; + this.vertexAssignmentList = null; + this.partList = null; + this.graph = null; + } + public Partition(int nbVertices, Structure[] structureList, Graph graph) { + this.graph = graph; + this.nbVertices = nbVertices; + this.partList = new ArrayList<Structure>(); + this.vertexAssignmentList = new int[nbVertices]; + + this.partList.add(new Structure(nbVertices)); + for(Structure structure: structureList){ + this.addStructure(structure); + } + } + + public Partition clone(Graph graph){ + int n = this.vertexAssignmentList.length; + Partition partition = new Partition(); + partition.nbVertices = this.nbVertices; + partition.vertexAssignmentList = new int[n]; + partition.partList = new ArrayList<Structure>(); + partition.graph = graph; + System.arraycopy(this.vertexAssignmentList, 0, partition.vertexAssignmentList, 0, n); + for(Structure structure: this.partList) + partition.partList.add(structure.clone()); + return partition; + } + + public void addStructure(Structure structure){ + int n = this.partList.size(); + int i, m; + Structure part; + ArrayList<Integer> todo = new ArrayList<Integer>(); + for(i=0; i<n; i++){ + part = this.partList.get(i); + Structure intersection = new Structure(0); + Structure difference = new Structure(0); + part.split(structure, intersection, difference); + if (!intersection.isEmpty()){ + this.partList.set(i, intersection); + if (!difference.isEmpty()){ + todo.add(i); + this.partList.add(difference); + } + } + } + m = this.partList.size(); + for(i=n; i<m; i++){ + part = this.partList.get(i); + for(int vertex: part.getList()){ + this.vertexAssignmentList[vertex] = i; + } + } + for(int j=0; j<todo.size(); j++){ + this.graph.split(todo.get(j),m); + } + } + + @Override + public String toString() { + return Arrays.toString(vertexAssignmentList) + "\n" + partList.toString(); + } + + public String toFormattedString() { + String ans = ""; + int n = this.partList.size(); + int i; + Structure part; + for(i=0; i<n; i++) { + part = this.partList.get(i); + ans += part.toFormattedString() + "\n"; + } + return ans; + } + + public int getVertexAssignment(int i) { return vertexAssignmentList[i]; } + public int getPartSize(int i) { return partList.get(vertexAssignmentList[i]).size(); } + + public ArrayList<Structure> getPartList() { + return partList; + } +} diff --git a/src/part2/GraphCompress/src/Positional.java b/src/part2/GraphCompress/src/Positional.java new file mode 100644 index 0000000000000000000000000000000000000000..97192734f21d2b3d88170807c01181e95f0847af --- /dev/null +++ b/src/part2/GraphCompress/src/Positional.java @@ -0,0 +1,4 @@ +public interface Positional { + public int getRow(); + public int getColumn(); +} diff --git a/src/part2/GraphCompress/src/SparseMatrix.java b/src/part2/GraphCompress/src/SparseMatrix.java new file mode 100644 index 0000000000000000000000000000000000000000..0ae4989e5068f5f0a565c554838c236471f1bdb3 --- /dev/null +++ b/src/part2/GraphCompress/src/SparseMatrix.java @@ -0,0 +1,98 @@ +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +public class SparseMatrix<E extends Positional> implements Iterable<E> { + private int size; + private ArrayList<ArrayList<E>> matrix; + private int undoSize; + private ArrayList<E> undoList; + + public SparseMatrix() { + this.size = 0; + this.undoSize = -1; + this.matrix = new ArrayList<ArrayList<E>>(); + this.undoList = new ArrayList<E>(); + } + + // Guaranty that the matrix has size at least n + // No guaranty on the exact size + public void scale(int n){ + this.size = n; + while(this.matrix.size() < n) + this.matrix.add(new ArrayList<E>(Collections.nCopies(1 + this.matrix.size(), null))); + } + + public E get(int i, int j){ + return this.matrix.get(max(i,j)).get(min(i,j)); + } + public boolean hasValue(int i, int j){return this.get(max(i,j), min(i,j)) != null;} + + public void set(int i, int j, E element){ + this.matrix.get(max(i,j)).set(min(i,j), element); + } + public void delete(int i, int j){ + this.undoList.add(this.get(i,j)); + this.set(i,j, null); + } + + public int getSize() { + return size; + } + + public void undoInit(){ + this.undoSize = this.size; + this.undoList = new ArrayList<E>(); + } + + public void undoAction(){ + // Undo actions in reverse order + for(int i = this.undoList.size() - 1; i>= 0; i--){ + E element = this.undoList.get(i); + this.set(element.getRow(), element.getColumn(), element); + } + for(int i = this.size; i > this.undoSize; i--) + this.matrix.remove(i-1); + this.size = this.undoSize; + this.undoSize = -1; + } + + + public Iterator<E> iterator() { + return new Iterator<E> () { + + private int i = 0; + private int j = -1; + + public boolean hasNext() { + while(true){ + j++; + if (j>i) { + j = 0; + i++; + if (i >= SparseMatrix.this.matrix.size()) + return false; + } + if (SparseMatrix.this.hasValue(i,j)) + return true; + } + } + + public E next() { + if (!SparseMatrix.this.hasValue(i,j)) + System.out.println("Erreur impossible"); + return SparseMatrix.this.get(i,j); + } + }; + } + @Override + public String toString() { + String answer = ""; + for(E element: this) + answer += element.toString() + "\n"; + return answer; + } +} diff --git a/src/part2/GraphCompress/src/Structure.java b/src/part2/GraphCompress/src/Structure.java new file mode 100644 index 0000000000000000000000000000000000000000..acdb87706d1e8d8fa4f3ef2f6756fc90a85eb158 --- /dev/null +++ b/src/part2/GraphCompress/src/Structure.java @@ -0,0 +1,121 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Scanner; + +import static java.lang.Integer.parseInt; + +public class Structure { + private int[] list; + + public Structure(int[] list) { + this.list = list; + } + + public Structure(int n) { + this.list = new int[n]; + for (int i=0; i<n; i++) + this.list[i]=i; + } + + public Structure(ArrayList<Integer> list) { + int n = list.size(); + this.list = new int[n]; + for(int i=0; i<n; i++){ + this.list[i] = list.get(i); + } + } + + public Structure(String input){ + String inputNoNewLine = input.replace("\n", ""); + String inputNoFC = inputNoNewLine.substring(3); + String[] inputSplit = inputNoFC.split(" "); + int n = inputSplit.length; + this.list = new int[n]; + int i = 0; + for (String vertex: inputSplit) { + this.list[i] = parseInt(vertex); + i++; + } + } + + public int[] getList() { + return list; + } + public int size() {return list.length;} + + public void setListFromArray(ArrayList<Integer> list) { + int n = list.size(); + this.list = new int[n]; + for (int i = 0; i < n; i++) { + this.list[i] = list.get(i); + } + } + + public boolean contains(int vertex){ + for (int u: this.getList()){ + if (u == vertex) + return true; + } + return false; + } + + public void split(Structure structure, Structure sIntersection, Structure sDifference){ + ArrayList<Integer> intersection = new ArrayList(); // this inter structure + ArrayList<Integer> difference = new ArrayList(); // this minus structure + for (int vertex: this.getList()){ + if (structure.contains(vertex)){ + intersection.add(vertex); + } else { + difference.add(vertex); + } + } + sIntersection.setListFromArray(intersection); + sDifference.setListFromArray(difference); + } + + public boolean isEmpty(){ + return this.list.length == 0; + } + + public static ArrayList<Structure> listFromFile(String filename){ + ArrayList<Structure> structList = new ArrayList<Structure>(); + try { + File myObj = new File(filename); + Scanner myReader = new Scanner(myObj); + while (myReader.hasNextLine()) { + String data = myReader.nextLine(); + if (!data.isEmpty()) { + structList.add(new Structure(data)); + } + } + myReader.close(); + } catch (FileNotFoundException e) { + System.out.println("An error occurred."); + e.printStackTrace(); + } + return structList; + } + + @Override + public String toString() { + return "Structure{" + Arrays.toString(list) + '}'; + } + + public String toFormattedString(){ + String ans = "pt"; + for (int k : this.list){ + ans += " " + Integer.toString(k); + } + return ans; + } + + public Structure clone(){ + int n = this.size(); + int[] list = new int[n]; + System.arraycopy(this.list, 0, list, 0, n); + return new Structure(list); + } + +} diff --git a/src/part3/encode.py b/src/part3/encode.py new file mode 100644 index 0000000000000000000000000000000000000000..9084aa1f6b14bf2f07cfc1775fce2cee78f5ccc2 --- /dev/null +++ b/src/part3/encode.py @@ -0,0 +1,233 @@ +from math import ceil + +PATH = "build/" +THRESHOLD = 8192 + +def listMap(f,x): return list(map(f,x)) + +def keySplit(s): + pq = s.split() + return (int(pq[0]), int(pq[1])) + +def stringToStruct(string): + string.replace('\n', '') + struct = string[3:] + vertexList = [] + for vertexString in struct.split(' '): + if vertexString: vertexList.append(int(vertexString)) + return vertexList + +def splitLongString(string, threshold): + count = 0 + partIndex = [0] + for i in range(len(string)): + if string[i] == '1': + count += 1 + if count > threshold: + partIndex.append(i) + count -= threshold + partIndex.append(len(string)) + partList = [] + for i in range(len(partIndex)-1): + start = partIndex[i] + end = partIndex[i+1] + partList.append(string[start:end]) + return partList + +def getEdge(fileGraph): + with open(fileGraph, 'r') as f: + edgeList = f.readlines() + def stringToCouple(x): + [i,j,w] = x.replace('\n', '').split(',') + ni = min(int(i), int(j)) + nj = max(int(i), int(j)) + return(int(ni),int(nj)) + edgeList = listMap(stringToCouple, edgeList) + return(edgeList) + +def getPartition(filePartition): + with open(filePartition, 'r') as f: + partList = f.readlines() + partList = listMap(stringToStruct, partList) + return(partList) + +def writeBinary(binary_string, file): + data = bytes(int(binary_string[i:i+8], 2) for i in range(0, len(binary_string), 8)) + with open(file, 'wb') as f: + f.write(data) + +############ + +def choose(n, k): + """ + A fast way to calculate binomial coefficients by Andrew Dalke. + See http://stackoverflow.com/questions/3025162/statistics-combinations-in-python + """ + if 0 <= k <= n: + ntok = 1 + ktok = 1 + for t in range(1, min(k, n - k) + 1): + ntok *= n + ktok *= t + n -= 1 + if k % 100 == 0: + print(">>>", n, k) + return ntok // ktok + else: + return 0 + +def ar_encode(list): + sum = 0 + k = 1 + for i, x in enumerate(list[::-1]): + if x in [1, '1']: + sum += choose(i,k) + k += 1 + return sum + +def encodeBigInt(n): + a = bin(n)[2:] + b = bin(len(a))[2:] + n = ceil(len(b)/4) + c = '1' * n + '0' + return c + b.zfill(4*n) + a + +def encodeSmallInt(n): + a = bin(n)[2:] + n = ceil(len(a)/4) + b = '0' * n + '1' + return b + a.zfill(4*n) + +def encodeInt(n): + if n <= 2**25: + return encodeSmallInt(n) + return encodeBigInt(n) + +############ + +class GraphEncode(): + def __init__(self, edgeList, partList): + self.edgeList = edgeList + self.partList = partList + self.order = sum(listMap(len,partList)) + self.vertexAssign = [] # if i = vertexAssign[vertex], then vertex is in partList[i] + self.vertexRank = [] # if i = vertexAssign[vertex] and j = vertexRank[vertex], then partList[i][j] == vertex + self.blocDict = {} + + self._computeVertexPOV() + print("> Graph imported") + for edge in self.edgeList: + self._addEdge(edge) + + def _computeVertexPOV(self): + n = self.order + self.vertexAssign = [0]*n + self.vertexRank = [0]*n + for i,part in enumerate(self.partList): + for j,vertex in enumerate(part): + self.vertexAssign[vertex] = i + self.vertexRank[vertex] = j + + def _addEdge(self, edge): + part1 = self.vertexAssign[edge[0]] + part2 = self.vertexAssign[edge[1]] + if part1 > part2: + part1, part2 = part2, part1 + edge = edge[::-1] + key = str(part1) + " " + str(part2) + if key in self.blocDict: + self.blocDict[key].append(edge) + else: + self.blocDict[key] = [edge] + + def getPartSize(self, part): + return len(self.partList[part]) + + def getSortedBlocList(self): + return sorted(map(lambda x: (keySplit(x[0]), x[1]), self.blocDict.items())) + + def metaMatrixToString(self): + n = len(self.partList) + print(">>> Data made of %d bits (%d ones)" % ((n*(n-1))//2, len(self.blocDict))) + ans = [[0] * n for _ in range(n)] + for key, value in self.blocDict.items(): + p,q = keySplit(key) + ans[p][q] = 1 + s = "" + for k,l in enumerate(ans): + for b in l[k:]: + s += str(b) + return s + + def blockToString(self, i, j): + assert i <= j + key = str(i) + " " + str(j) + if key not in self.blocDict: + return "" + p = self.getPartSize(i) + q = self.getPartSize(j) + print(">>> Data made of %d bits (%d ones)" % (p*q, len(self.blocDict[key]))) + ans = [[0] * q for _ in range(p)] + for edge in self.blocDict[key]: + x = self.vertexRank[edge[0]] + y = self.vertexRank[edge[1]] + ans[x][y] = 1 + s = "" + if i == j: + for k,l in enumerate(ans): + for b in l[k+1:]: + s += str(b) + else: + for l in ans: + for b in l: + s += str(b) + return s + + def encodeBlock(self, i, j): + s = "" + for part in splitLongString(self.blockToString(i, j), THRESHOLD): + s += encodeInt(ar_encode(part)) + return s + + def encodeMetaMatrix(self): + s = "" + for part in splitLongString(self.metaMatrixToString(), THRESHOLD): + s += encodeInt(ar_encode(part)) + return s + + def encode(self): + s = "" + s += encodeInt(self.order) + s += encodeInt(len(self.partList)) + for i in range(len(self.partList)): + s += encodeInt(self.getPartSize(i)) + print("> Part lenghs encoded") + s += encodeInt(len(self.blocDict)) + s += self.encodeMetaMatrix() + print("> Meta-matrix encoded") + l = self.getSortedBlocList() + for kv in l: + value = kv[1] + s += encodeInt(len(value)) + print("> Header encoded, current size is %d bits" % len(s)) + for i, kv in enumerate(l): + key = kv[0] + s += self.encodeBlock(*key) + print("> Bloc %d/%d encoded, current size is %d bits" % (i, len(l), len(s))) + return s + +############ + +def main(): + print("Part 3") + fileGraph = PATH + "graph.graph" + filePartition = PATH + "partition.txt" + fileOut = PATH + "compress.out" + edgeList = getEdge(fileGraph) + partList = getPartition(filePartition) + graph = GraphEncode(edgeList, partList) + output = graph.encode() + writeBinary(output, fileOut) + print("> Encoding done in %d bits" % len(output)) + +main()