├── src ├── ciTest.R ├── .RData ├── __pycache__ │ ├── pc.cpython-37.pyc │ ├── fci.cpython-37.pyc │ ├── graphs.cpython-37.pyc │ ├── algorithms.cpython-37.pyc │ └── indepTests.cpython-37.pyc ├── indepTests.py ├── pc.py ├── algorithms.py ├── .Rhistory ├── fci.py └── graphs.py ├── Docmentation ├── Report.out ├── Report.dvi ├── Report.pdf ├── Causal Nets.pdf ├── Requirements │ ├── Tasks.pdf │ ├── User Stories.pdf │ ├── Tasks.tex │ └── User Stories.tex ├── UOY-Logo-Stacked-shield-Black.png ├── Report.lot ├── Report.blg ├── Report.run.xml ├── Report.lof ├── UoYCSproject.cls ├── Report.toc ├── Report.bib └── Report.bbl ├── .vscode └── settings.json ├── README.md ├── Tests ├── __pycache__ │ └── profile.cpython-37.pyc ├── runtimeTests.py └── unittests.py ├── .gitignore └── data └── asia_1000.data /src/ciTest.R: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Docmentation/Report.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/src/.RData -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "C:\\Users\\James\\Anaconda3\\python.exe" 3 | } -------------------------------------------------------------------------------- /Docmentation/Report.dvi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/Docmentation/Report.dvi -------------------------------------------------------------------------------- /Docmentation/Report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/Docmentation/Report.pdf -------------------------------------------------------------------------------- /Docmentation/Causal Nets.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/Docmentation/Causal Nets.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning-Causal-Networks-in-Python 2 | 4th Year project aiming to implement PC, FCI and RFCI algorithms in python 3 | -------------------------------------------------------------------------------- /src/__pycache__/pc.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/src/__pycache__/pc.cpython-37.pyc -------------------------------------------------------------------------------- /Docmentation/Requirements/Tasks.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/Docmentation/Requirements/Tasks.pdf -------------------------------------------------------------------------------- /src/__pycache__/fci.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/src/__pycache__/fci.cpython-37.pyc -------------------------------------------------------------------------------- /src/__pycache__/graphs.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/src/__pycache__/graphs.cpython-37.pyc -------------------------------------------------------------------------------- /Tests/__pycache__/profile.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/Tests/__pycache__/profile.cpython-37.pyc -------------------------------------------------------------------------------- /Docmentation/Requirements/User Stories.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/Docmentation/Requirements/User Stories.pdf -------------------------------------------------------------------------------- /src/__pycache__/algorithms.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/src/__pycache__/algorithms.cpython-37.pyc -------------------------------------------------------------------------------- /src/__pycache__/indepTests.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/src/__pycache__/indepTests.cpython-37.pyc -------------------------------------------------------------------------------- /Docmentation/UOY-Logo-Stacked-shield-Black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jc1850/Learning-Causal-Networks-in-Python/HEAD/Docmentation/UOY-Logo-Stacked-shield-Black.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Docmentation/Requirements/*.log 2 | /Docmentation/Requirements/*.aux 3 | /Docmentation/Requirements/*.dvi 4 | /Docmentation/Requirements/User Stories.synctex.gz 5 | /Docmentation/Requirements/*.gz 6 | /Docmentation/*.log 7 | /Docmentation/*.gz 8 | /Docmentation/*.aux 9 | -------------------------------------------------------------------------------- /Tests/runtimeTests.py: -------------------------------------------------------------------------------- 1 | import cProfile 2 | import sys 3 | sys.path.append('src') 4 | import fci 5 | from indepTests import chi 6 | data = fci.FCIAlg.prepare_data('data/asia_1000.data', isLabeled = True) 7 | PCA = fci.FCIAlg(data, chi, 0.05) 8 | cProfile.run('PCA.learnGraph()', sort ='cumtime') -------------------------------------------------------------------------------- /Docmentation/Requirements/Tasks.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{multirow} 3 | 4 | \begin{document} 5 | \title{Tasks} 6 | \date{} 7 | \maketitle 8 | \begin{tabular}{| c | c | p{5cm} | l |} 9 | \hline 10 | Sprint & Task ID & Task & Associated Stories \\ 11 | \hline 12 | \multirow{5}{*}{1} 13 | & 1 & Create a graph class which can store a graph, generate a list of nodes and edges & 1.2, 1.3, 1.4, 1.6, 2.*\\ 14 | \cline{2-4} 15 | & 2 & Create a function to estimate the skeleton of a graph from data & 1.5\\ 16 | \hline 17 | 18 | \end{tabular} 19 | \end{document} -------------------------------------------------------------------------------- /Docmentation/Report.lot: -------------------------------------------------------------------------------- 1 | \boolfalse {citerequest}\boolfalse {citetracker}\boolfalse {pagetracker}\boolfalse {backtracker}\relax 2 | \babel@toc {british}{} 3 | \defcounter {refsection}{0}\relax 4 | \addvspace {10\p@ } 5 | \defcounter {refsection}{0}\relax 6 | \addvspace {10\p@ } 7 | \defcounter {refsection}{0}\relax 8 | \addvspace {10\p@ } 9 | \defcounter {refsection}{0}\relax 10 | \contentsline {table}{\numberline {2.1}{\ignorespaces Example Contingency Table For Two Variables}}{7}{table.2.1}% 11 | \defcounter {refsection}{0}\relax 12 | \addvspace {10\p@ } 13 | \defcounter {refsection}{0}\relax 14 | \addvspace {10\p@ } 15 | \defcounter {refsection}{0}\relax 16 | \addvspace {10\p@ } 17 | \defcounter {refsection}{0}\relax 18 | \addvspace {10\p@ } 19 | \defcounter {refsection}{0}\relax 20 | \addvspace {10\p@ } 21 | -------------------------------------------------------------------------------- /Docmentation/Report.blg: -------------------------------------------------------------------------------- 1 | [0] Config.pm:304> INFO - This is Biber 2.12 2 | [0] Config.pm:307> INFO - Logfile is 'Report.blg' 3 | [34] biber-MSWIN64:315> INFO - === 4 | [67] Biber.pm:371> INFO - Reading 'Report.bcf' 5 | [170] Biber.pm:889> INFO - Found 31 citekeys in bib section 0 6 | [185] Biber.pm:4093> INFO - Processing section 0 7 | [200] Biber.pm:4254> INFO - Looking for bibtex format file 'Report.bib' for section 0 8 | [260] bibtex.pm:1523> INFO - LaTeX decoding ... 9 | [312] bibtex.pm:1340> INFO - Found BibTeX data source 'Report.bib' 10 | [315] Utils.pm:193> WARN - Possible typo (case mismatch) between datasource keys: 'numpy' and 'Numpy' in file 'Report.bib' 11 | [344] Utils.pm:193> WARN - month field 'Mar' in entry 'ogrady_2019' is not an integer - this will probably not sort properly. 12 | [434] Utils.pm:193> WARN - month field 'Nov' in entry 'wilkinson_2014' is not an integer - this will probably not sort properly. 13 | [468] UCollate.pm:68> INFO - Overriding locale 'en-GB' defaults 'variable = shifted' with 'variable = non-ignorable' 14 | [468] UCollate.pm:68> INFO - Overriding locale 'en-GB' defaults 'normalization = NFD' with 'normalization = prenormalized' 15 | [468] Biber.pm:3921> INFO - Sorting list 'none/global//global/global' of type 'entry' with template 'none' and locale 'en-GB' 16 | [468] Biber.pm:3927> INFO - No sort tailoring available for locale 'en-GB' 17 | [498] bbl.pm:636> INFO - Writing 'Report.bbl' with encoding 'UTF-8' 18 | [509] bbl.pm:739> INFO - Output to Report.bbl 19 | [513] Biber.pm:110> INFO - WARNINGS: 3 20 | -------------------------------------------------------------------------------- /Docmentation/Requirements/User Stories.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{multirow} 3 | 4 | \begin{document} 5 | \title{Epics \& User Stories} 6 | \date{} 7 | \maketitle 8 | \section{Epics} 9 | \begin{tabular}{| l | p{12cm} |} 10 | \hline 11 | ID & Epic \\ 12 | \hline 13 | 1 & A user must be able to learn a Graph, representing causal relationships, from data \\ 14 | \hline 15 | 2 & A user must be able to view a learned graph \\ 16 | \hline 17 | \end{tabular} 18 | 19 | \section{User Stories} 20 | 21 | \begin{tabular}{| l | l | p{9.5cm} |} 22 | \hline 23 | Epic ID & Story ID & Story \\ 24 | \hline 25 | \multirow{11}{*}{1} & 1.1 & A user must be able to define a custom conditional independence function\\ 26 | \cline{2-3} 27 | & 1.2 & A user must be able to learn a Directed Acyclic Graph using the PC algorithm \\ 28 | \cline{2-3} 29 | & 1.3 & A user must be able to learn a Partial Ancestral Graph using the FCI algorithm \\ 30 | \cline{2-3} 31 | & 1.4 & A user must be able to learn a Partial Ancestral Graph using the RFCI algorithm \\ 32 | \cline{2-3} 33 | & 1.5 & A user must have access to predefined conditional independence functions \\ 34 | \cline{2-3} 35 | & 1.6 & A user must be able to estimate the skeleton of a graph \\ 36 | \hline 37 | \multirow{7}{*}{2} & 2.1 & A user must be able to plot a Graph with directed edges\\ 38 | \cline{2-3} 39 | & 2.2 & A user must be able to plot a graph with undirected edges \\ 40 | \cline{2-3} 41 | & 2.3 & A user must be able to plot a graph with bidirectional edges \\ 42 | \cline{2-3} 43 | & 2.4 & A user must be able to plot a graph with a mixture of above edges \\ 44 | \cline{2-3} 45 | & 2.5 & A user must have access to a data structure containing edges of the graph \\ 46 | \hline 47 | 48 | \end{tabular} 49 | 50 | \end{document} -------------------------------------------------------------------------------- /Docmentation/Report.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 28 | 33 | 36 | 39 | 42 | ]> 43 | 44 | 45 | latex 46 | 47 | Report.bcf 48 | 49 | 50 | Report.bbl 51 | 52 | 53 | blx-dm.def 54 | blx-compat.def 55 | biblatex.def 56 | standard.bbx 57 | numeric.bbx 58 | numeric-comp.bbx 59 | ieee.bbx 60 | numeric-comp.cbx 61 | ieee.cbx 62 | biblatex.cfg 63 | english.lbx 64 | british.lbx 65 | 66 | 67 | 68 | biber 69 | 70 | biber 71 | Report 72 | 73 | 74 | Report.bcf 75 | 76 | 77 | Report.bbl 78 | 79 | 80 | Report.bbl 81 | 82 | 83 | Report.bcf 84 | 85 | 86 | Report.bib 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Docmentation/Report.lof: -------------------------------------------------------------------------------- 1 | \boolfalse {citerequest}\boolfalse {citetracker}\boolfalse {pagetracker}\boolfalse {backtracker}\relax 2 | \babel@toc {british}{} 3 | \defcounter {refsection}{0}\relax 4 | \addvspace {10\p@ } 5 | \defcounter {refsection}{0}\relax 6 | \addvspace {10\p@ } 7 | \defcounter {refsection}{0}\relax 8 | \addvspace {10\p@ } 9 | \defcounter {refsection}{0}\relax 10 | \contentsline {figure}{\numberline {2.1}{\ignorespaces A DAG with 3 nodes and 2 edges}}{2}{figure.2.1}% 11 | \defcounter {refsection}{0}\relax 12 | \contentsline {figure}{\numberline {2.2}{\ignorespaces A PDAG with 3 nodes and 2 edges}}{2}{figure.2.2}% 13 | \defcounter {refsection}{0}\relax 14 | \contentsline {figure}{\numberline {2.3}{\ignorespaces A graph containing a collider}}{4}{figure.2.3}% 15 | \defcounter {refsection}{0}\relax 16 | \contentsline {figure}{\numberline {2.4}{\ignorespaces A DAG in which nodes 1 and 4 are D-Separated}}{5}{figure.2.4}% 17 | \defcounter {refsection}{0}\relax 18 | \contentsline {figure}{\numberline {2.5}{\ignorespaces A DAG in which nodes 1 and 4 are not D-Separated}}{5}{figure.2.5}% 19 | \defcounter {refsection}{0}\relax 20 | \contentsline {figure}{\numberline {2.6}{\ignorespaces $A-X-Y-Z$ is a discriminating path on $ Y $}}{6}{figure.2.6}% 21 | \defcounter {refsection}{0}\relax 22 | \addvspace {10\p@ } 23 | \defcounter {refsection}{0}\relax 24 | \contentsline {figure}{\numberline {3.1}{\ignorespaces Numpy Style docstring}}{19}{figure.3.1}% 25 | \defcounter {refsection}{0}\relax 26 | \addvspace {10\p@ } 27 | \defcounter {refsection}{0}\relax 28 | \contentsline {figure}{\numberline {4.1}{\ignorespaces A skeleton of a Causal Network}}{24}{figure.4.1}% 29 | \defcounter {refsection}{0}\relax 30 | \contentsline {figure}{\numberline {4.2}{\ignorespaces Two potential colliders in a skeleton}}{24}{figure.4.2}% 31 | \defcounter {refsection}{0}\relax 32 | \contentsline {figure}{\numberline {4.3}{\ignorespaces A potential orientation of the skeleton in Figure 4.1 containing colliders from Figure 4.2}}{25}{figure.4.3}% 33 | \defcounter {refsection}{0}\relax 34 | \contentsline {figure}{\numberline {4.4}{\ignorespaces A PDAG and how it would be represented in the implementation}}{28}{figure.4.4}% 35 | \defcounter {refsection}{0}\relax 36 | \contentsline {figure}{\numberline {4.5}{\ignorespaces A PAG and how it would be represented in the implementation}}{28}{figure.4.5}% 37 | \defcounter {refsection}{0}\relax 38 | \addvspace {10\p@ } 39 | \defcounter {refsection}{0}\relax 40 | \contentsline {figure}{\numberline {5.1}{\ignorespaces The actual network that generated data in the asia\_1000 dataset}}{31}{figure.5.1}% 41 | \defcounter {refsection}{0}\relax 42 | \contentsline {figure}{\numberline {5.2}{\ignorespaces The networks estimated by the R (left) and Python (right) implementation from the Asia\_1000 dataset}}{31}{figure.5.2}% 43 | \defcounter {refsection}{0}\relax 44 | \addvspace {10\p@ } 45 | \defcounter {refsection}{0}\relax 46 | \addvspace {10\p@ } 47 | -------------------------------------------------------------------------------- /src/indepTests.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import networkx as nx 3 | import itertools 4 | import scipy.stats 5 | 6 | 7 | def chi(data, X,Y,Z): 8 | """ A function to determine whether variable X is indepenent of Y given conditioning set Z 9 | Parameters 10 | ---------- 11 | X : str, 12 | One variable being tested for independence, 13 | Y : str 14 | The other variable being tested for independence 15 | Z: str[] 16 | The conditioning set 17 | alpha: float 18 | The minimum p-value returned by the indepence test 19 | for the data to be considered independent 20 | 21 | Returns 22 | ------- 23 | boolean 24 | True : X independent of Y given Z 25 | False: X not independent of Y given Z 26 | """ 27 | if len(Z) == 0: 28 | cont = pd.crosstab(data[X], data[Y]) 29 | xvalues = [val for val in cont.index] 30 | yvalues = [val for val in cont.columns] 31 | ysums = {val: sum(cont[val]) for val in yvalues} 32 | xsums = {val: sum(cont.loc[val]) for val in xvalues} 33 | 34 | total = sum(xsums.values()) 35 | observed = [] 36 | expected = [] 37 | for x in xvalues: 38 | for y in yvalues: 39 | observed.append(cont[y][x]) 40 | expected.append(xsums[x]/total * ysums[y]) 41 | freedom = len(xvalues) * len(yvalues) - ((len(xvalues) - 1) * (len(yvalues) - 1)) -1 42 | chisq, p = scipy.stats.chisquare(observed, f_exp=expected, ddof=freedom) 43 | return p, chisq 44 | else: 45 | zdata = [data[z] for z in Z] 46 | zdata = list(zip(*(column for column in zdata))) 47 | zdatastr = [] 48 | for point in zdata: 49 | pointstr = "" 50 | for var in point: 51 | pointstr += str(var) + "," 52 | zdatastr.append(pointstr) 53 | zdata = pd.DataFrame(data=zdatastr,columns=['z']) 54 | cont = pd.crosstab(data[X],[zdata['z'], data[Y],]) 55 | xvalues = [val for val in cont.index] 56 | yvalues = cont.columns.levels[1] 57 | zvalues = cont.columns.levels[0] 58 | labels = cont.columns.labels 59 | zyvalues = {z: [] for z in zvalues} 60 | for i in range(len(labels[0])): 61 | zyvalues[zvalues[labels[0][i]]].append(yvalues[labels[1][i]]) 62 | ygz = {} 63 | xgz = {} 64 | #find x|z and y|z 65 | ztotal = {} 66 | for z in zvalues: 67 | #calculate y|z for all y and z 68 | #also capture z totals 69 | ygz[z] = {} 70 | xgz[z] = {x: 0 for x in xvalues} 71 | ztotal[z] = 0 72 | for y in zyvalues[z]: 73 | zytotal = sum(cont[z][y]) 74 | ygz[z][y] = zytotal 75 | ztotal[z] += zytotal 76 | for x in xvalues: 77 | xgz[z][x] += cont[z][y][x] 78 | for y in zyvalues[z]: 79 | ygz[z][y] = ygz[z][y] / ztotal[z] 80 | for x in xvalues: 81 | xgz[z][x] = xgz[z][x]/ztotal[z] 82 | observed = [] 83 | expected = [] 84 | for z in zvalues: 85 | for y in zyvalues[z]: 86 | for x in xvalues: 87 | observed.append(cont[z][y][x]) 88 | expected.append(max(ygz[z][y] * xgz[z][x] * ztotal[z],0.000000000001)) 89 | zlength = 1 90 | for i in range(len(zvalues[0][:-1].split(','))): 91 | values = [] 92 | for value in zvalues: 93 | if value.split(',')[i] not in values: 94 | values.append(value.split(',')[i]) 95 | zlength *= len(values) 96 | 97 | freedom = len(observed) - ((len(yvalues) - 1) * (len(xvalues) - 1) * zlength)-1 98 | chisq, p = scipy.stats.chisquare(observed, f_exp=expected, ddof=freedom) 99 | return p, chisq -------------------------------------------------------------------------------- /src/pc.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | from graphs import PDAG 3 | from algorithms import GraphLearner 4 | from indepTests import chi 5 | import sys 6 | 7 | class PCAlg(GraphLearner): 8 | """ 9 | A graph learner which implements the PC algorithm 10 | """ 11 | 12 | def orientEdges(self, skeleton, sepset): 13 | """ A method to orient the edges of a skeleton 14 | 15 | Parameters 16 | ---------- 17 | skeleton : networkx.Graph 18 | An undirected graph showing causal links to be oriented by 19 | the pc algorithm. Can be genertaed using the learnSkeleton 20 | method. 21 | 22 | Returns 23 | ------- 24 | PDAG 25 | A partially directed acyclic graph represnting a set of directed acyclic graphs. 26 | this graph shows independence relationships between variables. 27 | """ 28 | directed = nx.DiGraph() 29 | directed.add_nodes_from(skeleton.nodes) 30 | undirected = skeleton.copy() 31 | self.orient_V( undirected, directed, sepset) 32 | old_directed = nx.DiGraph() 33 | while old_directed.edges != directed.edges: 34 | old_directed = directed.copy() 35 | for i in skeleton: 36 | for j in skeleton: 37 | if i != j: 38 | for k in skeleton: 39 | if i != k and j != k: 40 | if directed.has_edge(i,j) and not skeleton.has_edge(k,i) and undirected.has_edge(j,k): 41 | directed.add_edge(j,k) 42 | undirected.remove_edge(j,k) 43 | if PCAlg.findPath(i,j, directed, []) and undirected.has_edge(i,j): 44 | directed.add_edge(i,j) 45 | undirected.remove_edge(i,j) 46 | #generate PDAG 47 | pdag = self.pdag_union(directed, undirected) 48 | return pdag 49 | 50 | def learnGraph(self): 51 | """ 52 | function to learn a causal network from data 53 | 54 | Returns 55 | ------- 56 | PDAG 57 | causal network learned from data 58 | """ 59 | print('Learning Skeleton of graph...') 60 | skeleton, sepset = self.learnSkeleton() 61 | print('...Skeleton learnt') 62 | print('Orienting Edges...') 63 | pdag = self.orientEdges(skeleton, sepset) 64 | print('...Learning complete') 65 | return pdag 66 | 67 | def pdag_union(self, directed, undirected): 68 | """ 69 | A method to orient all "V-structures" in a graph 70 | 71 | Parameters 72 | ---------- 73 | undirected: nx.Graph 74 | graph containing the undirected edges 75 | directed: nx.DiGraph 76 | graph containing the directed edges 77 | 78 | Returns 79 | ------- 80 | PDAG 81 | a graph containing all edges from the two graphs 82 | """ 83 | pdag = PDAG() 84 | for edge in directed.edges: 85 | pdag.add_edge(*edge) 86 | for edge in undirected.edges: 87 | pdag.add_edge(*edge, False) 88 | return pdag 89 | 90 | 91 | if __name__ == '__main__': 92 | data_path = sys.argv[1] 93 | if len(sys.argv) == 4: 94 | if sys.argv[3] == 'space': 95 | sys.argv[3] = ' ' 96 | delimeator = sys.argv[3] 97 | labeled = sys.argv[2] == 'True' 98 | elif len(sys.argv) == 3: 99 | delimeator = ' ' 100 | labeled = sys.argv[2] == 'True' 101 | else: 102 | delimeator = ' ' 103 | labeled = True 104 | data = PCAlg.prepare_data(data_path, isLabeled=labeled, delim = delimeator) 105 | pc = PCAlg(data, chi, 0.05) 106 | pdag = pc.learnGraph() 107 | pdag.write_to_file('adjmat') 108 | 109 | 110 | -------------------------------------------------------------------------------- /Docmentation/UoYCSproject.cls: -------------------------------------------------------------------------------- 1 | % Jeremy Jacob UoYCSproject 2 | 3 | % A class file to typeset BEng, Bsc, MEng, MMath and taught MSc 4 | % project reports in the Department of Computer Science at the 5 | % University of York. 6 | 7 | % History 8 | % 9 | % Version 1 10 | % 11 | % 2004Apr27 Initial version 12 | % 2004May10 Generation of list of tables and figures removed 13 | % 2004Dec08 Minor fixes to error messages 14 | % 2005Feb02 Package pdfcprot replaced by microtype 15 | % 2005Apr12 dedication and acknowledgements now come after abstract 16 | % 2005Jul27 added option `sc' to `mathpazo' package & `textcomp' package 17 | % 2005Aug31 added packages for Helvetica and Courier fonts 18 | % 19 | % Version 2 created, not backward compatible with Version 1 20 | % 21 | % 2006Mar23 moved front matter generation from \AtBeginDocument to 22 | % separately called \maketitle 23 | % 2006Mar23 added options for choice of citation style 24 | % 2006May12 improved communication with type area calculation 25 | % 2006Jul03 added hypcap package 26 | % 2006Dec10 added fixltx2e package 27 | % 2007May31 fixed autoref names 28 | % 2007Nov01 fixed Masters title names 29 | % 2007Nov12 Added old-style text figures. 30 | % 2008Oct03 used hyperref option `pdfusetitle' 31 | % 2008Oct27 removed page numbers from `Part' pages 32 | % 2009Jun26 changed to IEEE trans style; removed options. 33 | % 2010Nov02 replaced obsolete KOMA-script options 34 | % 2014Oct22 added ACS declaration 35 | % 36 | % Version 3, backwards compatible 37 | % 38 | % 2015Apr24 Converted from BibTeX to BibLaTeX 39 | % 2016Dec05 Brought up to date with latest Koma Script 40 | 41 | \NeedsTeXFormat{LaTeX2e} 42 | \ProvidesClass{UoYCSproject}[2016/12/05 Jeremy Jacob] 43 | 44 | % Koma-script report style 45 | %\PassOptionsToPackage{twoside=false}{typearea} 46 | \LoadClass[fontsize=12pt,a4paper,abstracton,twoside=false,numbers=noenddot]{scrreprt} 47 | \RequirePackage{scrhack} 48 | \RequirePackage[toc,page]{appendix}{ 49 | \RequirePackage{graphicx} 50 | 51 | \RequirePackage[T1]{fontenc} % prevents < in text mode turning into 52 | \RequirePackage{textcomp} % ?', etc 53 | \RequirePackage[osf]{mathpazo} % Palatino font 54 | \RequirePackage{courier} % nicer typewriter-style fonts 55 | \RequirePackage[scaled]{helvet} % nice san serif fonts 56 | \RequirePackage{microtype} % micro-typographical extensions for 57 | % pdf(e)(la)tex 58 | \RequirePackage[british]{babel} % British hyphenation patterns, etc. 59 | \RequirePackage{ifthen} 60 | 61 | \usepackage[scaled]{helvet} 62 | \renewcommand\familydefault{\sfdefault} 63 | \usepackage[T1]{fontenc} 64 | 65 | \pagestyle{headings} 66 | \renewcommand{\partpagestyle}{empty} 67 | 68 | % Reference control 69 | \RequirePackage{csquotes} 70 | 71 | %\RequirePackage{silence} % To suppress some warning, see below. 72 | %\WarningFilter{biblatex}{File 'british-ieee.lbx'} %The warning is benign and can be ignored (issue since biblatex-ieee version 1.3). 73 | %\WarningFilter{biblatex}{File 'english-ieee.lbx'}%The warning is benign and can be ignored (issue since biblatex-ieee version 1.3). 74 | 75 | \RequirePackage[style=ieee,backend=biber]{biblatex} 76 | 77 | 78 | 79 | %\typearea[current]{calc} % force page layout recalculation after 80 | % changing all the fonts 81 | 82 | \newcommand*{\UoYCSP@mk@degree}[1]{% 83 | \expandafter\def\csname#1\endcsname{\newcommand*{\UoYCSP@degree}{#1}}% 84 | } 85 | \UoYCSP@mk@degree{BEng} 86 | \UoYCSP@mk@degree{BSc} 87 | \UoYCSP@mk@degree{MEng} 88 | \UoYCSP@mk@degree{MMath} 89 | \newcommand*{\SWE}{\newcommand*{\UoYCSP@degree}{MSc~in~Software~Engineering}} 90 | \newcommand*{\SCSE}{\newcommand*{\UoYCSP@degree}{MSc~in~Safety~Critical~Systems~Engineering}} 91 | \newcommand*{\MIP}{\newcommand*{\UoYCSP@degree}{MSc~in~Information~Processing}} 92 | \newcommand*{\MIT}{\newcommand*{\UoYCSP@degree}{MSc~in~Information~Technology}} 93 | \newcommand*{\MNC}{\newcommand*{\UoYCSP@degree}{MSc~in~Natural~Computation}} 94 | \newcommand*{\GTC}{\newcommand*{\UoYCSP@degree}{MSc~in~Gas~Turbine~Control}} 95 | \newcommand*{\ACS}{\newcommand*{\UoYCSP@degree}{MSc~in~Advanced~Computer~Science}} 96 | 97 | \newcommand*{\supervisor}[1]{\newcommand*{\UoYCSP@supervisor}{#1}} 98 | 99 | \newenvironment{summary} 100 | {\addchap{Executive Summary} 101 | \label{cha:exesummary} 102 | } 103 | { 104 | \clearpage 105 | \pagenumbering{arabic} 106 | } 107 | 108 | \usepackage[top=2.5cm, bottom=4cm, left=4cm, right=4cm]{geometry} 109 | \setlength{\parindent}{8pt} 110 | \setlength{\parskip}{8pt} 111 | 112 | \date{\fbox{\Huge DRAFT PROCESSED \today}} 113 | 114 | \titlehead{ \hfill Department of Computer Science\\\vspace{32pt} 115 | \begin{center} 116 | \includegraphics[height = 1in]{"./UOY-Logo-Stacked-shield-Black"}\\ 117 | \vspace{32pt} 118 | \ifx\UoYCSP@degree\undefined% 119 | \ClassError{UoYCSproject}% 120 | {degree scheme not set} 121 | {Declare the degree scheme in the preamble using 122 | \protect\BEng, \protect\MEng, etc.} 123 | \else% 124 | \large Submitted in part fulfilment for the degree of 125 | \UoYCSP@degree.% 126 | \fi% 127 | \end{center} 128 | } 129 | 130 | \publishers{% 131 | \large 132 | 133 | \ifx\UoYCSP@supervisor\undefined% 134 | \ClassError{UoYCSproject}% 135 | {supervisor not set} 136 | {Declare the supervisor in the preamble using \protect\supervisor{Name}} 137 | \else% 138 | Supervisor: \UoYCSP@supervisor% 139 | \fi% 140 | 141 | } 142 | \let\oldtitle\title 143 | \renewcommand{\title}[1]{\oldtitle{ \vspace{-64pt} #1}} 144 | 145 | %\let\old@abstract\abstract 146 | %\let\endold@abstract\endabstract 147 | %\renewcommand{\abstract}[1]{\newcommand{\UoYCSP@abstract}{#1}} 148 | %\renewcommand{\endabstract}{} 149 | 150 | \let\old@dedication\dedication 151 | \newcommand*{\UoYCSP@dedication}{} 152 | \renewcommand*{\dedication}[1]{\renewcommand*{\UoYCSP@dedication}{#1}} 153 | \newif\ifacknowledgements 154 | \acknowledgementsfalse 155 | \newcommand*{\UoYCSP@acknowledgements}{} 156 | \newcommand{\acknowledgements}[1]{% 157 | \renewcommand{\UoYCSP@acknowledgements}{#1}% 158 | \acknowledgementstrue 159 | } 160 | 161 | \InputIfFileExists{\jobname.ldf}{} 162 | 163 | \RequirePackage[pdfusetitle]{hyperref}% automatic hyperlinks, etc 164 | \RequirePackage[all]{hypcap}% improve link placement in floats 165 | \hypersetup{% 166 | pdfstartview={Fit}% 167 | } 168 | \urlstyle{sf} 169 | \renewcommand*{\Itemautorefname}{Item} 170 | \renewcommand*{\chapterautorefname}{Chapter} 171 | \renewcommand*{\sectionautorefname}{Section} 172 | \renewcommand*{\subsectionautorefname}{Subsection} 173 | \renewcommand*{\subsubsectionautorefname}{Subsubsection} 174 | \renewcommand*{\paragraphautorefname}{Paragraph} 175 | \renewcommand*{\Hfootnoteautorefname}{Footnote} 176 | %\renewcommand*{\pageautorefname}{Page} 177 | 178 | \let\old@maketitle=\maketitle 179 | \renewcommand*{\maketitle}{% 180 | \old@maketitle% 181 | % dedication & acknowledgements 182 | \ifthenelse% 183 | {\equal{\UoYCSP@dedication}{\@empty} 184 | \and\equal{\UoYCSP@acknowledgements}{\@empty}} 185 | {}{ 186 | \cleardoublepage% 187 | \thispagestyle{empty} 188 | \vspace*{\fill}% 189 | % 190 | \ifthenelse{\equal{\UoYCSP@dedication}{\@empty}}% 191 | {}% 192 | { \begin{center}% 193 | \large\UoYCSP@dedication% 194 | \end{center}% 195 | }% 196 | % 197 | \ifacknowledgements% 198 | { \vfill% 199 | \normalsize% 200 | \begin{center}% 201 | \large\bfseries Acknowledgements% 202 | \end{center}% 203 | \UoYCSP@acknowledgements% 204 | }% 205 | \fi% 206 | \vspace*{\fill}% 207 | }% 208 | \cleardoublepage% 209 | \microtypesetup{protrusion=false}% 210 | \tableofcontents% 211 | \microtypesetup{protrusion=true}% 212 | } 213 | 214 | \AtBeginDocument{% 215 | \nonfrenchspacing% 216 | } 217 | -------------------------------------------------------------------------------- /Docmentation/Report.toc: -------------------------------------------------------------------------------- 1 | \boolfalse {citerequest}\boolfalse {citetracker}\boolfalse {pagetracker}\boolfalse {backtracker}\relax 2 | \babel@toc {british}{} 3 | \defcounter {refsection}{0}\relax 4 | \contentsline {chapter}{\nonumberline Executive Summary}{vii}{chapter*.4}% 5 | \defcounter {refsection}{0}\relax 6 | \contentsline {chapter}{\numberline {1}Introduction}{1}{chapter.1}% 7 | \defcounter {refsection}{0}\relax 8 | \contentsline {chapter}{\numberline {2}Literature Review}{2}{chapter.2}% 9 | \defcounter {refsection}{0}\relax 10 | \contentsline {section}{\numberline {2.1}Causal Networks}{2}{section.2.1}% 11 | \defcounter {refsection}{0}\relax 12 | \contentsline {section}{\numberline {2.2}Probability and Independence}{3}{section.2.2}% 13 | \defcounter {refsection}{0}\relax 14 | \contentsline {subsection}{\numberline {2.2.1}Basic Probability}{3}{subsection.2.2.1}% 15 | \defcounter {refsection}{0}\relax 16 | \contentsline {subsection}{\numberline {2.2.2}Distributions}{3}{subsection.2.2.2}% 17 | \defcounter {refsection}{0}\relax 18 | \contentsline {subsection}{\numberline {2.2.3}Independence}{3}{subsection.2.2.3}% 19 | \defcounter {refsection}{0}\relax 20 | \contentsline {section}{\numberline {2.3}D Separation}{4}{section.2.3}% 21 | \defcounter {refsection}{0}\relax 22 | \contentsline {subsection}{\numberline {2.3.1}Definitions}{4}{subsection.2.3.1}% 23 | \defcounter {refsection}{0}\relax 24 | \contentsline {subsection}{\numberline {2.3.2}D-Separation}{4}{subsection.2.3.2}% 25 | \defcounter {refsection}{0}\relax 26 | \contentsline {section}{\numberline {2.4}Faithfulness}{5}{section.2.4}% 27 | \defcounter {refsection}{0}\relax 28 | \contentsline {section}{\numberline {2.5}Discriminating paths}{5}{section.2.5}% 29 | \defcounter {refsection}{0}\relax 30 | \contentsline {section}{\numberline {2.6}Possible D-Separation Set}{6}{section.2.6}% 31 | \defcounter {refsection}{0}\relax 32 | \contentsline {section}{\numberline {2.7}Tests for Independence}{6}{section.2.7}% 33 | \defcounter {refsection}{0}\relax 34 | \contentsline {section}{\numberline {2.8}Algorithms For Learning Causal Networks}{7}{section.2.8}% 35 | \defcounter {refsection}{0}\relax 36 | \contentsline {subsection}{\numberline {2.8.1}Constraint Based Methods}{7}{subsection.2.8.1}% 37 | \defcounter {refsection}{0}\relax 38 | \contentsline {subsection}{\numberline {2.8.2}Score Based Methods}{8}{subsection.2.8.2}% 39 | \defcounter {refsection}{0}\relax 40 | \contentsline {section}{\numberline {2.9}Computing a skeleton}{8}{section.2.9}% 41 | \defcounter {refsection}{0}\relax 42 | \contentsline {section}{\numberline {2.10}The PC Algorithm}{10}{section.2.10}% 43 | \defcounter {refsection}{0}\relax 44 | \contentsline {section}{\numberline {2.11}The FCI algorithm}{10}{section.2.11}% 45 | \defcounter {refsection}{0}\relax 46 | \contentsline {section}{\numberline {2.12}The RFCI Algorithm}{12}{section.2.12}% 47 | \defcounter {refsection}{0}\relax 48 | \contentsline {chapter}{\numberline {3}Design}{14}{chapter.3}% 49 | \defcounter {refsection}{0}\relax 50 | \contentsline {section}{\numberline {3.1}Methodology}{14}{section.3.1}% 51 | \defcounter {refsection}{0}\relax 52 | \contentsline {subsection}{\numberline {3.1.1}Waterfall}{14}{subsection.3.1.1}% 53 | \defcounter {refsection}{0}\relax 54 | \contentsline {subsection}{\numberline {3.1.2}Agile}{15}{subsection.3.1.2}% 55 | \defcounter {refsection}{0}\relax 56 | \contentsline {subsection}{\numberline {3.1.3}Spiral}{15}{subsection.3.1.3}% 57 | \defcounter {refsection}{0}\relax 58 | \contentsline {subsection}{\numberline {3.1.4}Chosen Approach}{15}{subsection.3.1.4}% 59 | \defcounter {refsection}{0}\relax 60 | \contentsline {section}{\numberline {3.2}Sprints}{16}{section.3.2}% 61 | \defcounter {refsection}{0}\relax 62 | \contentsline {section}{\numberline {3.3}Requirements}{17}{section.3.3}% 63 | \defcounter {refsection}{0}\relax 64 | \contentsline {subsection}{\numberline {3.3.1}Epics}{17}{subsection.3.3.1}% 65 | \defcounter {refsection}{0}\relax 66 | \contentsline {subsection}{\numberline {3.3.2}User Stories}{17}{subsection.3.3.2}% 67 | \defcounter {refsection}{0}\relax 68 | \contentsline {subsection}{\numberline {3.3.3}Tasks}{17}{subsection.3.3.3}% 69 | \defcounter {refsection}{0}\relax 70 | \contentsline {section}{\numberline {3.4}Architecture}{18}{section.3.4}% 71 | \defcounter {refsection}{0}\relax 72 | \contentsline {subsection}{\numberline {3.4.1}Unit Testing}{18}{subsection.3.4.1}% 73 | \defcounter {refsection}{0}\relax 74 | \contentsline {section}{\numberline {3.5}Documentation}{18}{section.3.5}% 75 | \defcounter {refsection}{0}\relax 76 | \contentsline {section}{\numberline {3.6}Tools}{19}{section.3.6}% 77 | \defcounter {refsection}{0}\relax 78 | \contentsline {subsection}{\numberline {3.6.1}Version Control}{19}{subsection.3.6.1}% 79 | \defcounter {refsection}{0}\relax 80 | \contentsline {subsection}{\numberline {3.6.2}Python Libraries}{20}{subsection.3.6.2}% 81 | \defcounter {refsection}{0}\relax 82 | \contentsline {section}{\numberline {3.7}Refactoring}{20}{section.3.7}% 83 | \defcounter {refsection}{0}\relax 84 | \contentsline {chapter}{\numberline {4}Implementation}{22}{chapter.4}% 85 | \defcounter {refsection}{0}\relax 86 | \contentsline {section}{\numberline {4.1}Independence Test}{22}{section.4.1}% 87 | \defcounter {refsection}{0}\relax 88 | \contentsline {section}{\numberline {4.2}Skeleton}{23}{section.4.2}% 89 | \defcounter {refsection}{0}\relax 90 | \contentsline {subsection}{\numberline {4.2.1}Variables to be Tested}{23}{subsection.4.2.1}% 91 | \defcounter {refsection}{0}\relax 92 | \contentsline {subsection}{\numberline {4.2.2}Separation Sets}{23}{subsection.4.2.2}% 93 | \defcounter {refsection}{0}\relax 94 | \contentsline {section}{\numberline {4.3}PC Edge Orientation}{23}{section.4.3}% 95 | \defcounter {refsection}{0}\relax 96 | \contentsline {subsection}{\numberline {4.3.1}V-Structures}{24}{subsection.4.3.1}% 97 | \defcounter {refsection}{0}\relax 98 | \contentsline {section}{\numberline {4.4}FCI Algorithm Edge Orientation}{25}{section.4.4}% 99 | \defcounter {refsection}{0}\relax 100 | \contentsline {section}{\numberline {4.5}Testing}{25}{section.4.5}% 101 | \defcounter {refsection}{0}\relax 102 | \contentsline {subsection}{\numberline {4.5.1}Independence Test}{25}{subsection.4.5.1}% 103 | \defcounter {refsection}{0}\relax 104 | \contentsline {subsection}{\numberline {4.5.2}Skeleton Estimation}{26}{subsection.4.5.2}% 105 | \defcounter {refsection}{0}\relax 106 | \contentsline {subsection}{\numberline {4.5.3}PC Algorithm}{26}{subsection.4.5.3}% 107 | \defcounter {refsection}{0}\relax 108 | \contentsline {subsection}{\numberline {4.5.4}FCI Algorithm}{26}{subsection.4.5.4}% 109 | \defcounter {refsection}{0}\relax 110 | \contentsline {subsection}{\numberline {4.5.5}Final Structure}{27}{subsection.4.5.5}% 111 | \defcounter {refsection}{0}\relax 112 | \contentsline {subsection}{\numberline {4.5.6}Independence Test}{27}{subsection.4.5.6}% 113 | \defcounter {refsection}{0}\relax 114 | \contentsline {subsection}{\numberline {4.5.7}Graph Learners}{27}{subsection.4.5.7}% 115 | \defcounter {refsection}{0}\relax 116 | \contentsline {subsection}{\numberline {4.5.8}Graphs}{27}{subsection.4.5.8}% 117 | \defcounter {refsection}{0}\relax 118 | \contentsline {section}{\numberline {4.6}Usage}{28}{section.4.6}% 119 | \defcounter {refsection}{0}\relax 120 | \contentsline {section}{\numberline {4.7}Viewing Graphs}{29}{section.4.7}% 121 | \defcounter {refsection}{0}\relax 122 | \contentsline {subsection}{\numberline {4.7.1}Adjacency Matrices}{29}{subsection.4.7.1}% 123 | \defcounter {refsection}{0}\relax 124 | \contentsline {chapter}{\numberline {5}Analysis}{30}{chapter.5}% 125 | \defcounter {refsection}{0}\relax 126 | \contentsline {section}{\numberline {5.1}Independence Test}{30}{section.5.1}% 127 | \defcounter {refsection}{0}\relax 128 | \contentsline {section}{\numberline {5.2}Initial Skeleton Generation}{31}{section.5.2}% 129 | \defcounter {refsection}{0}\relax 130 | \contentsline {section}{\numberline {5.3}PC Algorithm Edge Orientation}{31}{section.5.3}% 131 | \defcounter {refsection}{0}\relax 132 | \contentsline {section}{\numberline {5.4}FCI Algorithm Final Skeleton}{32}{section.5.4}% 133 | \defcounter {refsection}{0}\relax 134 | \contentsline {section}{\numberline {5.5}FCI Algorithm Edge Orientation}{33}{section.5.5}% 135 | \defcounter {refsection}{0}\relax 136 | \contentsline {section}{\numberline {5.6}Run Speed}{33}{section.5.6}% 137 | \defcounter {refsection}{0}\relax 138 | \contentsline {chapter}{\numberline {6}Conclusion}{35}{chapter.6}% 139 | \defcounter {refsection}{0}\relax 140 | \contentsline {section}{\numberline {6.1}Further Work}{35}{section.6.1}% 141 | \defcounter {refsection}{0}\relax 142 | \contentsline {chapter}{\numberline {A}Appendix}{39}{appendix.A}% 143 | \defcounter {refsection}{0}\relax 144 | \contentsline {section}{\numberline {A.1}UML Class Diagram}{39}{section.A.1}% 145 | \defcounter {refsection}{0}\relax 146 | \contentsline {section}{\numberline {A.2}Epics}{39}{section.A.2}% 147 | \defcounter {refsection}{0}\relax 148 | \contentsline {section}{\numberline {A.3}User Stories}{40}{section.A.3}% 149 | \defcounter {refsection}{0}\relax 150 | \contentsline {section}{\numberline {A.4}Sprints and Tasks}{41}{section.A.4}% 151 | -------------------------------------------------------------------------------- /src/algorithms.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import itertools 3 | from pandas import DataFrame 4 | from graphs import PDAG 5 | 6 | class GraphLearner(object): 7 | """ 8 | Base Class for all graph learning algorithms 9 | implementing functionality used across algorithms 10 | """ 11 | 12 | def __init__(self, data, indep_test, alpha = 0.05): 13 | """ 14 | Initialise graph learner object 15 | Parameters 16 | ---------- 17 | data : pandas.DataFrame, 18 | DataFrame with rows as datapoints and columns as variables 19 | indep_test : function 20 | A function which can calculate indpendence of variabkles in data 21 | alpha : float, optional 22 | The minimum p-value returned by the indepence test 23 | for the data to be considered independent 24 | """ 25 | self.alpha = alpha 26 | self.data = data 27 | self.indep_test = indep_test 28 | 29 | def learnSkeleton(self): 30 | """ A function to build the skeleton of a causal graph from data 31 | 32 | Returns 33 | ------- 34 | networkx.Graph 35 | The skeleton of the causal network 36 | dict 37 | Dicitonary containg separation sets of all pairs of nodes 38 | """ 39 | 40 | # Find variable labels 41 | labels = list(self.data.columns) 42 | # Generate completed graph 43 | graph = nx.complete_graph(len(labels)) 44 | #Rename nodes in graph with labels 45 | name_map = {i:label for i,label in enumerate(labels)} 46 | graph = nx.relabel_nodes(graph, name_map) 47 | sepset = {} 48 | condsize = 0 49 | for x in graph: 50 | for y in graph.neighbors(x): 51 | sepset[(x,y)] = () 52 | sepset[(y,x)] = () 53 | # Iterate over each pair of adjacent nodes 54 | condlen = 1 55 | while condlen != 0: 56 | condlen = 0 57 | ylabels = labels.copy() 58 | for x in labels: 59 | for y in labels: 60 | if y in graph.neighbors(x): 61 | # Generate the conditioning sets needed for independence tests 62 | condSets = self.gen_cond_sets(x,y,graph,condsize) 63 | if not len(condSets) == 0: 64 | condlen += len(condSets) 65 | # Test for independence with each conditioning set 66 | for condset in condSets: 67 | print('testing {} indep {} given {}'.format(x,y,condset)) 68 | p, *_ = self.indep_test(self.data, x, y, condset) 69 | indep = p > self.alpha 70 | #stop testing if independence is found and remove edge 71 | if indep: 72 | print('removing edge {},{}, with certainty {}'.format(x,y,p)) 73 | graph.remove_edge(x,y) 74 | sepset[(x,y)] = condset 75 | sepset[(y,x)] = condset 76 | break 77 | condsize += 1 78 | return graph, sepset 79 | 80 | def gen_cond_sets(self, x,y, g, size): 81 | """ A function to build the set of conditioning sets to be for variables x and y 82 | on graph g of a certain size when generating a skeleton 83 | 84 | Parameters 85 | ---------- 86 | X : str, 87 | One variable being tested for independence, 88 | Y : str 89 | The other variable being tested for independence 90 | graph : float, optional 91 | The minimum p-value returned by the indepence test 92 | for the data to be considered independent 93 | size: int 94 | the size of each conditioning set to be returned 95 | Returns 96 | ------- 97 | list of lists of strings 98 | a list of conditioning sets to be tested 99 | """ 100 | # Handle size 0 case 101 | if size == 0: 102 | return [()] 103 | # Get all neighbors of x in g 104 | adjy = g.neighbors(x) 105 | # Remove y from neighbour list 106 | adj = [node for node in adjy if node!= y] 107 | # Generate all unique combinations of len size 108 | combos = itertools.combinations(adj, size) 109 | # Convert to list 110 | combos = [combo for combo in combos] 111 | return combos 112 | 113 | def orientEdges(self): 114 | pass 115 | 116 | @staticmethod 117 | def prepare_data(data_file, delim = ' ', isLabeled = False, ): 118 | """ 119 | A function which reads data from a file into a pandas dataframe 120 | the file should consist of rows of datapoints with each variable 121 | separated by some delimination string 122 | 123 | Parameters 124 | ---------- 125 | data_file : str, 126 | The path to the file containing data 127 | delim : str, optional 128 | the deliminating string, ',' for csv files 129 | isLabeled : bool, optional 130 | True if the first line in the file is the lit of variabe names 131 | Returns 132 | ------- 133 | pandas.DataFrame 134 | data frame containing data from file 135 | """ 136 | 137 | with open(data_file, 'r') as f: 138 | if isLabeled: 139 | labels = f.readline().replace('\n','').split(delim) 140 | line1 = f.readline().replace('\n','').split(delim) 141 | else: 142 | line1 = f.readline().replace('\n','').split(delim) 143 | labels = [str(i) for i in range(len(line1))] 144 | data = [] 145 | data.append(line1) 146 | for line in f.readlines(): 147 | line = line.replace('\n','').split(delim) 148 | data.append(line) 149 | data = DataFrame(data, columns = labels) 150 | return data 151 | 152 | 153 | def orient_V(self, undirected, directed, sepset): 154 | """ 155 | A method to orient all "V-structures" in a graph 156 | 157 | Parameters 158 | ---------- 159 | undirected: nx.Graph 160 | graph containing the undirected edges 161 | directed: nx.DiGraph 162 | graph containing the directed edges 163 | sepset: Dict 164 | dictionary with pairs of nodes as keys and 165 | seperating sets of nodes as values 166 | """ 167 | skeleton = undirected.copy() 168 | for i in undirected: 169 | for j in undirected: 170 | if i != j: 171 | for k in undirected: 172 | if i != k and j != k: 173 | if skeleton.has_edge(i,k) and skeleton.has_edge(k,j) and not skeleton.has_edge(i,j) and k not in sepset[(i,j)]: 174 | directed.add_edge(j,k) 175 | if directed.has_edge(k,j): 176 | directed.remove_edge(k,j) 177 | if undirected.has_edge(j,k): 178 | undirected.remove_edge(j,k) 179 | directed.add_edge(i,k) 180 | if directed.has_edge(k,i): 181 | directed.remove_edge(k,i) 182 | if undirected.has_edge(i,k): 183 | undirected.remove_edge(i,k) 184 | 185 | @staticmethod 186 | def findPath( x,y, directed, explored): 187 | """ 188 | A method to check if there is a path between two nodes in graph 189 | ---------- 190 | x: str 191 | from node of a path 192 | y: str 193 | to node of a path 194 | directed: nx.DiGraph 195 | Directed graph 196 | explored: str[] 197 | list of nodes explored by previous recursive calls left as [] in calling 198 | 199 | Returns 200 | ------- 201 | bool 202 | True if there is a path between x and y in directed 203 | """ 204 | 205 | explored.append(x) 206 | neigh = [] 207 | for n in directed.successors(x): 208 | neigh.append(n) 209 | Z = [] 210 | for n in neigh: 211 | if n not in explored: 212 | Z.append(n) 213 | if y in Z: 214 | return True 215 | if len(Z) == 0: 216 | return False 217 | isPath = False 218 | for z in Z: 219 | zcont = GraphLearner.findPath(z,y, directed, explored) 220 | isPath = isPath or zcont 221 | return isPath -------------------------------------------------------------------------------- /Docmentation/Report.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | @article{ZHANG20081873, 4 | title = "On the completeness of orientation rules for causal discovery in the presence of latent confounders and selection bias", 5 | journal = "Artificial Intelligence", 6 | volume = "172", 7 | number = "16", 8 | pages = "1873 - 1896", 9 | year = "2008", 10 | issn = "0004-3702", 11 | doi = "https://doi.org/10.1016/j.artint.2008.08.001", 12 | url = "http://www.sciencedirect.com/science/article/pii/S0004370208001008", 13 | author = "Jiji Zhang", 14 | keywords = "Ancestral graphs, Automated causal discovery, Bayesian networks, Causal models, Markov equivalence, Latent variables" 15 | } 16 | 17 | @incollection{verma1990causal, 18 | title={Causal networks: Semantics and expressiveness}, 19 | author={Verma, Thomas and Pearl, Judea}, 20 | booktitle={Machine Intelligence and Pattern Recognition}, 21 | volume={9}, 22 | pages={69--76}, 23 | year={1990}, 24 | publisher={Elsevier} 25 | } 26 | 27 | @article{kalisch2007estimating, 28 | title={Estimating high-dimensional directed acyclic graphs with the PC-algorithm}, 29 | author={Kalisch, Markus and B{\"u}hlmann, Peter}, 30 | journal={Journal of Machine Learning Research}, 31 | volume={8}, 32 | number={Mar}, 33 | pages={613--636}, 34 | year={2007} 35 | } 36 | @article{colombo2012learning, 37 | title={Learning high-dimensional directed acyclic graphs with latent and selection variables}, 38 | author={Colombo, Diego and Maathuis, Marloes H and Kalisch, Markus and Richardson, Thomas S}, 39 | journal={The Annals of Statistics}, 40 | pages={294--321}, 41 | year={2012}, 42 | publisher={JSTOR} 43 | } 44 | 45 | @article{colombo2012learning2, 46 | title={Supplement to “Learning high-dimensional directed acyclic graphs with latent and selection 47 | variables}, 48 | author={Colombo, Diego and Maathuis, Marloes H and Kalisch, Markus and Richardson, Thomas S}, 49 | journal={The Annals of Statistics}, 50 | year={2012}, 51 | publisher={JSTOR} 52 | } 53 | 54 | @article{zhang2008causal, 55 | title={Causal reasoning with ancestral graphs}, 56 | author={Zhang, Jiji}, 57 | journal={Journal of Machine Learning Research}, 58 | volume={9}, 59 | number={Jul}, 60 | pages={1437--1474}, 61 | year={2008} 62 | } 63 | @article{geiger1990identifying, 64 | title={Identifying independence in Bayesian networks}, 65 | author={Geiger, Dan and Verma, Thomas and Pearl, Judea}, 66 | journal={Networks}, 67 | volume={20}, 68 | number={5}, 69 | pages={507--534}, 70 | year={1990}, 71 | publisher={Wiley Online Library} 72 | } 73 | 74 | @inproceedings{spirtes2001anytime, 75 | title={An Anytime Algorithm for Causal Inference.}, 76 | author={Spirtes, Peter} 77 | } 78 | 79 | @article{pearl2003causality, 80 | title={Causality: models, reasoning, and inference}, 81 | author={Pearl, Judea}, 82 | journal={Econometric Theory}, 83 | volume={19}, 84 | number={675-685}, 85 | pages={46}, 86 | year={2003} 87 | } 88 | 89 | @article{pearl2009, 90 | 91 | doi = "10.1214/09-SS057", 92 | fjournal = "Statistics Surveys", 93 | journal = "Statist. Surv.", 94 | pages = "96--146", 95 | publisher = "The American Statistical Association, the Bernoulli Society, the Institute of Mathematical Statistics, and the Statistical Society of Canada", 96 | title = "Causal inference in statistics: An overview", 97 | url = "https://doi.org/10.1214/09-SS057", 98 | volume = "3", 99 | author ="Judea Pearl", 100 | year = "2009" 101 | } 102 | 103 | @article{scheines1997introduction, 104 | title={An introduction to causal inference}, 105 | author={Scheines, Richard}, 106 | publisher={Citeseer} 107 | } 108 | 109 | @article{spirtes1991algorithm, 110 | title={An algorithm for fast recovery of sparse causal graphs}, 111 | author={Spirtes, Peter and Glymour, Clark}, 112 | journal={Social science computer review}, 113 | volume={9}, 114 | number={1}, 115 | pages={62--72}, 116 | year={1991}, 117 | publisher={Sage Publications Sage CA: Thousand Oaks, CA} 118 | } 119 | 120 | @misc{kalisch_hauser_maechler, 121 | title={Methods for Graphical Models and Causal Inference [R package pcalg version 2.6-0]}, 122 | url={https://cran.r-project.org/web/packages/pcalg/index.html}, 123 | journal={The Comprehensive R Archive Network}, 124 | publisher={Comprehensive R Archive Network (CRAN)}, 125 | author={Kalisch, Markus and Hauser, Alain and Maechler , Martin} 126 | } 127 | 128 | @misc{piatetsky, title={KDnuggets}, url={https://www.kdnuggets.com/2018/05/poll-tools-analytics-data-science-machine-learning-results.html}, journal={KDnuggets Analytics Big Data Data Mining and Data Science}, author={Piatetsky, Gregory}} 129 | 130 | @misc{ogrady_2019, title={The RedMonk Programming Language Rankings: January 2019}, url={https://redmonk.com/sogrady/2019/03/20/language-rankings-1-19/}, journal={tecosystems}, author={O'Grady , Stephen}, year={2019}, month={Mar}} 131 | 132 | @article{Pearson, 133 | author = { Karl Pearson F.R.S. }, 134 | title = {X. On the criterion that a given system of deviations from the probable in the case of a correlated system of variables is such that it can be reasonably supposed to have arisen from random sampling}, 135 | journal = {The London, Edinburgh, and Dublin Philosophical Magazine and Journal of Science}, 136 | volume = {50}, 137 | number = {302}, 138 | pages = {157-175}, 139 | year = {1900}, 140 | publisher = {Taylor & Francis}, 141 | doi = {10.1080/14786440009463897}, 142 | 143 | URL = { 144 | https://doi.org/10.1080/14786440009463897 145 | 146 | }, 147 | eprint = { 148 | https://doi.org/10.1080/14786440009463897 149 | 150 | } 151 | 152 | } 153 | 154 | @book{barber_2012, place={Cambridge}, title={Bayesian Reasoning and Machine Learning}, DOI={10.1017/CBO9780511804779}, publisher={Cambridge University Press}, author={Barber, David}, year={2012}} 155 | 156 | 157 | @inproceedings{royce1987managing, 158 | title={Managing the development of large software systems: concepts and techniques}, 159 | author={Royce, Winston W}, 160 | booktitle={Proceedings of the 9th international conference on Software Engineering}, 161 | pages={328--338}, 162 | year={1987}, 163 | organization={IEEE Computer Society Press} 164 | } 165 | 166 | @misc{beck2001agile, 167 | added-at = {2007-12-30T11:39:05.000+0100}, 168 | author = {Beck, Kent and Beedle, Mike and van Bennekum, Arie and Cockburn, Alistair and Cunningham, Ward and Fowler, Martin and Grenning, James and Highsmith, Jim and Hunt, Andrew and Jeffries, Ron and Kern, Jon and Marick, Brian and Martin, Robert C. and Mellor, Steve and Schwaber, Ken and Sutherland, Jeff and Thomas, Dave}, 169 | biburl = {https://www.bibsonomy.org/bibtex/28954248a545d88dd2c0e688d1c7e2f9d/juve}, 170 | booktitle = {Manifesto for Agile Software Development}, 171 | description = {Manifesto for Agile Software Development}, 172 | interhash = {098cc7e185f10c3da390459a01e0d535}, 173 | intrahash = {8954248a545d88dd2c0e688d1c7e2f9d}, 174 | keywords = {imported}, 175 | timestamp = {2007-12-30T11:39:05.000+0100}, 176 | title = {Manifesto for Agile Software Development}, 177 | url = {http://www.agilemanifesto.org/}, 178 | year = 2001 179 | } 180 | 181 | @article{boehm1988spiral, 182 | title={A spiral model of software development and enhancement}, 183 | author={Boehm, Barry W}, 184 | journal={Computer}, 185 | number={5}, 186 | pages={61--72}, 187 | year={1988}, 188 | publisher={IEEE} 189 | } 190 | 191 | @incollection{schwaber1997scrum, 192 | title={Scrum development process}, 193 | author={Schwaber, Ken}, 194 | booktitle={Business object design and implementation}, 195 | pages={117--134}, 196 | year={1997}, 197 | publisher={Springer} 198 | } 199 | 200 | @book{cohn2004user, 201 | title={User stories applied: For agile software development}, 202 | author={Cohn, Mike}, 203 | year={2004}, 204 | publisher={Addison-Wesley Professional} 205 | } 206 | 207 | @article{janzen2005test, 208 | title={Test-driven development concepts, taxonomy, and future direction}, 209 | author={Janzen, David and Saiedian, Hossein}, 210 | journal={Computer}, 211 | volume={38}, 212 | number={9}, 213 | pages={43--50}, 214 | year={2005}, 215 | publisher={IEEE} 216 | } 217 | 218 | @misc{Numpy, title={Example NumPy Style Python Docstrings¶}, url={https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html}, journal={Example NumPy Style Python Docstrings - napoleon 0.7 documentation}} 219 | 220 | @misc{pandas, title={Python Data Analysis Library¶}, url={https://pandas.pydata.org/}, journal={pandas}} 221 | 222 | @misc{networkx, title={NetworkX}, url={https://networkx.github.io/}, journal={NetworkX}} 223 | 224 | @misc{scipy, title={Statistical functions (scipy.stats)¶}, url={https://docs.scipy.org/doc/scipy/reference/stats.html}, journal={Statistical functions (scipy.stats) - SciPy v1.2.1 Reference Guide}} 225 | 226 | @misc{numpy, title={NumPy¶}, url={http://www.numpy.org/}, journal={NumPy}} 227 | 228 | @misc{data, url={https://www.cs.york.ac.uk/aig/sw/gobnilp/data/}, journal={GOBNILP DATA}} 229 | 230 | @misc{cython, title={C-Extensions for Python}, url={https://cython.org/}, journal={Cython}} 231 | 232 | @article{wilbers2009using, 233 | title={Using cython to speed up numerical python programs}, 234 | author={Wilbers, Ilmar M and Langtangen, Hans Petter and {\O}deg{\aa}rd, {\AA}smund}, 235 | journal={Proceedings of MekIT}, 236 | volume={9}, 237 | pages={495--512}, 238 | year={2009} 239 | } 240 | 241 | @misc{wilkinson_2014, title={Gibbs sampler in various languages (revisited)}, url={https://darrenjw.wordpress.com/2011/07/16/gibbs-sampler-in-various-languages-revisited/}, journal={Darren Wilkinson's research blog}, publisher={Gibbs sampler in various languages }, author={Wilkinson, Darren j}, year={2014}, month={Nov}} 242 | 243 | 244 | @article{colombo2014order, 245 | title={Order-independent constraint-based causal structure learning}, 246 | author={Colombo, Diego and Maathuis, Marloes H}, 247 | journal={The Journal of Machine Learning Research}, 248 | volume={15}, 249 | number={1}, 250 | pages={3741--3782}, 251 | year={2014}, 252 | publisher={JMLR. org} 253 | } 254 | -------------------------------------------------------------------------------- /src/.Rhistory: -------------------------------------------------------------------------------- 1 | pc() 2 | install.packages("pcalg") 3 | pcalg::pc 4 | pcalg::pc() 5 | pcalg::help() 6 | pcalg 7 | pcalg.help 8 | pcalg.help() 9 | pcalg.pc() 10 | pc 11 | usepckage(rbn) 12 | usepackage(rbn) 13 | package(rbn) 14 | install.packages("ibn") 15 | install.packages(rbn) 16 | install.packages("pcalg") 17 | data(gmG#) 18 | ) 19 | data(gmB) 20 | (pcalg::gmB) 21 | library(pcalg) 22 | install.packages("graph") 23 | if (!requireNamespace("BiocManager", quietly = TRUE)) 24 | install.packages("BiocManager") 25 | BiocManager::install("graph", version = "3.8") 26 | library(pcalg) 27 | install.packages("RBGL") 28 | if (!requireNamespace("BiocManager", quietly = TRUE)) 29 | install.packages("BiocManager") 30 | BiocManager::install("RBGL") 31 | library(pcalg) 32 | data(gmB) 33 | pc.B <- pc(suffStat = list(dm = gmB$x, adaptDF = FALSE), 34 | indepTest = binCItest, alpha = 0.01, labels = V, verbose = TRUE) 35 | V <- colnames(gmB$x) 36 | pc.B <- pc(suffStat = list(dm = gmB$x, adaptDF = FALSE), 37 | indepTest = binCItest, alpha = 0.01, labels = V, verbose = TRUE) 38 | pc.B 39 | pc.B.edges 40 | pc.B$edges 41 | pc.B 42 | pc.B.amat 43 | pc.B$amat 44 | amat(pc.B) 45 | pc.B.G 46 | pc.B 47 | print(pc.B) 48 | show(pc.B) 49 | print(pc.B, amat = True) 50 | print(pc.B, amat = TRUE) 51 | library(pcalg) 52 | if (!requireNamespace("BiocManager", quietly = TRUE)) 53 | install.packages("BiocManager") 54 | BiocManager::install("graph", version = "3.8") 55 | library(pcalg) 56 | if (!requireNamespace("BiocManager", quietly = TRUE)) 57 | install.packages("BiocManager") 58 | BiocManager::install("RBGL", version = "3.8") 59 | library(pcalg) 60 | data("gmB") 61 | n <- nrow(gmB8$x) 62 | n <- nrow(gmB$x) 63 | V <- colnames(gmB$x) 64 | V 65 | n 66 | skel.fit <- skeleton(suffStat = list(C = cor(gmG8$x), n = n), 67 | indepTest = gaussCItest, ## (partial correlations) 68 | alpha = 0.01, labels = V, verbose = TRUE) 69 | skel.fit <- skeleton(suffStat = list(C = cor(gmB$x), n = n), 70 | indepTest = gaussCItest, ## (partial correlations) 71 | alpha = 0.01, labels = V, verbose = TRUE) 72 | X <- gmB$x 73 | skel.fm2 <- skeleton(suffStat = list(dm = X, adaptDF = FALSE), 74 | indepTest = binCItest, alpha = 0.01, 75 | labels = colnames(X), verbose = TRUE) 76 | skel 77 | skel.fm2 78 | if (require(Rgraphviz)) { 79 | ## show estimated Skeleton 80 | par(mfrow = c(1,2)) 81 | plot(skel.fm2, main = "Binary Data 'gmB': Estimated Skeleton") 82 | plot(gmB$g, main = "True DAG") 83 | } 84 | install.packages("Rgraphviz") 85 | if (!requireNamespace("BiocManager", quietly = TRUE)) 86 | install.packages("BiocManager") 87 | BiocManager::install("Rgraphviz", version = "3.8") 88 | if (require(Rgraphviz)) { 89 | ## show estimated Skeleton 90 | par(mfrow = c(1,2)) 91 | plot(skel.fm2, main = "Binary Data 'gmB': Estimated Skeleton") 92 | plot(gmB$g, main = "True DAG") 93 | } 94 | show(skel.fm2) 95 | str(ss <- pc.fit@sepset, max=1) 96 | show(skel.fm2@sepset) 97 | show(skel.fm2@sepset[[1][3]]) 98 | show(skel.fm2@sepset[[1]][[3]]) 99 | show(skel.fm2@sepset[[1]][[4]]) 100 | show(skel.fm2@sepset[[1]][[5]]) 101 | show(skel.fm2@sepset[[1]][[1]]) 102 | show(skel.fm2@sepset[[2]][[1]]) 103 | show(skel.fm2@sepset[[3]][[1]]) 104 | show(skel.fm2@sepset[[2]][[3]]) 105 | show(skel.fm2@sepset[[4]][[5]]) 106 | data(gmB) 107 | V <- colnames(gmB$x) 108 | ## estimate CPDAG 109 | pc.B <- pc(suffStat = list(dm = gmB$x, adaptDF = FALSE), 110 | indepTest = binCItest, alpha = 0.01, labels = V, verbose = TRUE) 111 | pc.B 112 | if (require(Rgraphviz)) { 113 | ## show estimated CPDAG 114 | plot(pc.B, main = "Estimated CPDAG") 115 | plot(gmB$g, main = "True DAG") 116 | } 117 | alarm_10000 <- read.csv("~/Fourth Year/Learning-Causal-Networks-in-Python/src/alarm_10000.dat", sep="") 118 | View(alarm_10000) 119 | alarm_10000$PULMEMBOLUS 120 | table(alarm_10000$PULMEMBOLUS, alarm_10000$PAP) 121 | cont <- table(alarm_10000$PULMEMBOLUS, alarm_10000$PAP) 122 | chisq <- chisq.test(cont) 123 | chisq 124 | cont <- table(alarm_10000$EXPCO2, alarm_10000$PAP) 125 | chisq <- chisq.test(cont) 126 | chisq 127 | cont <- table(alarm_10000$EXPCO2, alarm_10000$PULMEMBOLUS) 128 | chisq <- chisq.test(cont) 129 | chisq 130 | library(bnlearn) 131 | install.packages("bnlearn") 132 | indep<-ci.test("EXPCO", "PULMEMBOLUS"x2, NULL, alarm_10000, "x2") 133 | indep <- ci.test("EXPCO", "PULMEMBOLUS"x2, NULL, alarm_10000, "x2") 134 | indep <- ci.test("EXPCO", "PULMEMBOLUS", x2, NULL, alarm_10000, "x2") 135 | library(bnlearn) 136 | indep <- ci.test("EXPCO", "PULMEMBOLUS", x2, NULL, alarm_10000, "x2") 137 | View(alarm_10000) 138 | View(alarm_10000) 139 | indep <- ci.test("EXPCO", "PULMEMBOLUS", x2, NULL, alarm_10000, "x2") 140 | indep <- ci.test("EXPCO", "PULMEMBOLUS", NULL, alarm_10000, "x2") 141 | indep <- ci.test("EXPCO", "PULMEMBOLUS", NULL, alarm_10000, "x2") 142 | typeof(alarm_10000$PULMEMBOLUS) 143 | typeof(alarm_10000$EXPCO2) 144 | class(alarm_10000$EXPCO2) 145 | df[,'PULMEMBOLUS']<-factor(df[,'PULMEMBOLUS']) 146 | df[,'PULMEMBOLUS'] 147 | df['PULMEMBOLUS'] 148 | df$PULMEMBOLUS <- factor(df$PULMEMBOLUS) 149 | indep <- ci.test("EXPCO", "PULMEMBOLUS", NULL, alarm_10000, "x2", 10, TRUE) 150 | dat <- alarm_10000 151 | dat[] <- lapply(dat, as.factor) 152 | indep <- ci.test("EXPCO", "PULMEMBOLUS", NULL, dat, "x2", 10, TRUE) 153 | dat 154 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", NULL, dat, "x2", 10, TRUE) 155 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", c(), dat, "x2", 10, TRUE) 156 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", z=NULL, dat, "x2", 10, TRUE) 157 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", c(NULL), dat, "x2", 10, TRUE) 158 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", numeric(), dat, "x2", 10, TRUE) 159 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", list(), dat, "x2", 10, TRUE) 160 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", c(''), dat, "x2", 10, TRUE) 161 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", data=dat, test="x2", B=10, debug=TRUE) 162 | indep 163 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", c("PAP") data=dat, test="x2", B=10, debug=TRUE) 164 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", c("PAP"), data=dat, test="x2", B=10, debug=TRUE) 165 | indep 166 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", c("PAP"), data=dat, test="x2", debug=TRUE) 167 | indep 168 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", c("KINKEDTUBE"), data=dat, test="x2", debug=TRUE) 169 | indep 170 | cont <- table(alarm_10000$EXPCO2, alarm_10000$PULMEMBOLUS, alarm_10000$PAP) 171 | cont 172 | indep <- ci.test("EXPCO2", "PULMEMBOLUS", "KINKEDTUBE", data=dat, test="x2", debug=TRUE) 173 | indep 174 | View(chisq) 175 | chisq <- ci.test('EXPCO2', 'PULMEMBOLUS', ['PAP'], data = alarm_10000, test='chi') 176 | chisq <- ci.test('EXPCO2', 'PULMEMBOLUS', 'PAP', data = alarm_10000, test='chi') 177 | library(bnlearn) 178 | chisq <- ci.test('EXPCO2', 'PULMEMBOLUS', 'PAP', data = alarm_10000, test='chi') 179 | alarm_10000 <- as.factor(alarm_10000) 180 | chisq <- ci.test('EXPCO2', 'PULMEMBOLUS', 'PAP', data = alarm_10000, test='chi') 181 | dat <- as.factor(dat) 182 | chisq <- ci.test('EXPCO2', 'PULMEMBOLUS', 'PAP', data = dat, test='chi') 183 | alarm_10000 <- read.csv("~/Fourth Year/Learning-Causal-Networks-in-Python/src/alarm_10000.dat", sep="") 184 | View(alarm_10000) 185 | df <- alarm_10000 186 | df[] <- lapply( df, factor) # the "[]" keeps the dataframe structure 187 | col_names <- names(df) 188 | # do do it for some names in a vector named 'col_names' 189 | df[col_names] <- lapply(df[col_names] , factor) 190 | chisq <- ci.test('EXPCO2', 'PULMEMBOLUS', 'PAP', data = df, test='chi') 191 | chisq <- ci.test('EXPCO2', 'PULMEMBOLUS', 'PAP', data = df, test='x2') 192 | chisq 193 | chisq <- ci.test('EXPCO2', 'PULMEMBOLUS', c('PAP','KINKEDTUBE', data = df, test='x2') 194 | ) 195 | chisq <- ci.test('EXPCO2', 'PULMEMBOLUS', c('PAP','KINKEDTUBE'), data = df, test='x2') 196 | chisq 197 | install.packages("pcalg") 198 | df[0] 199 | df[0].label 200 | row.names(df) 201 | cols.names(df) 202 | col.names(df) 203 | colnames(df) 204 | colnames(df)[0] 205 | colnames(df)[1] 206 | colnames(df)[1,3] 207 | colnames(df)[1][3] 208 | colnames(df)[(1,3)] 209 | colnames(df)[1:3] 210 | ciTest.R 211 | library(bnlearn) 212 | View(df) 213 | ciIndep(1,2,3, df) 214 | source('ciTest.r') 215 | source('\\userfs\jc1850\w2k\Fourth Year\Learning-Causal-Networks-in-Python\src\ciTest.r') 216 | source('/userfs/jc1850\w2k\Fourth Year\Learning-Causal-Networks-in-Python\src\ciTest.r') 217 | source('/userfs/jc1850/w2k/Fourth Year/Learning-Causal-Networks-in-Python/src/ciTest.r') 218 | cd 219 | setwd("~/Fourth Year/Learning-Causal-Networks-in-Python/src") 220 | source('ciTest.R') 221 | source('ciTest.R') 222 | ciIndep(1,2,3,df) 223 | ciIndep(1,2,3,df) 224 | source('ciTest.R') 225 | ciIndep(1,2,3,df) 226 | ciIndep(1,2,3,df) 227 | source('ciTest.R') 228 | ciIndep(1,2,3,df) 229 | ciIndep(1,2,[3],df) 230 | ciIndep(1,2,c(3),df) 231 | source('ciTest.R') 232 | ciIndep(1,2,c(3),df) 233 | source('ciTest.R') 234 | ciIndep(1,2,c(3),df) 235 | source('ciTest.R') 236 | ciIndep(1,2,c(3),df) 237 | source('ciTest.R') 238 | ciIndep(1,2,c(3),df) 239 | ciIndep(1,2,c(3),df) 240 | source('ciTest.R') 241 | ciIndep(1,2,c(3),df) 242 | ciIndep(1,2,c(3),df) 243 | source('ciTest.R') 244 | ciIndep(1,2,c(3),df) 245 | source('ciTest.R') 246 | ciIndep(1,2,c(3),df) 247 | source('ciTest.R') 248 | ciIndep(1,2,c(3),df) 249 | ciIndep(1,2,c(3),df) 250 | source('ciTest.R') 251 | ciIndep(1,2,c(3),df) 252 | colnames(df)[25] 253 | colnames(df)[30] 254 | ciIndep(1,2,c(30),df) 255 | ciIndep(1,30,c(2),df) 256 | pc(df, ciIndep, 0.95) 257 | pc(df, ciIndep, 0.95, labels= colnames(df), p=37) 258 | pc(df, ciIndep, 0.95, labels= colnames(df)) 259 | pc(df, ciIndep, 0.95, labels= colnames(df)) 260 | source('ciIndep') 261 | source('ciIndep.R') 262 | source('ciTest.R') 263 | source('ciTest.R') 264 | pc(df, ciIndep, 0.95, labels= colnames(df)) 265 | source('ciTest.R') 266 | pc(df, ciIndep, 0.95, labels= colnames(df)) 267 | source('ciTest.R') 268 | pc(df, ciIndep, 0.95, labels= colnames(df)) 269 | pc(df, ciIndep, 0.95, labels= colnames(df)) 270 | source('ciTest.R') 271 | pc(df, ciIndep, 0.95, labels= colnames(df)) 272 | ci.test('PULMEMBOLUS', 'EXPCO2', 'PAP', df) 273 | ci.test('PULMEMBOLUS', 'EXPCO2', df) 274 | ci.test('PULMEMBOLUS', 'EXPCO2', z=NULL, df) 275 | ci.test('PULMEMBOLUS', 'EXPCO2', z=c(), df) 276 | ci.test('PULMEMBOLUS', 'EXPCO2', z=c(), df) 277 | ci.test('PULMEMBOLUS', 'EXPCO2', z='', df) 278 | ci.test('PULMEMBOLUS', 'EXPCO2', z=, df) 279 | ci.test('PULMEMBOLUS', 'EXPCO2', data=df) 280 | source('ciTest.R') 281 | pc(df, ciIndep, 0.95, labels= colnames(df)) 282 | source('ciTest.R') 283 | pc(df, ciIndep, 0.95, labels= colnames(df)) 284 | source('~/Fourth Year/Learning-Causal-Networks-in-Python/src/ciTest.R') 285 | pc(df, ciIndep, 0.95, labels= colnames(df)) 286 | source('~/Fourth Year/Learning-Causal-Networks-in-Python/src/ciTest.R') 287 | source('~/Fourth Year/Learning-Causal-Networks-in-Python/src/ciTest.R') 288 | pc(df, ciIndep, 0.95, labels= colnames(df)) 289 | source('~/Fourth Year/Learning-Causal-Networks-in-Python/src/ciTest.R') 290 | pc(df, ciIndep, 0.95, labels= colnames(df)) 291 | df[] 292 | pc(df[], ciIndep, 0.95, labels= colnames(df)) 293 | pc<-pc(df[], ciIndep, 0.95, labels= colnames(df)) 294 | pc 295 | skeleton 296 | pc:skel.fit 297 | pcalg::skeleton() 298 | pcalg::skeleton 299 | skeleton <- pcalg::skeleton() 300 | skeleton <- pcalg::skeleton 301 | pc<-pc(df[], ciIndep, 0.95, labels= colnames(df)) 302 | source('~/Fourth Year/Learning-Causal-Networks-in-Python/src/ciTest.R') 303 | pc<-pc(df[], ciIndep, 0.95, labels= colnames(df)) 304 | chisq 305 | data(asia) 306 | -------------------------------------------------------------------------------- /src/fci.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | from graphs import PAG 3 | from algorithms import GraphLearner 4 | import itertools 5 | from indepTests import chi 6 | import copy 7 | import sys 8 | 9 | class FCIAlg(GraphLearner): 10 | """ 11 | A graph learner which implements the FCI algorithm 12 | """ 13 | 14 | def orientEdges(self, skeleton, sepSet): 15 | """ 16 | A function to orient the edges of a skeleton using the orientation rules of the FCI algorithm 17 | Parameters 18 | ---------- 19 | skeleton: networkx Graph(), 20 | skeleton estimation 21 | sepSet: dict 22 | Dicitonary containg separation sets of all pairs of nodes 23 | 24 | Returns 25 | ------- 26 | PAG containing estimated causal relationships in data 27 | 28 | """ 29 | pag = PAG() 30 | pag.add_nodes_from(skeleton) 31 | pag.add_edges_from(skeleton.edges) 32 | self.orient_V(pag, sepSet) 33 | old_pag = nx.DiGraph() 34 | while old_pag.edges != pag.edges: 35 | old_pag = copy.deepcopy(pag) 36 | for i in pag: 37 | for j in pag: 38 | for k in pag: 39 | if k not in [i,j] and j != i: 40 | self.rule1(pag,i,j,k) 41 | self.rule2(pag,i,j,k) 42 | for l in pag: 43 | if l not in [i,j,k]: 44 | self.rule3(pag,i,j,k,l) 45 | self.rule4(pag,i,j,k,l, sepSet) 46 | self.rule5(pag,i,j,k,l) 47 | self.rule67(pag,i,j,k) 48 | self.rule8(pag,i,j,k) 49 | self.rule9(pag,i,j,k,l) 50 | self.rule10(pag,i,j,k,l) 51 | return pag 52 | 53 | def learnSkeleton(self): 54 | """ A function to build the skeleton of a causal graph from data 55 | 56 | Returns 57 | ------- 58 | PDAG 59 | The skeleton of the causal network 60 | dict 61 | Dicitonary containg separation sets of all pairs of nodes 62 | 63 | """ 64 | 65 | skeleton, sepSet = super().learnSkeleton() 66 | pag = PAG() 67 | pag.add_nodes_from(skeleton) 68 | pag.add_edges_from(skeleton.edges) 69 | print('finalising skeleton') 70 | self.orient_V(pag, sepSet) 71 | dseps = self.possible_d_seps( pag) 72 | pag.write_to_file('tmp') 73 | print(dseps) 74 | for x in pag: 75 | for y in pag: 76 | if y in pag.neighbors(x): 77 | indep = False 78 | for i in range(1,len(dseps[x])+1): 79 | for dsepset in itertools.combinations(dseps[x],i): 80 | indep = False 81 | dsepset = list(dsepset) 82 | if y in dsepset: 83 | dsepset.remove(y) 84 | if len(dsepset )>= 1: 85 | print('testing {} indep {} given {}'.format(x,y,dsepset) ) 86 | p, *_ = self.indep_test(self.data, x, y, dsepset) 87 | indep = p > self.alpha 88 | #stop testing if independence is found and remove edge 89 | if indep: 90 | print('removing edge {},{}'.format(x,y)) 91 | pag.remove_edge(x,y) 92 | sepSet[(x,y)] = dsepset 93 | sepSet[(y,x)] = dsepset 94 | break 95 | if indep: 96 | break 97 | if indep: 98 | break 99 | return pag, sepSet 100 | 101 | def orient_V(self, pag, sepSet): 102 | """ 103 | A function to orient the colliders in a PAG 104 | 105 | Parameters 106 | ---------- 107 | pag: PAG 108 | PAG to be oriented 109 | sepSet: dict 110 | separation d#sets of all pairs of nodes in PAG 111 | Returns 112 | ------- 113 | PAG 114 | PAG with v-structures oriented 115 | """ 116 | for i in pag: 117 | for j in pag: 118 | if j != i: 119 | for k in pag: 120 | if k not in [i,j]: 121 | if pag.has_edge(i,j) and pag.has_edge(k,j) and not pag.has_edge(i,k): 122 | if j not in sepSet[(i,k)]: 123 | pag.direct_edge(i,j) 124 | pag.direct_edge(k,j) 125 | print('Orienting collider {}, {}, {}'.format(i,j,k)) 126 | 127 | def learnGraph(self): 128 | """ 129 | function to learn a causal network from data 130 | 131 | Returns 132 | ------- 133 | PAG 134 | causal network learned from data 135 | """ 136 | print('Learning Skeleton of graph...') 137 | skeleton, sepset = self.learnSkeleton() 138 | print('...Skeleton learnt') 139 | print('Orienting Edges...') 140 | pag = self.orientEdges(skeleton, sepset) 141 | print('...Learning complete') 142 | return pag 143 | 144 | @staticmethod 145 | def is_possible_d_sep(X,Y, pag): 146 | """ 147 | A function to test if one node is in the possibled sep set of another 148 | 149 | Parameters 150 | ---------- 151 | X: str 152 | one node tested for d seperation 153 | Y: str 154 | other node to be tested 155 | pag: PAG 156 | PAG containing the nodes 157 | Returns 158 | ------- 159 | bool 160 | true if nodes possibly d-sep eachother 161 | """ 162 | all_paths = nx.all_simple_paths(pag,X,Y) 163 | for path in all_paths: 164 | path_sep = True 165 | for i in range(1, len(path[:-1])): 166 | collider = (pag.has_directed_edge(path[i-1],path[i]) and pag.has_directed_edge(path[i+1],path[i])) 167 | triangle = (pag.has_edge(path[i-1],path[i]) and pag.has_edge(path[i+1],path[i]) and pag.has_edge(path[i-1],path[i+1])) 168 | if not(collider or triangle): 169 | path_sep = False 170 | if path_sep: 171 | return True 172 | return False 173 | 174 | @staticmethod 175 | def possible_d_seps(pag): 176 | """ 177 | Method to construct the possible d-sep-set of a pag 178 | 179 | Parameters 180 | ---------- 181 | pag: PAG 182 | PAG to find dseps for 183 | Returns 184 | ------- 185 | dict 186 | keys: nodes 187 | values: nodes which could d seperate other nodes from the key node 188 | 189 | """ 190 | dseps = {} 191 | for i in pag: 192 | dseps[i] = [] 193 | for j in pag: 194 | if i != j: 195 | if FCIAlg.is_possible_d_sep(i,j,pag): 196 | dseps[i].append(j) 197 | return dseps 198 | 199 | @staticmethod 200 | def rule1(pag,i,j,k): 201 | """ 202 | rule 1 of edge orientation in the fci algorithm 203 | 204 | Parameters 205 | ---------- 206 | pag: PAG 207 | PAG to orient edges of 208 | i,j,k: str 209 | nodes to test for orientation rule 210 | """ 211 | if pag.has_directed_edge(i,j) and pag.has_o(j,k,j) and not pag.has_edge(i,k): 212 | pag.fully_direct_edge(j,k) 213 | print('Orienting edge {},{} with rule 1'.format(j,k)) 214 | 215 | @staticmethod 216 | def rule2(pag,i,j,k): 217 | """ 218 | rule 2 of edge orientation in the fci algorithm 219 | 220 | Parameters 221 | ---------- 222 | pag: PAG 223 | PAG to orient edges of 224 | i,j,k: str 225 | nodes to test for orientation rule 226 | """ 227 | chain1 = pag.has_fully_directed_edge(i,j) and pag.has_directed_edge(j,k) 228 | chain2 = pag.has_fully_directed_edge(j,k) and pag.has_directed_edge(i,j) 229 | if (chain1 or chain2) and pag.has_o(i,k,k): 230 | pag.direct_edge(i,k) 231 | print('Orienting edge {},{} with rule 2'.format(i,k)) 232 | 233 | @staticmethod 234 | def rule3(pag,i,j,k,l): 235 | """ 236 | rule 3 of edge orientation in the fci algorithm 237 | 238 | Parameters 239 | ---------- 240 | pag: PAG 241 | PAG to orient edges of 242 | i,j,k,l: str 243 | nodes to test for orientation rule 244 | """ 245 | chain1 = (pag.has_directed_edge(i,j)) and pag.has_directed_edge(k,j) 246 | chain2 = (pag.has_o(i,l,l)) and (pag.has_o(k,l,l)) 247 | if chain1 and chain2 and not pag.has_edge(i,k) and pag.has_o(l,j,j): 248 | pag.direct_edge(l,j) 249 | print('Orienting edge {},{} with rule 3'.format(l,j)) 250 | 251 | @staticmethod 252 | def rule4(pag,i,j,k,l, sepSet): 253 | """ 254 | rule 4 of edge orientation in the fci algorithm 255 | 256 | Parameters 257 | ---------- 258 | pag: PAG 259 | PAG to orient edges of 260 | i,j,k,l: str 261 | nodes to test for orientation rule 262 | """ 263 | paths = pag.findDiscPath(l,k,j) 264 | for path in paths: 265 | if i in path: 266 | if path.index(i) == len(path)-3 and pag.has_o(j,k,j) : 267 | if j in sepSet[(l,k)]: 268 | pag.fully_direct_edge(j,k) 269 | print('Orienting edge {},{} with rule 4'.format(j,k)) 270 | 271 | else: 272 | pag.direct_edge(i,j) 273 | pag.direct_edge(j,k) 274 | pag.direct_edge(j,i) 275 | pag.direct_edge(k,j) 276 | print('Orienting edges {},{}, {},{} with rule 4'.format(i,j,j,k)) 277 | 278 | 279 | @staticmethod 280 | def rule5(pag,i,j,k,l): 281 | """ 282 | rule 5 of edge orientation in the fci algorithm 283 | 284 | Parameters 285 | ---------- 286 | pag: PAG 287 | PAG to orient edges of 288 | i,j,k,l: str 289 | nodes to test for orientation rule 290 | """ 291 | for path in pag.findUncoveredCirclePaths(i,j): 292 | edge = pag.has_o(i,j,j) and pag.has_o(i,j,j) 293 | on_path = False 294 | if l in path and k in path: 295 | on_path = path.index(k) == 1 and path.index(l) == (len(path) - 2) 296 | nonadj = not pag.has_edge(i,l) and not pag.has_edge(k,j) 297 | if edge and on_path and nonadj: 298 | pag.undirect_edge(i,j) 299 | print('Orienting edge {},{} with rule 5'.format(i,j)) 300 | for x in range(len(path)-1): 301 | pag.undirect_edge(path[x], path[x+1]) 302 | print('Orienting edge {},{} with rule 5'.format(path[x], path[x+1])) 303 | 304 | @staticmethod 305 | def rule67(pag,i,j,k): 306 | """ 307 | rules 6 and 7 of edge orientation in the fci algorithm 308 | 309 | Parameters 310 | ---------- 311 | pag: PAG 312 | PAG to orient edges of 313 | i,j,k: str 314 | nodes to test for orientation rule 315 | """ 316 | if pag.has_edge(i,j) and pag.has_edge(j,k): 317 | edge1 = pag.get_edge_data(i,j) 318 | edge2 = pag.get_edge_data(j,k) 319 | if edge1[i] == '-' and edge1[j] == '-' and edge2[j] == 'o': 320 | pag.setTag([j,k],j,'-') 321 | print('Orienting edge {},{} with rule 6'.format(k,j)) 322 | if edge1[i] == '-' and edge1[j] == 'o' and edge2[j] == 'o' and not pag.has_edge(i,k): 323 | pag.setTag([j,k],j,'-') 324 | print('Orienting edge {},{} with rule 7'.format(k,j)) 325 | 326 | 327 | @staticmethod 328 | def rule8(pag,i,j,k): 329 | """ 330 | rule 8 of edge orientation in the fci algorithm 331 | 332 | Parameters 333 | ---------- 334 | pag: PAG 335 | PAG to orient edges of 336 | i,j,k: str 337 | nodes to test for orientation rule 338 | """ 339 | chain1 = pag.has_fully_directed_edge(i,j) and pag.has_fully_directed_edge(j,k)# 340 | chain2 = False 341 | edge = False 342 | if pag.has_edge(i,j) and pag.has_edge(i,k): 343 | chain2 = pag.has_directed_edge(j,k) and pag.get_edge_data(i,j)[j] == 'o' and pag.get_edge_data(i,j)[i] == '-' 344 | edge = pag.get_edge_data(i,k)[i] == 'o' and pag.has_directed_edge(i,k) 345 | if (chain1 or chain2) and edge: 346 | pag.fully_direct_edge(i,k) 347 | print('Orienting edge {},{} with rule 8'.format(k,i)) 348 | 349 | @staticmethod 350 | def rule9(pag,i,j,k,l): 351 | """ 352 | rule 9 of edge orientation in the fci algorithm 353 | 354 | Parameters 355 | ---------- 356 | pag: PAG 357 | PAG to orient edges of 358 | i,j,k,l: str 359 | nodes to test for orientation rule 360 | """ 361 | if pag.has_directed_edge(i,k) and pag.has_o(i,k,i): 362 | for path in nx.all_simple_paths(pag,i,k): 363 | if pag.isUncovered(path) and pag.isPD(path): 364 | if path[1] == j and path[2] == l and not pag.has_edge(j,k): 365 | pag.fully_direct_edge(i,k) 366 | print('Orienting edge {},{} with rule 9'.format(k,i)) 367 | break 368 | 369 | @staticmethod 370 | def rule10(pag,i,j,k,l): 371 | """ 372 | rule 10 of edge orientation in the fci algorithm 373 | 374 | Parameters 375 | ---------- 376 | pag: PAG 377 | PAG to orient edges of 378 | i,j,k,l: str 379 | nodes to test for orientation rule 380 | """ 381 | if pag.has_directed_edge(i,k) and pag.has_o(i,k,i): 382 | if pag.has_fully_directed_edge(j,k) and pag.has_fully_directed_edge(l,k): 383 | for path1 in nx.all_simple_paths(pag,i,j): 384 | for path2 in nx.all_simple_paths(pag,i,l): 385 | if pag.isUncovered(path1) and pag.isPD(path1) and pag.isUncovered(path2) and pag.isPD(path2): 386 | if path1[1] != path2[1] and not pag.has_edge(path1[1],path2[1]): 387 | pag.fully_direct_edge(i,k) 388 | print('Orienting edge {},{} with rule 10'.format(k,i)) 389 | 390 | if __name__ == '__main__': 391 | data_path = sys.argv[1] 392 | if len(sys.argv) == 4: 393 | if sys.argv[3] == 'space': 394 | sys.argv[3] = ' ' 395 | delimeator = sys.argv[3] 396 | labeled = sys.argv[2] == 'True' 397 | elif len(sys.argv) == 3: 398 | delimeator = ' ' 399 | labeled = sys.argv[2] == 'True' 400 | else: 401 | delimeator = ' ' 402 | labeled = True 403 | data = FCIAlg.prepare_data(data_path, isLabeled=labeled, delim = delimeator) 404 | fci = FCIAlg(data, chi, 0.05) 405 | pag = fci.learnGraph() 406 | pag.write_to_file('adjmat') -------------------------------------------------------------------------------- /src/graphs.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import numpy as np 3 | 4 | class PDAG(nx.DiGraph): 5 | """ 6 | A class implementaing a graph which can have both directed and undirected edges 7 | """ 8 | def add_edge(self, u,v, directed = True): 9 | """ 10 | A method to add an edge to a graph 11 | 12 | Parameters 13 | ---------- 14 | u : str 15 | the from node of an edge 16 | v: str 17 | the to node of an edge 18 | directed: bool, optional 19 | determines whether an edge is directed (True) or not (False) 20 | """ 21 | super().add_edge(u,v) 22 | if not directed: 23 | super().add_edge(v,u) 24 | 25 | def remove_edge(self, u,v): 26 | """ 27 | A method to remove an edge from the graph 28 | 29 | Parameters 30 | ---------- 31 | u : str 32 | the from node of the edge 33 | v: str 34 | the to node of the edge 35 | 36 | """ 37 | super().remove_edge(u,v) 38 | if super().has_edge(v,u): 39 | super().remove_edge(v,u) 40 | 41 | def has_directed_edge(self,u,v): 42 | """ 43 | A method to check the graph for a directed edge 44 | 45 | Parameters 46 | ---------- 47 | u : str 48 | the from node of the edge 49 | v: str 50 | the to node of the edge 51 | 52 | Returns 53 | ------- 54 | bool 55 | True if has directed edge, false if not 56 | 57 | """ 58 | return super().has_edge(u,v) and not super().has_edge(v,u) 59 | 60 | def to_matrix(self): 61 | """ 62 | A method to generate the adjacency matrix of the graph 63 | 64 | Returns 65 | ---------- 66 | numpy.ndarray 67 | a 2d array containing the adjacency matrix of the graph 68 | 69 | """ 70 | labels = [node for node in self] 71 | mat = np.zeros((len(labels), (len(labels)))) 72 | for x in labels: 73 | for y in labels: 74 | if self.has_edge(x,y): 75 | mat[labels.index(x)][labels.index(y)] = 1 76 | return mat 77 | 78 | def write_to_file(self, path): 79 | """ 80 | A method to write the adjacency matrix of the graph to a file 81 | 82 | Parameters 83 | ---------- 84 | path: str 85 | path to file to write adjacency matrix to 86 | 87 | """ 88 | mat = self.to_matrix() 89 | labels = [node for node in self] 90 | f = open(path, 'w') 91 | for label in labels: 92 | f.write(label) 93 | f.write(' ') 94 | f.write('\n') 95 | for i in range(len(labels)): 96 | f.write(labels[i]) 97 | f.write(' ') 98 | for point in mat[i]: 99 | f.write(str(int(point))) 100 | f.write(' ') 101 | f.write('\n') 102 | f.close() 103 | 104 | 105 | class PAG(nx.Graph): 106 | """ 107 | A class implementaing a graph which can have 108 | all edge types of a partial ancestral graph 109 | """ 110 | def add_edge(self, u,v, utag = 'o', vtag = 'o'): 111 | """ 112 | A method to add an edge to a graph 113 | 114 | Parameters 115 | ---------- 116 | u : str 117 | the from node of an edge 118 | v: str 119 | the to node of an edge 120 | utag: str 121 | the tag of the from node of an edge 122 | vtag: str 123 | the tag of the to node of an edge 124 | """ 125 | super().add_edges_from([(u,v, {u:utag, v:vtag})]) 126 | 127 | 128 | def has_directed_edge(self, u,v): 129 | """ 130 | A method to check the graph for a directed edge 131 | (an edge with a > tag on the to node) 132 | 133 | Parameters 134 | ---------- 135 | u : str 136 | the from node of the edge 137 | v: str 138 | the to node of the edge 139 | 140 | Returns 141 | ------- 142 | bool 143 | True if has directed edge, false if not 144 | 145 | """ 146 | if super().has_edge(u,v): 147 | tags = super().get_edge_data(u,v) 148 | if tags[v] == '>': 149 | return True 150 | else: 151 | return False 152 | else: 153 | return False 154 | 155 | def has_fully_directed_edge(self, u,v): 156 | """ 157 | A method to check the graph for a fully directed edge 158 | (an edge with a > tag on the to node and 159 | a - tag on the from node) 160 | 161 | Parameters 162 | ---------- 163 | u : str 164 | the from node of the edge 165 | v: str 166 | the to node of the edge 167 | 168 | Returns 169 | ------- 170 | bool 171 | True if has fully directed edge, false if not 172 | 173 | """ 174 | if super().has_edge(u,v): 175 | tags = super().get_edge_data(u,v) 176 | if tags[u] == '-' and tags[v] == '>': 177 | return True 178 | else: 179 | return False 180 | else: 181 | return False 182 | 183 | def has_fully_undirected_edge(self, u,v): 184 | """ 185 | A method to check the graph for a fully undirected edge 186 | (an edge with a - tag on the to node and 187 | a - tag on the from node) 188 | 189 | Parameters 190 | ---------- 191 | u : str 192 | the from node of the edge 193 | v: str 194 | the to node of the edge 195 | 196 | Returns 197 | ------- 198 | bool 199 | True if has undirected edge, false if not 200 | """ 201 | if super().has_edge(u,v): 202 | tags = super().get_edge_data(u,v) 203 | if tags[u] == '-' and tags[v] == '-': 204 | return True 205 | else: 206 | return False 207 | else: 208 | return False 209 | 210 | def add_edges_from(self, bunch): 211 | """ 212 | A method to add a list of edges with o tags to a graph 213 | 214 | Parameters 215 | ---------- 216 | bunch: iterable 217 | a list of pairs of nodes which are edges 218 | """ 219 | for edge in bunch: 220 | super().add_edges_from([(*(edge), {edge[0]:'o', edge[1]:'o'})]) 221 | 222 | def setTag(self, edge, node, tag): 223 | """ 224 | A method to set the tag of one side of an edge 225 | 226 | Parameters 227 | ---------- 228 | edge : [str,str] 229 | the two nodes of the edge to modify 230 | node: str 231 | the side of the edge to modify 232 | tag: str 233 | the new tag of the edge, in [>,-,o] 234 | """ 235 | if super().has_edge(*edge): 236 | self.edges[edge][node] = tag 237 | 238 | def direct_edge(self, u,v): 239 | """ 240 | A method to direct an edge in a graph (set the tag of the to node to >) 241 | 242 | Parameters 243 | ---------- 244 | u : str 245 | the from node of the edge 246 | v: str 247 | the to node of the edge 248 | 249 | """ 250 | if super().has_edge(u,v): 251 | self.edges[(u,v)][v] = '>' 252 | 253 | def fully_direct_edge(self, u,v): 254 | """ 255 | A method to fully direct an edge in a graph 256 | (set the tag of the to node to > and the from node to -) 257 | 258 | Parameters 259 | ---------- 260 | u : str 261 | the from node of the edge 262 | v: str 263 | the to node of the edge 264 | 265 | """ 266 | if super().has_edge(u,v): 267 | self.edges[(u,v)][v] = '>' 268 | self.edges[(u,v)][u] = '-' 269 | 270 | def undirect_edge(self, u,v): 271 | """ 272 | A method to fully undirect an edge in a graph 273 | (set the tag of the to node to - and the from node to -) 274 | Parameters 275 | ---------- 276 | u : str 277 | the from node of the edge 278 | v: str 279 | the to node of the edge 280 | 281 | """ 282 | if super().has_edge(u,v): 283 | self.edges[(u,v)][v] = '-' 284 | self.edges[(u,v)][u] = '-' 285 | 286 | def hasDiscPath(self,u, v, b): 287 | """ 288 | A method to see if the pag has a discriminating path 289 | between two nodes 290 | Parameters 291 | ---------- 292 | u : str 293 | the from node of the path 294 | v: str 295 | the to node of the path 296 | b: str 297 | the penultimate node of the disc path 298 | 299 | Returns 300 | ------- 301 | bool 302 | True if there is a disc path, false if not 303 | 304 | """ 305 | all_paths = nx.all_simple_paths(self, u, v) 306 | for path in all_paths: 307 | if b in path: 308 | b_pred = (path.index(v) - path.index(b)) == 1 and self.has_edge(b,v) 309 | all_colliders = True 310 | for node in path[1:-1]: 311 | prev = path[path.index(node)-1] 312 | suc = path[path.index(node)+1] 313 | if (node != b) and not ((self.has_directed_edge(prev,node)) and (self.has_directed_edge(suc,node))): 314 | all_colliders = False 315 | all_pred = True 316 | for node in path[1:-2]: 317 | if not (self.has_directed_edge(node, v)): 318 | all_pred = False 319 | nonadj = not self.has_edge(u,v) 320 | if (b_pred and all_colliders and all_pred and nonadj): 321 | return True 322 | return False 323 | 324 | def findDiscPath(self,u,v,b): 325 | """ 326 | A method find all discriminating paths 327 | between two nodes in the pag 328 | Parameters 329 | ---------- 330 | u : str 331 | the from node of the path 332 | v: str 333 | the to node of the path 334 | b: str 335 | the penultimate node of the disc path 336 | 337 | Returns 338 | ------- 339 | str[][] 340 | List of discriminating paths in pag between the two nodes on the third node 341 | """ 342 | all_paths = nx.all_simple_paths(self, u, v) 343 | discpaths = [] 344 | for path in all_paths: 345 | if b in path: 346 | b_pred = (path.index(v) - path.index(b)) == 1 and self.has_edge(b,v) 347 | all_colliders = True 348 | for node in path[1:-1]: 349 | prev = path[path.index(node)-1] 350 | suc = path[path.index(node)+1] 351 | if (node != b) and not ((self.has_directed_edge(prev,node)) and (self.has_directed_edge(suc,node))): 352 | all_colliders = False 353 | all_pred = True 354 | for node in path[1:-2]: 355 | if not (self.has_directed_edge(node, v)): 356 | all_pred = False 357 | nonadj = not self.has_edge(u,v) 358 | if (b_pred and all_colliders and all_pred and nonadj): 359 | discpaths.append(path) 360 | return discpaths 361 | 362 | def has_o(self,u,v,side): 363 | """ 364 | A method to check the graph for a o tag on one side of an edge 365 | 366 | Parameters 367 | ---------- 368 | u : str 369 | the from node of the edge 370 | v: str 371 | the to node of the edge 372 | side: str 373 | the side to test for the tag 374 | 375 | Returns 376 | ------- 377 | bool 378 | True if has undirected edge, false if not 379 | """ 380 | cond = False 381 | if self.has_edge(u,v): 382 | if self[u][v][side] == 'o': 383 | cond = True 384 | return cond 385 | 386 | 387 | def isUncovered(self, path): 388 | """ 389 | A method to see if the path is uncovered in the pag 390 | Parameters 391 | ---------- 392 | path: str[] 393 | list of nodes 394 | 395 | Returns 396 | ------- 397 | bool 398 | True if path is uncovered path, false if not 399 | 400 | """ 401 | for x in range(1,len(path)-1): 402 | pred = path[x-1] 403 | suc = path[x+1] 404 | if self.has_edge(pred,suc): 405 | return False 406 | return True 407 | 408 | def isPD(self, path): 409 | """ 410 | A method to see if the path is potentially directed in the pag 411 | Parameters 412 | ---------- 413 | path: str[] 414 | list of nodes 415 | 416 | Returns 417 | ------- 418 | bool 419 | True if path is potentially directed path, false if not 420 | 421 | """ 422 | for x in range(len(path)-1): 423 | node = path[x] 424 | suc = path[x+1] 425 | edge = self.get_edge_data(node,suc) 426 | if (edge[suc] == '-' or edge[node] == '>'): 427 | return False 428 | return True 429 | 430 | def isCirclePath(self,path): 431 | """ 432 | A method to see if the every tag in the path is an o 433 | Parameters 434 | ---------- 435 | path: str[] 436 | list of nodes 437 | 438 | Returns 439 | ------- 440 | bool 441 | True if every tag in the path is an o, false if not 442 | """ 443 | for i in range(len(path[:-1])): 444 | node = path[i] 445 | suc = path[i+1] 446 | if not (self.has_o(node,suc,node) and self.has_o(suc,node,suc)): 447 | return False 448 | return True 449 | 450 | 451 | def findUncoveredCirclePaths(self,u,v): 452 | """ 453 | A method find all circle paths 454 | between two nodes in the pag 455 | Parameters 456 | ---------- 457 | u : str 458 | the from node of the path 459 | v: str 460 | the to node of the path 461 | 462 | Returns 463 | ------- 464 | str[][] 465 | List of circle paths in pag between the two nodes 466 | """ 467 | paths = [] 468 | for path in nx.all_simple_paths(self, u,v): 469 | if self.isUncovered(path) and self.isCirclePath(path): 470 | paths.append(path) 471 | return paths 472 | 473 | def to_matrix(self): 474 | """ 475 | A method to generate the adjacency matrix of the graph 476 | 477 | Returns 478 | ---------- 479 | numpy.ndarray 480 | a 2d array containing the adjacency matrix of the graph 481 | 482 | """ 483 | symbol_map = {'o':1,'>':2,'-':3} 484 | 485 | labels = [node for node in self] 486 | mat = np.zeros((len(labels), (len(labels)))) 487 | for x in labels: 488 | for y in labels: 489 | if self.has_edge(x,y): 490 | mat[labels.index(x)][labels.index(y)] = symbol_map[self.get_edge_data(x,y)[y]] 491 | return mat 492 | 493 | def write_to_file(self, path): 494 | """ 495 | A method to write the adjacency matrix of the graph to a file 496 | 497 | Parameters 498 | ---------- 499 | path: str 500 | path to file to write adjacency matrix to 501 | 502 | """ 503 | mat = self.to_matrix() 504 | labels = [node for node in self] 505 | f = open(path, 'w') 506 | for label in labels: 507 | f.write(label) 508 | f.write(' ') 509 | f.write('\n') 510 | for i in range(len(labels)): 511 | f.write(labels[i]) 512 | f.write(' ') 513 | for point in mat[i]: 514 | f.write(str(int(point))) 515 | f.write(' ') 516 | f.write('\n') 517 | f.close() -------------------------------------------------------------------------------- /Tests/unittests.py: -------------------------------------------------------------------------------- 1 | import networkx as nx 2 | import unittest 3 | import matplotlib.pyplot as plt 4 | import sys 5 | sys.path.append('src') 6 | from pc import PCAlg 7 | from indepTests import chi 8 | from graphs import PDAG, PAG 9 | from fci import FCIAlg 10 | 11 | class ChiSquareTests(unittest.TestCase): 12 | # Chi squared independence test functions 13 | def setUp(self): 14 | self.data = PCAlg.prepare_data('data/alarm_10000.dat', ' ', True) 15 | 16 | 17 | def test1(self): 18 | p, *_= chi(self.data, 'EXPCO2', 'EXPCO2', []) 19 | assert(p == 0) 20 | 21 | 22 | 23 | def test2(self): 24 | p, h = chi(self.data, 'PAP', 'PULMEMBOLUS', []) 25 | assert(round(h,1)==1041.7) 26 | 27 | def test3(self): 28 | p, h = chi(self.data, 'EXPCO2', 'PULMEMBOLUS', []) 29 | assert(round(h,3)==0.349) 30 | 31 | def test4(self): 32 | p, h = chi(self.data, 'EXPCO2', 'PULMEMBOLUS', ['PAP']) 33 | assert(round(h,3)== 3.841) 34 | 35 | def test5(self): 36 | p, h = chi(self.data, 'EXPCO2', 'PULMEMBOLUS', ['PAP','KINKEDTUBE']) 37 | assert(round(h,3)== 3.862) 38 | 39 | def test6(self): 40 | p, h = chi(self.data, 'EXPCO2', 'PULMEMBOLUS', ['KINKEDTUBE','PAP',]) 41 | assert(round(h,3)== 3.862) 42 | 43 | def test7(self): 44 | self.data = PCAlg.prepare_data('data/asia_1000.data', ' ', True) 45 | p, h = chi(self.data, 'asia', 'tub', []) 46 | assert(round(h,3)== 34.496) 47 | 48 | def test8(self): 49 | self.data = PCAlg.prepare_data('data/asia_1000.data', ' ', True) 50 | p, h = chi(self.data, 'asia', 'tub', ['smoke']) 51 | assert(round(h,3)== 37.322) 52 | 53 | def test9(self): 54 | self.data = PCAlg.prepare_data('data/asia_1000.data', ' ', True) 55 | p, h = chi(self.data, 'asia', 'tub', ['smoke', 'lung']) 56 | assert(round(h,3)== 36.997) 57 | 58 | 59 | def test10(self): 60 | self.data = PCAlg.prepare_data('data/asia_1000.data', ' ', True) 61 | p, h = chi(self.data, 'either', 'tub', ['bronc', 'xray']) 62 | assert(round(h,3)== 991) 63 | 64 | def test11(self): 65 | self.data = PCAlg.prepare_data('data/asia_10000.data', ' ', True) 66 | p, h = chi(self.data, 'either', 'tub', ['bronc', 'xray']) 67 | assert(round(h,3)== 9884.0 ) 68 | 69 | def test12(self): 70 | self.data = PCAlg.prepare_data('data/alarm_1000.data', ' ', False) 71 | p, h = chi(self.data, '1', '2', ['3', '4']) 72 | assert(round(h,3)==3.115) 73 | 74 | def test13(self): 75 | self.data = PCAlg.prepare_data('data/insurance_1000.data', ' ', False) 76 | p, h = chi(self.data, '0', '1', ['2', '3']) 77 | assert(round(h,3)==35.531) 78 | 79 | class SkeletonTests(unittest.TestCase): 80 | # Tests for the skeleton estimation 81 | def setUp(self): 82 | self.data = PCAlg.prepare_data('data/asia_1000.data', ' ', True) 83 | self.pcalg = PCAlg(self.data, chi) 84 | self.skeleton = nx.Graph() 85 | 86 | def test1(self): 87 | self.skeleton.add_nodes_from([1,2,3,4,5]) 88 | sepset ={(1,2):(), (1,3):(2,), (1,4):(), (1,5):(2,), 89 | (2,1):(), (2,3):(4,5), (2,4):(), (2,5):(), 90 | (3,1):(2,), (3,2):(4,5), (3,4):(), (3,5):(), 91 | (4,1):(), (4,2):(), (4,3):(), (4,5):(3,), 92 | (5,1):(2,), (5,2):(), (5,3):(), (5,4):(3,), } 93 | self.skeleton.add_edges_from([[1,2],[3,4],[3,5],[4,2],[5,2]]) 94 | directed = self.pcalg.orientEdges(self.skeleton, sepset) 95 | assert(list(directed.edges) == [(1, 2), (4, 2), (4, 3), (5, 2), (5, 3), (3, 4), (3, 5)]) 96 | 97 | 98 | class PathTests(unittest.TestCase): 99 | def setUp(self): 100 | self.directed = nx.DiGraph() 101 | self.directed.add_nodes_from([1,2,3,4,5]) 102 | 103 | def test1(self): 104 | self.directed.add_edges_from([[1,2],[2,3]]) 105 | assert(PCAlg.findPath(1,3,self.directed, [])) 106 | 107 | def test2(self): 108 | self.directed.add_edges_from([[1,2],[2,3]]) 109 | assert(not PCAlg.findPath(1,5,self.directed, [])) 110 | 111 | def test3(self): 112 | self.directed.add_edges_from([[1,2],[2,3]]) 113 | self.directed.add_edges_from([[3,4]]) 114 | assert(PCAlg.findPath(3,4,self.directed, [])) 115 | 116 | def test4(self): 117 | self.directed.add_edges_from([[1,2],[2,3]]) 118 | self.directed.add_edges_from([[3,4]]) 119 | assert(PCAlg.findPath(1,4,self.directed, [])) 120 | 121 | def test5(self): 122 | self.directed.add_edges_from([[1,2],[1,3]]) 123 | self.directed.add_edges_from([[3,4],[3,5]]) 124 | assert(PCAlg.findPath(1,5,self.directed, [])) 125 | 126 | def test6(self): 127 | self.directed.add_edges_from([[1,3]]) 128 | self.directed.add_edges_from([[1,2],[3,4],[3,5]]) 129 | assert(not PCAlg.findPath(2,5,self.directed, [])) 130 | 131 | class D_SepTests(unittest.TestCase): 132 | #Tests for possible d sep set calculation 133 | def setUp(self): 134 | self.pag = PAG() 135 | self.pag.add_nodes_from([1,2,3,4,5,6]) 136 | 137 | def test1(self): 138 | self.pag.add_edge(1,2) 139 | self.pag.add_edge(3,2) 140 | dseps = FCIAlg.possible_d_seps(self.pag) 141 | assert(dseps == {1:[2],2:[1,3],3:[2], 4:[], 5:[], 6:[]}) 142 | 143 | def test2(self): 144 | self.pag.add_edge(1,2) 145 | self.pag.add_edge(2,3) 146 | self.pag.fully_direct_edge(1,2) 147 | self.pag.fully_direct_edge(3,2) 148 | dseps = FCIAlg.possible_d_seps(self.pag) 149 | assert(dseps == {1:[2,3],2:[1,3],3:[1,2], 4:[], 5:[], 6:[]}) 150 | 151 | def test3(self): 152 | self.pag.add_edge(1,2) 153 | self.pag.add_edge(2,3) 154 | self.pag.fully_direct_edge(1,2) 155 | self.pag.fully_direct_edge(3,2) 156 | self.pag.add_edge(2,4) 157 | self.pag.add_edge(3,4) 158 | dseps = FCIAlg.possible_d_seps(self.pag) 159 | assert(dseps == {1:[2,3,4],2:[1,3,4],3:[1,2,4,], 4:[1,2,3], 5:[], 6:[]}) 160 | 161 | def test4(self): 162 | self.pag.add_edge(1,2) 163 | self.pag.add_edge(3,2) 164 | self.pag.add_edge(3,1) 165 | dseps = FCIAlg.possible_d_seps(self.pag) 166 | assert(dseps == {1:[2,3],2:[1,3],3:[1,2], 4:[], 5:[], 6:[]}) 167 | 168 | class DiscPathTest(unittest.TestCase): 169 | # tests for finding discriminating paths on a graph 170 | def setUp(self): 171 | self.pag = PAG() 172 | self.pag.add_nodes_from([1,2,3,4]) 173 | 174 | def test1(self): 175 | self.pag.add_edges_from([[1,2],[2,3],[3,4],[2,4]]) 176 | self.pag.fully_direct_edge(1,2) 177 | self.pag.fully_direct_edge(3,2) 178 | self.pag.fully_direct_edge(2,4) 179 | self.pag.fully_direct_edge(3,4) 180 | assert(self.pag.hasDiscPath(1,4,3)) 181 | 182 | def test2(self): 183 | self.pag.add_edges_from([[1,2],[2,3],[2,4]]) 184 | self.pag.fully_direct_edge(1,2) 185 | self.pag.fully_direct_edge(3,2) 186 | self.pag.fully_direct_edge(2,4) 187 | assert(not self.pag.hasDiscPath(1,4,3)) 188 | 189 | def test3(self): 190 | self.pag.add_edges_from([[1,2],[2,3],[3,4],[2,4]]) 191 | self.pag.fully_direct_edge(1,2) 192 | self.pag.fully_direct_edge(2,3) 193 | self.pag.fully_direct_edge(2,4) 194 | self.pag.fully_direct_edge(3,4) 195 | assert(not self.pag.hasDiscPath(1,4,3)) 196 | 197 | def test4(self): 198 | self.pag.add_edges_from([[1,2],[2,3],[3,4],[2,4]]) 199 | self.pag.fully_direct_edge(1,2) 200 | self.pag.fully_direct_edge(3,2) 201 | self.pag.fully_direct_edge(3,4) 202 | assert(not self.pag.hasDiscPath(1,4,3)) 203 | 204 | def test5(self): 205 | self.pag.add_edges_from([[1,2],[2,3],[3,4],[2,4]]) 206 | self.pag.fully_direct_edge(1,2) 207 | self.pag.fully_direct_edge(3,2) 208 | self.pag.fully_direct_edge(3,4) 209 | self.pag.fully_direct_edge(1,4) 210 | assert(not self.pag.hasDiscPath(1,4,3)) 211 | 212 | 213 | class VOrientTests(unittest.TestCase): 214 | # tests for v structure orientation 215 | def setUp(self): 216 | self.data = PCAlg.prepare_data('data/asia_1000.data', ' ', True) 217 | self.pcalg = PCAlg(self.data, chi) 218 | self.fcialg = FCIAlg(self.data, chi) 219 | self.directed = nx.DiGraph() 220 | self.undirected = nx.Graph() 221 | self.directed.add_nodes_from([1,2,3,4]) 222 | self.undirected.add_nodes_from(self.directed) 223 | self.pag = PAG() 224 | self.pag.add_nodes_from(self.undirected) 225 | self.sepset = {(x,y): [] for x in [1,2,3,4,5] for y in [1,2,3,4,5] if x!=y} 226 | 227 | def test1(self): 228 | self.undirected.add_edges_from([(1,2), (2,3)]) 229 | self.pcalg.orient_V(self.undirected, self.directed, self.sepset) 230 | part1 = not self.undirected.has_edge(1,2) and not self.undirected.has_edge(3,2) 231 | part2 = self.directed.has_edge(1,2) and self.directed.has_edge(3,2) 232 | assert(part1 and part2) 233 | 234 | def test2(self): 235 | self.undirected.add_edges_from([(1,2), (2,3)]) 236 | self.sepset[(1,3)].append(2) 237 | self.sepset[(3,1)].append(2) 238 | self.pcalg.orient_V(self.undirected, self.directed, self.sepset) 239 | part1 = not self.undirected.has_edge(1,2) and not self.undirected.has_edge(3,2) 240 | part2 = self.directed.has_edge(1,2) and self.directed.has_edge(3,2) 241 | assert(not (part1 and part2)) 242 | 243 | def test3(self): 244 | self.pag.add_edges_from([(1,2), (2,3)]) 245 | self.fcialg.orient_V(self.pag, self.sepset) 246 | assert(self.pag.has_directed_edge(1,2) and self.pag.has_directed_edge(3,2)) 247 | 248 | def test4(self): 249 | self.pag.add_edges_from([(1,2), (2,3)]) 250 | self.sepset[(1,3)].append(2) 251 | self.sepset[(3,1)].append(2) 252 | self.fcialg.orient_V(self.pag, self.sepset) 253 | assert(not self.pag.has_directed_edge(1,2) and not self.pag.has_directed_edge(3,2)) 254 | 255 | class RulesTests(unittest.TestCase): 256 | # tests for fci algorithm orientation rules 257 | def setUp(self): 258 | self.pag = PAG() 259 | self.pag.add_nodes_from([1,2,3,4,5]) 260 | 261 | # Rule 1 Tests 262 | def test11(self): 263 | self.pag.add_edge(1,2) 264 | self.pag.add_edge(2,3) 265 | self.pag.direct_edge(1,2) 266 | FCIAlg.rule1(self.pag,1,2,3) 267 | assert(self.pag.has_fully_directed_edge(2,3)) 268 | 269 | def test12(self): 270 | self.pag.add_edge(1,2) 271 | self.pag.add_edge(2,3) 272 | FCIAlg.rule1(self.pag,1,2,3) 273 | assert(not self.pag.has_fully_directed_edge(2,3)) 274 | 275 | # Rule 2 Tests 276 | def test21(self): 277 | self.pag.add_edge(1,2) 278 | self.pag.add_edge(2,3) 279 | self.pag.add_edge(1,3) 280 | self.pag.direct_edge(1,2) 281 | self.pag.fully_direct_edge(2,3) 282 | FCIAlg.rule2(self.pag,1,2,3) 283 | assert(self.pag.has_directed_edge(1,3)) 284 | 285 | def test22(self): 286 | self.pag.add_edge(1,2) 287 | self.pag.add_edge(2,3) 288 | self.pag.add_edge(1,3) 289 | self.pag.direct_edge(2,3) 290 | self.pag.fully_direct_edge(1,2) 291 | FCIAlg.rule2(self.pag,1,2,3) 292 | assert(self.pag.has_directed_edge(1,3)) 293 | 294 | def test23(self): 295 | self.pag.add_edge(1,2) 296 | self.pag.add_edge(2,3) 297 | self.pag.add_edge(1,3) 298 | self.pag.fully_direct_edge(3,2) 299 | self.pag.fully_direct_edge(1,2) 300 | FCIAlg.rule2(self.pag,1,2,3) 301 | assert(not self.pag.has_directed_edge(1,3)) 302 | 303 | # Rule 3 Tests 304 | def test31(self): 305 | self.pag.add_edge(1,2) 306 | self.pag.add_edge(2,3) 307 | self.pag.add_edge(1,4) 308 | self.pag.add_edge(4,3) 309 | self.pag.add_edge(4,2) 310 | self.pag.direct_edge(1,2) 311 | self.pag.direct_edge(3,2) 312 | FCIAlg.rule3(self.pag,1,2,3,4) 313 | assert(self.pag.has_directed_edge(4,2)) 314 | 315 | def test32(self): 316 | self.pag.add_edge(1,2) 317 | self.pag.add_edge(2,3) 318 | self.pag.add_edge(1,4) 319 | self.pag.add_edge(4,3) 320 | self.pag.add_edge(4,2) 321 | self.pag.direct_edge(1,2) 322 | self.pag.direct_edge(3,2) 323 | self.pag.direct_edge(1,4) 324 | FCIAlg.rule3(self.pag,1,2,3,4) 325 | assert(not self.pag.has_directed_edge(4,2)) 326 | 327 | # Rule 4 Tests 328 | def test41(self): 329 | self.pag.add_edge(1,2) 330 | self.pag.add_edge(2,3) 331 | self.pag.add_edge(3,4) 332 | self.pag.add_edge(4,5) 333 | self.pag.add_edge(2,5) 334 | self.pag.add_edge(3,5) 335 | self.pag.direct_edge(1,2) 336 | self.pag.direct_edge(2,3) 337 | self.pag.direct_edge(2,5) 338 | self.pag.direct_edge(3,2) 339 | self.pag.direct_edge(3,4) 340 | self.pag.direct_edge(3,5) 341 | self.pag.direct_edge(4,3) 342 | self.pag.direct_edge(3,2) 343 | sepset = {(1,5) : [4], (5,1): [4]} 344 | FCIAlg.rule4(self.pag, 3,4,5,1, sepset) 345 | assert(self.pag.has_directed_edge(4,5)) 346 | 347 | def test42(self): 348 | self.pag.add_edge(1,2) 349 | self.pag.add_edge(2,3) 350 | self.pag.add_edge(3,4) 351 | self.pag.add_edge(4,5) 352 | self.pag.add_edge(2,5) 353 | self.pag.add_edge(3,5) 354 | self.pag.direct_edge(1,2) 355 | self.pag.direct_edge(2,3) 356 | self.pag.direct_edge(2,5) 357 | self.pag.direct_edge(3,2) 358 | self.pag.direct_edge(3,4) 359 | self.pag.direct_edge(3,5) 360 | self.pag.direct_edge(4,3) 361 | self.pag.direct_edge(3,2) 362 | sepset = {(1,5) : [2], (5,1): [2]} 363 | FCIAlg.rule4(self.pag, 3,4,5,1, sepset) 364 | assert(self.pag.has_directed_edge(4,5) and self.pag.has_directed_edge(5,4) and self.pag.has_directed_edge(4,3) and self.pag.has_directed_edge(3,4)) 365 | 366 | # Rule 5 Tests 367 | def test51(self): 368 | self.pag.add_edge(1,2) 369 | self.pag.add_edge(1,3) 370 | self.pag.add_edge(3,4) 371 | self.pag.add_edge(2,4) 372 | FCIAlg.rule5(self.pag, 1,2,3,4) 373 | assert(self.pag.has_fully_undirected_edge(1,2) and self.pag.has_fully_undirected_edge(1,3) and self.pag.has_fully_undirected_edge(3,4) and self.pag.has_fully_undirected_edge(4,2)) 374 | 375 | def test52(self): 376 | self.pag.add_edge(1,2) 377 | self.pag.add_edge(1,3) 378 | self.pag.add_edge(2,4) 379 | FCIAlg.rule5(self.pag, 1,2,3,4) 380 | assert(not( self.pag.has_fully_undirected_edge(1,2) and self.pag.has_fully_undirected_edge(1,3) and self.pag.has_fully_undirected_edge(3,4) and self.pag.has_fully_undirected_edge(4,2))) 381 | 382 | def test53(self): 383 | self.pag.add_edge(1,2) 384 | self.pag.add_edge(1,3) 385 | self.pag.add_edge(3,4) 386 | FCIAlg.rule5(self.pag, 1,2,3,4) 387 | assert(not(self.pag.has_fully_undirected_edge(1,2) and self.pag.has_fully_undirected_edge(1,3) and self.pag.has_fully_undirected_edge(3,4) and self.pag.has_fully_undirected_edge(4,2))) 388 | 389 | def test54(self): 390 | self.pag.add_edge(1,5) 391 | self.pag.add_edge(1,2) 392 | self.pag.add_edge(1,3) 393 | self.pag.add_edge(3,4) 394 | self.pag.add_edge(2,4) 395 | FCIAlg.rule5(self.pag, 1,2,3,4) 396 | assert(self.pag.has_fully_undirected_edge(1,2) and self.pag.has_fully_undirected_edge(1,3) and self.pag.has_fully_undirected_edge(3,4) and self.pag.has_fully_undirected_edge(4,2)) 397 | 398 | 399 | 400 | # Rule 6 Tests 401 | def test61(self): 402 | self.pag.add_edge(1,2) 403 | self.pag.add_edge(2,3) 404 | self.pag.undirect_edge(1,2) 405 | FCIAlg.rule67(self.pag,1,2,3) 406 | assert(self.pag.get_edge_data(2,3)[2] == '-') 407 | 408 | def test62(self): 409 | self.pag.add_edge(1,2) 410 | self.pag.add_edge(2,3) 411 | FCIAlg.rule67(self.pag,1,2,3) 412 | assert(not (self.pag.get_edge_data(2,3)[2] == '-')) 413 | 414 | def test63(self): 415 | self.pag.add_edge(2,3) 416 | self.pag.undirect_edge(1,2) 417 | FCIAlg.rule67(self.pag,1,2,3) 418 | assert(not (self.pag.get_edge_data(2,3)[2] == '-')) 419 | 420 | # Rule 7 Tests 421 | def test71(self): 422 | self.pag.add_edge(1,2) 423 | self.pag.add_edge(2,3) 424 | self.pag.setTag([1,2],1,'-') 425 | FCIAlg.rule67(self.pag,1,2,3) 426 | assert(self.pag.get_edge_data(2,3)[2] == '-') 427 | 428 | def test72(self): 429 | self.pag.add_edge(1,2) 430 | self.pag.add_edge(2,3) 431 | FCIAlg.rule67(self.pag,1,2,3) 432 | assert(not (self.pag.get_edge_data(2,3)[2] == '-')) 433 | 434 | # Rule 8 Tests 435 | def test81(self): 436 | self.pag.add_edge(1,2) 437 | self.pag.add_edge(2,3) 438 | self.pag.add_edge(1,3) 439 | self.pag.direct_edge(1,3) 440 | self.pag.fully_direct_edge(1,2) 441 | self.pag.fully_direct_edge(2,3) 442 | FCIAlg.rule8(self.pag,1,2,3) 443 | assert(self.pag.has_fully_directed_edge(1,3)) 444 | 445 | def test82(self): 446 | self.pag.add_edge(1,2) 447 | self.pag.add_edge(2,3) 448 | self.pag.add_edge(1,3) 449 | self.pag.direct_edge(1,3) 450 | self.pag.setTag([1,2],1,'-') 451 | self.pag.fully_direct_edge(2,3) 452 | FCIAlg.rule8(self.pag,1,2,3) 453 | assert(self.pag.has_fully_directed_edge(1,3)) 454 | 455 | # Rule 9 Tests 456 | def test91(self): 457 | self.pag.add_edge(1,3) 458 | self.pag.add_edge(1,2) 459 | self.pag.add_edge(2,4) 460 | self.pag.add_edge(4,3) 461 | self.pag.direct_edge(1,3) 462 | self.pag.direct_edge(1,2) 463 | FCIAlg.rule9(self.pag,1,2,3,4) 464 | assert(self.pag.has_fully_directed_edge(1,3)) 465 | 466 | def test92(self): 467 | self.pag.add_edge(1,3) 468 | self.pag.add_edge(1,2) 469 | self.pag.add_edge(2,4) 470 | self.pag.add_edge(4,3) 471 | self.pag.direct_edge(1,3) 472 | self.pag.undirect_edge(1,2) 473 | FCIAlg.rule9(self.pag,1,2,3,4) 474 | assert(not self.pag.has_fully_directed_edge(1,3)) 475 | 476 | def test93(self): 477 | self.pag.add_edge(1,3) 478 | self.pag.add_edge(1,2) 479 | self.pag.add_edge(2,4) 480 | self.pag.add_edge(4,3) 481 | self.pag.direct_edge(1,3) 482 | self.pag.direct_edge(2,1) 483 | FCIAlg.rule9(self.pag,1,2,3,4) 484 | assert(not self.pag.has_fully_directed_edge(1,3)) 485 | 486 | # Rule 10 Tests 487 | def test101(self): 488 | self.pag.add_edge(1,3) 489 | self.pag.add_edge(1,2) 490 | self.pag.add_edge(2,3) 491 | self.pag.add_edge(4,3) 492 | self.pag.add_edge(1,5) 493 | self.pag.add_edge(5,4) 494 | self.pag.direct_edge(1,3) 495 | self.pag.fully_direct_edge(2,3) 496 | self.pag.direct_edge(1,5) 497 | self.pag.fully_direct_edge(4,3) 498 | FCIAlg.rule10(self.pag,1,2,3,4) 499 | assert(self.pag.has_fully_directed_edge(1,3)) 500 | 501 | def test102(self): 502 | self.pag.add_edge(1,3) 503 | self.pag.add_edge(1,2) 504 | self.pag.add_edge(2,3) 505 | self.pag.add_edge(4,3) 506 | self.pag.add_edge(1,5) 507 | self.pag.add_edge(5,4) 508 | self.pag.fully_direct_edge(2,3) 509 | self.pag.direct_edge(1,5) 510 | self.pag.fully_direct_edge(4,3) 511 | FCIAlg.rule10(self.pag,1,2,3,4) 512 | assert(not (self.pag.has_fully_directed_edge(1,3))) 513 | 514 | def test103(self): 515 | self.pag.add_edge(1,3) 516 | self.pag.add_edge(1,2) 517 | self.pag.add_edge(2,3) 518 | self.pag.add_edge(4,3) 519 | self.pag.add_edge(1,5) 520 | self.pag.direct_edge(1,3) 521 | self.pag.direct_edge(1,5) 522 | self.pag.fully_direct_edge(4,3) 523 | FCIAlg.rule10(self.pag,1,2,3,4) 524 | assert(not (self.pag.has_fully_directed_edge(1,3))) 525 | 526 | def test104(self): 527 | self.pag.add_edge(1,3) 528 | self.pag.add_edge(1,2) 529 | self.pag.add_edge(2,3) 530 | self.pag.add_edge(4,3) 531 | self.pag.add_edge(1,5) 532 | self.pag.direct_edge(1,3) 533 | self.pag.fully_direct_edge(2,3) 534 | self.pag.direct_edge(1,5) 535 | self.pag.fully_direct_edge(4,3) 536 | FCIAlg.rule10(self.pag,1,2,3,4) 537 | assert(not (self.pag.has_fully_directed_edge(1,3))) 538 | 539 | 540 | if __name__ == '__main__': 541 | unittest.main() -------------------------------------------------------------------------------- /data/asia_1000.data: -------------------------------------------------------------------------------- 1 | asia tub smoke lung bronc either xray dysp 2 | 1 0 0 0 0 0 0 0 3 | 1 0 1 1 1 1 0 1 4 | 0 0 0 0 0 0 1 0 5 | 1 0 1 0 0 0 1 1 6 | 0 0 0 0 0 0 1 0 7 | 1 1 0 0 0 1 0 0 8 | 1 0 1 0 0 0 1 1 9 | 0 0 1 0 0 0 1 0 10 | 1 0 0 0 0 0 1 0 11 | 1 1 0 0 0 1 0 0 12 | 0 0 1 0 0 0 1 1 13 | 1 0 1 0 0 0 0 1 14 | 0 0 0 0 0 0 1 0 15 | 0 0 0 0 0 0 1 0 16 | 0 0 1 0 0 0 1 1 17 | 1 0 1 0 0 0 1 1 18 | 1 0 1 0 0 0 1 1 19 | 0 0 0 0 0 0 1 0 20 | 0 0 0 0 1 1 0 0 21 | 0 0 1 0 0 0 1 1 22 | 1 0 1 1 0 0 1 1 23 | 0 0 0 0 0 0 1 0 24 | 0 0 1 0 0 0 1 1 25 | 1 0 1 0 0 0 1 1 26 | 0 0 0 0 0 0 1 0 27 | 1 1 0 0 0 1 0 1 28 | 0 0 0 0 0 0 1 0 29 | 0 0 1 0 0 0 1 0 30 | 1 0 1 0 0 0 1 1 31 | 1 0 0 0 0 0 1 0 32 | 0 0 0 0 0 0 1 0 33 | 0 0 0 0 0 0 1 0 34 | 1 1 0 0 0 1 0 1 35 | 1 0 1 0 0 0 1 1 36 | 0 0 0 0 0 0 1 1 37 | 1 0 0 0 0 0 1 0 38 | 1 0 0 0 0 0 0 0 39 | 0 0 1 0 0 0 1 1 40 | 0 0 0 0 0 0 1 0 41 | 0 0 0 0 0 0 1 0 42 | 1 0 1 0 0 0 0 1 43 | 0 0 1 0 0 0 1 1 44 | 0 0 0 0 0 0 1 0 45 | 1 0 1 0 0 0 1 1 46 | 1 0 0 0 0 0 1 0 47 | 1 0 1 0 0 0 1 1 48 | 1 0 0 0 0 0 1 0 49 | 1 0 1 0 0 0 1 1 50 | 1 0 0 0 0 0 1 0 51 | 0 0 0 0 0 0 1 0 52 | 1 0 0 0 0 0 1 0 53 | 0 0 0 0 0 0 1 0 54 | 0 0 0 0 0 0 1 0 55 | 0 0 1 0 0 0 1 1 56 | 1 0 1 0 0 0 1 1 57 | 1 0 1 0 0 0 1 1 58 | 1 0 1 0 0 0 1 1 59 | 0 0 1 0 0 0 1 1 60 | 0 0 0 0 0 0 1 0 61 | 0 0 0 1 0 0 1 0 62 | 0 0 0 0 0 0 1 0 63 | 0 0 0 0 0 0 1 0 64 | 1 0 0 0 0 0 1 1 65 | 0 0 0 0 0 0 1 0 66 | 1 0 1 0 0 0 1 1 67 | 0 0 1 0 0 0 1 1 68 | 0 0 0 0 1 1 0 1 69 | 1 0 1 0 0 0 1 1 70 | 0 0 1 0 0 0 1 1 71 | 0 0 0 0 0 0 1 0 72 | 0 0 0 0 0 0 1 0 73 | 1 0 1 0 0 0 1 1 74 | 1 1 0 0 0 1 0 1 75 | 0 0 1 0 0 0 1 1 76 | 1 0 0 0 0 0 1 0 77 | 0 0 1 0 0 0 1 1 78 | 0 0 1 1 0 0 1 0 79 | 1 0 1 0 0 0 1 1 80 | 1 0 1 0 0 0 1 1 81 | 0 0 0 0 0 0 1 0 82 | 1 1 1 0 0 1 0 1 83 | 1 0 1 0 0 0 1 1 84 | 1 0 1 0 0 0 1 1 85 | 1 0 0 0 0 0 1 0 86 | 0 0 0 0 0 0 1 0 87 | 0 0 0 0 0 0 1 0 88 | 0 0 1 0 0 0 1 1 89 | 0 0 0 0 0 0 1 1 90 | 1 0 0 0 0 0 1 0 91 | 1 0 0 0 0 0 1 1 92 | 0 0 0 0 0 0 1 0 93 | 1 0 1 0 0 0 1 1 94 | 1 0 1 0 0 0 1 1 95 | 1 1 1 0 0 1 0 1 96 | 0 0 0 0 0 0 1 0 97 | 1 0 0 0 0 0 1 0 98 | 1 0 1 0 0 0 1 1 99 | 0 0 0 0 0 0 1 0 100 | 0 0 0 0 0 0 1 0 101 | 0 0 0 0 0 0 1 0 102 | 1 0 0 0 0 0 1 1 103 | 1 0 1 0 0 0 1 0 104 | 0 0 0 0 0 0 1 0 105 | 0 0 0 0 0 0 1 0 106 | 0 0 0 0 0 0 1 0 107 | 1 0 1 0 0 0 1 0 108 | 1 1 1 0 0 1 0 1 109 | 1 0 1 0 0 0 0 1 110 | 0 0 1 0 0 0 1 1 111 | 1 0 1 0 0 0 1 1 112 | 1 0 1 0 0 0 1 1 113 | 1 1 1 0 0 1 0 0 114 | 0 0 1 0 0 0 1 0 115 | 0 0 0 0 0 0 1 0 116 | 0 0 1 0 0 0 0 1 117 | 0 0 0 0 0 0 1 0 118 | 0 0 0 0 0 0 0 0 119 | 1 1 1 0 0 1 0 1 120 | 1 0 0 0 0 0 1 0 121 | 0 0 0 0 0 0 1 0 122 | 1 0 1 0 0 0 1 1 123 | 0 0 1 0 0 0 1 0 124 | 1 0 0 0 0 0 1 0 125 | 1 0 1 0 0 0 0 1 126 | 1 0 1 0 0 0 1 1 127 | 1 0 1 0 0 0 1 1 128 | 0 0 0 0 0 0 1 0 129 | 1 0 1 0 0 0 1 1 130 | 0 0 0 0 0 0 1 0 131 | 1 0 1 0 0 0 1 1 132 | 0 0 0 0 0 0 1 1 133 | 1 0 0 0 0 0 1 0 134 | 0 0 1 0 0 0 1 1 135 | 0 0 0 0 0 0 1 0 136 | 1 0 1 0 0 0 1 0 137 | 1 0 1 0 0 0 1 1 138 | 0 0 0 0 0 0 1 0 139 | 1 0 1 0 0 0 1 1 140 | 0 0 0 0 0 0 1 0 141 | 1 0 1 0 0 0 1 1 142 | 1 0 1 0 0 0 1 1 143 | 1 0 1 0 0 0 1 1 144 | 0 0 0 0 0 0 1 0 145 | 0 0 0 0 0 0 1 0 146 | 0 0 0 0 0 0 1 0 147 | 0 0 0 0 0 0 1 0 148 | 1 0 0 0 0 0 1 0 149 | 0 0 0 0 0 0 1 0 150 | 0 0 0 0 0 0 1 0 151 | 1 0 1 0 0 0 1 1 152 | 1 0 1 0 0 0 1 1 153 | 0 0 1 0 0 0 1 1 154 | 0 0 1 0 0 0 1 1 155 | 1 0 1 0 0 0 1 1 156 | 1 0 1 0 0 0 1 0 157 | 1 0 1 0 0 0 1 1 158 | 1 0 0 0 0 0 1 0 159 | 1 0 0 0 0 0 1 0 160 | 1 0 1 0 0 0 1 1 161 | 0 0 1 0 0 0 1 1 162 | 1 0 0 0 0 0 1 0 163 | 1 0 1 0 0 0 1 1 164 | 0 0 1 0 0 0 1 1 165 | 0 0 0 0 0 0 1 0 166 | 0 0 0 0 0 0 1 0 167 | 0 0 1 0 0 0 1 1 168 | 0 0 0 0 0 0 1 0 169 | 1 0 0 0 0 0 1 0 170 | 0 0 0 0 0 0 1 0 171 | 1 1 0 0 0 1 0 1 172 | 0 0 0 0 0 0 1 0 173 | 1 0 0 0 0 0 1 0 174 | 0 0 0 0 0 0 1 1 175 | 0 0 0 0 0 0 1 0 176 | 0 0 0 0 0 0 1 0 177 | 0 0 0 0 0 0 1 0 178 | 1 0 0 0 0 0 1 0 179 | 0 0 1 0 0 0 1 0 180 | 1 0 0 0 0 0 1 0 181 | 1 0 0 0 1 1 0 1 182 | 0 0 0 0 0 0 1 1 183 | 0 0 1 0 0 0 1 1 184 | 0 0 1 0 0 0 1 1 185 | 1 0 0 0 0 0 1 1 186 | 1 0 0 0 0 0 1 0 187 | 0 0 0 0 0 0 1 0 188 | 0 0 1 0 0 0 1 1 189 | 0 0 1 0 0 0 1 1 190 | 1 0 0 0 0 0 1 0 191 | 0 0 0 0 0 0 1 0 192 | 0 0 1 0 0 0 1 1 193 | 0 0 0 0 0 0 1 0 194 | 1 0 1 0 0 0 1 1 195 | 0 0 1 0 0 0 1 1 196 | 0 0 0 0 0 0 1 0 197 | 1 0 1 0 0 0 1 0 198 | 0 0 1 0 0 0 1 1 199 | 1 0 1 0 0 0 1 1 200 | 1 0 0 0 0 0 1 0 201 | 0 0 0 0 0 0 1 0 202 | 0 0 0 0 0 0 1 0 203 | 1 0 1 0 0 0 1 0 204 | 0 0 0 0 0 0 1 0 205 | 1 0 1 0 0 0 1 1 206 | 0 0 1 0 0 0 1 1 207 | 1 0 1 0 0 0 1 1 208 | 0 1 1 0 0 1 0 1 209 | 1 0 1 0 0 0 1 0 210 | 0 0 1 0 0 0 1 1 211 | 0 0 0 0 0 0 1 0 212 | 0 0 0 0 0 0 1 0 213 | 1 0 0 0 0 0 1 0 214 | 1 0 1 0 0 0 1 1 215 | 1 0 1 0 0 0 0 0 216 | 1 0 0 0 0 0 1 0 217 | 1 0 1 0 0 0 1 1 218 | 0 0 0 0 0 0 1 1 219 | 1 0 1 0 0 0 1 0 220 | 0 0 0 0 0 0 1 0 221 | 1 0 0 0 0 0 1 0 222 | 0 0 0 0 0 0 1 0 223 | 1 0 1 0 0 0 1 1 224 | 1 1 1 0 0 1 0 1 225 | 0 0 0 0 0 0 1 0 226 | 1 0 1 0 0 0 1 1 227 | 0 1 0 0 0 1 0 1 228 | 0 0 0 0 0 0 0 0 229 | 1 0 0 0 0 0 1 0 230 | 1 0 1 0 0 0 1 0 231 | 1 0 1 0 0 0 1 0 232 | 1 0 1 0 0 0 1 1 233 | 1 0 1 0 0 0 1 1 234 | 0 0 1 0 0 0 1 1 235 | 1 0 1 0 0 0 1 0 236 | 0 0 0 0 0 0 0 0 237 | 0 0 0 0 0 0 1 0 238 | 0 0 0 0 0 0 1 0 239 | 1 0 1 0 0 0 1 0 240 | 0 0 0 0 0 0 1 0 241 | 1 0 0 0 0 0 1 1 242 | 0 0 0 0 0 0 1 0 243 | 1 0 1 0 0 0 1 1 244 | 0 0 1 0 0 0 1 1 245 | 1 0 0 0 0 0 1 0 246 | 1 0 0 0 0 0 1 1 247 | 0 0 1 0 0 0 1 1 248 | 1 0 1 0 0 0 1 0 249 | 0 0 0 0 0 0 1 0 250 | 1 0 1 0 0 0 1 1 251 | 0 0 0 0 0 0 1 0 252 | 1 0 0 0 0 0 1 0 253 | 0 0 1 0 0 0 1 1 254 | 0 0 1 0 0 0 1 1 255 | 1 0 1 0 0 0 1 1 256 | 0 0 0 1 0 0 1 0 257 | 0 0 1 0 0 0 1 1 258 | 1 0 0 0 0 0 1 0 259 | 1 0 1 0 0 0 1 1 260 | 1 0 1 0 0 0 1 1 261 | 0 0 0 0 1 1 0 1 262 | 0 0 0 0 0 0 1 0 263 | 0 0 1 0 0 0 1 1 264 | 1 0 1 0 0 0 1 1 265 | 1 0 1 0 0 0 1 1 266 | 1 0 0 0 0 0 1 0 267 | 0 0 0 0 0 0 1 0 268 | 1 0 1 0 0 0 1 0 269 | 1 0 1 0 0 0 1 1 270 | 0 0 0 0 0 0 1 1 271 | 1 0 1 0 0 0 1 1 272 | 0 0 1 0 0 0 1 1 273 | 0 0 0 0 0 0 1 0 274 | 1 0 1 0 0 0 1 1 275 | 0 0 0 0 0 0 1 0 276 | 0 0 0 0 0 0 1 0 277 | 0 0 0 0 0 0 1 0 278 | 0 0 0 0 0 0 1 0 279 | 0 0 0 0 0 0 1 1 280 | 1 0 1 0 0 0 1 0 281 | 0 0 0 0 0 0 1 0 282 | 0 0 0 0 0 0 1 0 283 | 1 0 0 0 0 0 1 0 284 | 1 0 0 0 0 0 1 0 285 | 0 0 0 0 0 0 0 0 286 | 0 0 0 0 0 0 1 0 287 | 0 0 1 0 0 0 1 0 288 | 1 0 0 0 0 0 1 0 289 | 1 0 0 0 0 0 1 1 290 | 1 0 1 0 0 0 1 0 291 | 0 0 1 0 0 0 0 1 292 | 1 0 1 0 0 0 0 1 293 | 0 0 1 0 0 0 1 0 294 | 0 0 1 0 0 0 1 1 295 | 1 1 1 0 0 1 0 1 296 | 1 0 1 0 0 0 1 0 297 | 0 0 0 0 0 0 1 0 298 | 1 0 0 0 0 0 1 0 299 | 1 0 0 0 0 0 1 0 300 | 0 0 1 0 0 0 1 0 301 | 1 0 1 0 0 0 1 0 302 | 1 0 0 0 0 0 1 0 303 | 0 0 0 0 0 0 1 0 304 | 1 1 1 0 0 1 0 1 305 | 1 0 1 0 0 0 1 1 306 | 0 0 0 0 0 0 1 0 307 | 1 0 1 0 0 0 1 0 308 | 1 0 1 0 0 0 1 0 309 | 0 0 0 0 0 0 1 1 310 | 1 1 0 0 0 1 0 1 311 | 0 0 1 0 0 0 0 1 312 | 0 0 1 0 0 0 1 1 313 | 1 0 1 0 0 0 1 1 314 | 1 1 0 0 0 1 0 1 315 | 1 0 1 0 0 0 1 1 316 | 1 0 1 0 0 0 0 1 317 | 0 0 0 0 1 1 0 1 318 | 0 0 0 0 0 0 1 0 319 | 1 0 1 0 0 0 1 0 320 | 0 0 1 0 0 0 1 1 321 | 1 1 1 0 0 1 0 1 322 | 1 0 1 0 0 0 1 1 323 | 0 0 0 0 0 0 1 0 324 | 0 0 0 0 0 0 1 0 325 | 1 0 1 0 0 0 1 0 326 | 1 0 1 0 0 0 1 1 327 | 1 0 1 0 0 0 1 1 328 | 1 0 0 0 0 0 1 0 329 | 0 0 1 0 0 0 1 0 330 | 0 0 0 0 0 0 1 0 331 | 1 0 0 0 0 0 0 0 332 | 1 0 1 0 0 0 1 0 333 | 0 0 0 0 0 0 1 0 334 | 1 0 0 0 0 0 1 0 335 | 0 0 0 0 0 0 1 0 336 | 1 1 1 0 0 1 0 1 337 | 1 0 1 0 0 0 1 0 338 | 1 0 0 0 0 0 1 1 339 | 0 0 1 0 0 0 1 1 340 | 1 0 1 0 0 0 1 0 341 | 1 0 1 0 0 0 1 1 342 | 0 0 0 0 0 0 1 0 343 | 0 0 1 0 0 0 1 1 344 | 1 0 0 0 0 0 1 0 345 | 1 0 0 0 0 0 1 0 346 | 0 0 0 0 0 0 1 0 347 | 1 0 0 0 0 0 1 0 348 | 1 0 1 0 0 0 1 1 349 | 1 1 1 0 0 1 0 1 350 | 1 0 0 0 0 0 1 0 351 | 1 1 1 0 0 1 0 1 352 | 1 0 1 0 0 0 1 1 353 | 0 0 1 0 0 0 1 1 354 | 0 0 0 0 0 0 1 0 355 | 1 0 1 0 0 0 1 0 356 | 1 0 1 0 0 0 1 0 357 | 1 0 1 0 0 0 1 1 358 | 1 0 1 0 0 0 1 1 359 | 1 0 1 0 0 0 1 1 360 | 1 0 1 0 0 0 1 1 361 | 0 0 1 0 0 0 1 1 362 | 1 1 1 0 0 1 0 1 363 | 1 0 1 0 0 0 1 0 364 | 0 0 0 0 0 0 1 0 365 | 1 0 1 0 0 0 1 1 366 | 1 0 1 0 0 0 1 1 367 | 1 0 1 0 0 0 0 1 368 | 1 0 1 0 0 0 1 0 369 | 1 0 1 0 0 0 1 1 370 | 1 0 0 0 0 0 1 0 371 | 1 0 1 0 0 0 1 1 372 | 1 1 0 0 0 1 0 0 373 | 1 0 0 0 0 0 1 0 374 | 1 0 0 0 0 0 1 0 375 | 1 0 0 0 0 0 1 0 376 | 1 0 0 0 0 0 1 1 377 | 1 0 1 0 0 0 1 0 378 | 1 0 1 0 0 0 1 0 379 | 0 0 0 0 0 0 1 0 380 | 1 0 0 0 0 0 1 0 381 | 0 0 0 0 0 0 1 1 382 | 1 0 1 0 0 0 1 1 383 | 0 0 0 0 0 0 1 0 384 | 1 0 0 0 0 0 1 0 385 | 0 0 0 0 0 0 1 0 386 | 0 0 0 0 0 0 1 0 387 | 0 0 1 0 0 0 1 1 388 | 0 0 0 0 0 0 1 0 389 | 0 0 0 0 0 0 1 0 390 | 1 0 0 0 0 0 1 0 391 | 1 0 1 0 0 0 1 1 392 | 0 0 0 0 0 0 1 0 393 | 1 0 1 0 0 0 1 0 394 | 1 0 1 0 0 0 1 1 395 | 1 0 1 0 0 0 0 1 396 | 0 0 0 0 0 0 1 0 397 | 1 0 0 0 0 0 1 0 398 | 0 0 1 0 0 0 1 1 399 | 0 0 0 0 0 0 1 0 400 | 0 0 1 0 0 0 1 0 401 | 1 0 1 0 0 0 1 1 402 | 1 0 0 0 0 0 1 0 403 | 1 0 1 0 0 0 1 1 404 | 0 0 0 0 0 0 1 1 405 | 0 0 1 0 0 0 1 1 406 | 1 0 1 0 0 0 1 1 407 | 0 0 1 0 0 0 1 0 408 | 0 0 0 0 0 0 1 0 409 | 0 0 0 0 0 0 1 0 410 | 1 0 1 0 0 0 1 1 411 | 1 0 1 0 0 0 1 1 412 | 1 0 0 0 0 0 1 0 413 | 1 0 0 0 0 0 1 0 414 | 1 0 1 0 0 0 1 1 415 | 0 0 1 0 1 1 0 1 416 | 0 0 1 0 0 0 1 1 417 | 1 0 0 0 0 0 1 0 418 | 0 0 0 0 0 0 1 0 419 | 1 0 0 0 0 0 1 0 420 | 1 0 1 0 0 0 1 1 421 | 0 0 0 0 0 0 1 0 422 | 1 0 1 0 0 0 1 1 423 | 1 0 1 0 0 0 1 1 424 | 1 0 1 0 0 0 1 1 425 | 0 0 0 0 0 0 1 1 426 | 1 0 0 0 0 0 1 0 427 | 1 1 0 0 0 1 0 1 428 | 0 0 0 0 0 0 1 0 429 | 0 0 0 0 0 0 1 0 430 | 0 0 0 0 0 0 1 0 431 | 0 0 0 0 0 0 1 1 432 | 1 0 1 0 0 0 1 0 433 | 0 0 1 0 0 0 0 1 434 | 0 0 0 0 0 0 0 0 435 | 0 0 0 0 0 0 1 0 436 | 1 0 1 0 0 0 0 1 437 | 1 0 0 0 0 0 1 0 438 | 1 0 1 0 0 0 0 1 439 | 0 0 0 0 0 0 1 0 440 | 0 0 1 0 0 0 1 0 441 | 1 0 0 0 0 0 1 0 442 | 1 0 0 0 0 0 1 0 443 | 1 0 0 0 0 0 1 0 444 | 1 0 1 0 0 0 1 1 445 | 1 0 1 0 0 0 1 1 446 | 0 0 0 0 0 0 1 0 447 | 0 0 1 0 1 1 0 1 448 | 0 0 1 0 0 0 1 1 449 | 1 0 1 0 0 0 1 1 450 | 1 1 0 0 0 1 0 0 451 | 0 0 1 0 0 0 1 0 452 | 1 0 0 0 0 0 1 1 453 | 1 0 0 0 0 0 1 0 454 | 1 0 1 0 0 0 1 1 455 | 0 0 1 0 0 0 1 1 456 | 0 0 1 0 0 0 1 1 457 | 0 0 1 0 0 0 0 0 458 | 1 0 0 0 0 0 1 0 459 | 0 0 0 0 0 0 1 0 460 | 0 0 0 0 0 0 1 0 461 | 0 0 0 0 0 0 1 0 462 | 1 0 0 0 0 0 1 0 463 | 1 0 0 0 0 0 1 0 464 | 0 0 0 0 0 0 1 0 465 | 1 0 1 0 0 0 1 1 466 | 1 0 0 0 0 0 1 0 467 | 0 0 1 0 0 0 1 1 468 | 0 0 0 0 0 0 1 0 469 | 1 0 1 0 0 0 1 1 470 | 0 0 0 0 0 0 1 0 471 | 0 0 1 0 0 0 1 1 472 | 1 0 1 0 0 0 1 1 473 | 1 0 1 0 0 0 1 1 474 | 0 0 0 0 0 0 1 0 475 | 1 1 1 0 0 1 0 1 476 | 1 0 1 0 0 0 1 1 477 | 0 0 0 0 0 0 1 1 478 | 0 0 0 0 0 0 1 0 479 | 1 0 0 0 0 0 1 0 480 | 1 0 1 0 0 0 1 0 481 | 1 0 0 0 0 0 1 0 482 | 0 0 0 0 0 0 1 0 483 | 0 0 0 0 0 0 1 1 484 | 1 0 1 0 0 0 1 0 485 | 0 0 1 0 0 0 1 0 486 | 1 0 0 0 0 0 1 0 487 | 1 0 0 0 0 0 1 0 488 | 1 0 1 0 0 0 1 1 489 | 1 0 1 0 0 0 1 1 490 | 0 0 1 0 0 0 1 0 491 | 1 0 1 0 0 0 1 0 492 | 0 0 0 0 0 0 1 0 493 | 1 0 1 0 0 0 1 0 494 | 1 0 1 0 0 0 0 0 495 | 0 0 1 0 0 0 1 0 496 | 0 0 1 0 0 0 1 0 497 | 0 0 0 0 0 0 1 1 498 | 0 0 1 1 0 0 1 1 499 | 1 0 1 0 0 0 1 1 500 | 1 0 0 0 0 0 1 0 501 | 0 0 0 0 0 0 1 0 502 | 0 0 1 0 0 0 1 0 503 | 0 0 0 0 0 0 0 0 504 | 1 0 1 0 0 0 1 1 505 | 1 0 1 0 0 0 1 0 506 | 1 0 1 0 0 0 1 1 507 | 0 0 1 0 0 0 1 1 508 | 0 0 1 0 0 0 0 1 509 | 0 0 1 0 0 0 1 1 510 | 1 0 0 0 0 0 1 0 511 | 1 1 1 0 0 1 0 1 512 | 1 0 0 0 0 0 1 1 513 | 0 0 0 0 0 0 1 0 514 | 0 0 0 0 0 0 1 0 515 | 0 0 0 0 0 0 1 0 516 | 0 0 1 0 0 0 0 1 517 | 1 0 1 0 0 0 1 1 518 | 0 0 1 0 0 0 1 1 519 | 1 0 1 0 0 0 1 1 520 | 0 0 0 0 0 0 1 0 521 | 1 0 0 0 0 0 1 0 522 | 0 0 0 0 0 0 1 0 523 | 1 0 1 0 0 0 1 1 524 | 1 0 1 0 0 0 1 0 525 | 1 0 0 0 0 0 1 0 526 | 0 0 1 0 0 0 1 0 527 | 0 0 0 0 0 0 1 0 528 | 0 0 0 0 0 0 1 0 529 | 1 0 1 0 0 0 1 1 530 | 0 0 0 0 0 0 1 0 531 | 1 0 1 0 0 0 0 1 532 | 1 0 1 0 0 0 1 1 533 | 0 0 0 0 0 0 1 0 534 | 1 0 1 0 0 0 1 1 535 | 0 0 0 0 0 0 1 1 536 | 0 0 1 0 0 0 1 1 537 | 1 1 0 0 0 1 0 1 538 | 0 0 0 0 0 0 1 0 539 | 1 0 1 0 0 0 1 1 540 | 0 0 0 0 0 0 1 0 541 | 0 0 1 0 0 0 1 1 542 | 0 0 1 0 0 0 1 1 543 | 0 0 1 0 0 0 1 1 544 | 0 0 0 0 0 0 0 0 545 | 0 0 1 0 0 0 1 0 546 | 0 0 1 0 0 0 1 1 547 | 0 0 0 0 0 0 1 0 548 | 1 0 0 0 0 0 1 0 549 | 0 0 0 0 0 0 1 1 550 | 1 0 1 0 0 0 1 1 551 | 0 0 0 0 0 0 1 0 552 | 0 0 1 0 0 0 1 0 553 | 0 0 0 0 0 0 1 0 554 | 1 0 1 0 0 0 1 1 555 | 1 0 1 0 0 0 1 1 556 | 0 0 1 0 0 0 1 1 557 | 1 0 1 0 0 0 1 0 558 | 1 0 1 0 0 0 1 1 559 | 1 0 1 0 0 0 1 1 560 | 1 0 1 0 0 0 0 1 561 | 0 0 0 0 0 0 1 0 562 | 0 0 1 0 0 0 1 1 563 | 0 0 0 0 0 0 1 0 564 | 1 0 0 0 0 0 1 0 565 | 0 0 1 0 0 0 1 1 566 | 1 1 1 0 0 1 0 1 567 | 1 0 1 0 0 0 1 1 568 | 1 0 1 0 0 0 1 0 569 | 1 0 0 0 0 0 1 0 570 | 0 0 0 0 0 0 0 0 571 | 1 0 1 0 0 0 1 1 572 | 0 0 1 0 0 0 1 1 573 | 1 0 0 0 0 0 1 0 574 | 0 0 0 0 0 0 1 0 575 | 1 1 1 0 0 1 0 1 576 | 0 0 1 0 0 0 1 1 577 | 0 0 1 0 0 0 1 1 578 | 1 0 0 0 0 0 1 0 579 | 1 0 1 0 0 0 1 1 580 | 1 0 0 0 0 0 1 0 581 | 1 0 0 0 0 0 1 0 582 | 0 0 1 0 0 0 1 1 583 | 1 0 1 0 0 0 1 0 584 | 1 0 1 0 0 0 0 0 585 | 0 0 0 0 0 0 1 0 586 | 1 0 1 0 0 0 1 1 587 | 1 0 0 0 0 0 1 0 588 | 0 0 0 0 0 0 1 0 589 | 1 0 1 0 0 0 1 0 590 | 1 0 1 0 0 0 1 1 591 | 1 0 1 0 0 0 1 1 592 | 0 0 1 0 0 0 1 1 593 | 1 0 1 0 0 0 1 1 594 | 1 0 1 0 0 0 1 1 595 | 1 1 1 0 0 1 0 1 596 | 0 0 0 0 0 0 1 0 597 | 0 0 1 0 0 0 1 1 598 | 0 0 0 0 0 0 1 0 599 | 0 0 1 0 0 0 1 1 600 | 0 0 1 0 0 0 1 1 601 | 0 0 1 0 0 0 1 1 602 | 0 0 0 0 0 0 1 0 603 | 0 0 1 0 0 0 1 1 604 | 1 0 0 0 0 0 1 1 605 | 0 0 0 0 0 0 1 0 606 | 1 0 0 0 0 0 1 0 607 | 0 0 0 0 0 0 1 0 608 | 0 0 0 0 0 0 1 0 609 | 1 0 0 0 0 0 1 0 610 | 0 0 0 0 0 0 1 0 611 | 0 0 0 0 0 0 1 0 612 | 0 0 1 0 0 0 1 0 613 | 0 0 1 0 0 0 1 1 614 | 0 0 0 0 0 0 1 0 615 | 1 1 0 0 0 1 0 0 616 | 0 0 0 0 0 0 1 0 617 | 0 0 0 0 0 0 0 0 618 | 0 0 0 0 0 0 1 0 619 | 0 0 0 0 0 0 0 0 620 | 0 0 1 0 0 0 1 1 621 | 0 0 0 0 0 0 1 0 622 | 0 0 1 0 0 0 1 0 623 | 0 0 0 0 0 0 1 0 624 | 1 0 0 0 0 0 1 1 625 | 1 0 1 0 0 0 1 1 626 | 1 1 0 0 0 1 0 1 627 | 1 0 0 0 0 0 0 0 628 | 1 0 1 0 0 0 1 1 629 | 1 0 1 0 0 0 1 0 630 | 1 0 0 0 0 0 1 0 631 | 1 0 1 0 0 0 1 1 632 | 0 0 0 0 0 0 1 1 633 | 0 0 0 0 0 0 1 0 634 | 0 0 0 0 0 0 1 1 635 | 1 0 1 0 0 0 1 1 636 | 0 0 1 0 0 0 1 1 637 | 1 0 1 0 0 0 1 0 638 | 0 0 1 0 0 0 1 1 639 | 1 0 1 0 0 0 1 1 640 | 1 0 1 0 0 0 1 1 641 | 0 0 0 0 0 0 1 0 642 | 0 0 1 0 0 0 1 1 643 | 1 0 0 0 0 0 1 0 644 | 1 0 0 0 0 0 1 0 645 | 0 0 0 0 0 0 1 0 646 | 0 0 0 0 0 0 1 0 647 | 0 0 0 0 0 0 1 0 648 | 1 0 1 0 0 0 1 1 649 | 0 0 0 0 0 0 1 0 650 | 0 0 1 0 0 0 1 0 651 | 0 0 1 0 0 0 1 0 652 | 1 0 1 0 0 0 1 1 653 | 1 1 1 0 0 1 0 1 654 | 0 0 0 0 0 0 1 0 655 | 0 0 1 0 0 0 1 1 656 | 1 1 1 0 0 1 0 1 657 | 1 0 1 0 0 0 1 1 658 | 1 0 1 0 0 0 1 1 659 | 1 0 1 0 0 0 1 1 660 | 0 0 0 0 0 0 0 0 661 | 1 0 0 0 0 0 1 0 662 | 1 0 1 0 0 0 0 0 663 | 1 0 0 0 0 0 1 1 664 | 1 0 0 0 0 0 1 0 665 | 1 0 0 0 0 0 1 0 666 | 1 0 1 0 0 0 1 1 667 | 1 0 1 0 0 0 1 0 668 | 1 1 0 0 0 1 0 1 669 | 0 1 0 0 0 1 1 1 670 | 0 0 0 0 0 0 1 0 671 | 1 0 1 0 0 0 1 1 672 | 0 0 0 0 0 0 0 0 673 | 0 0 0 0 0 0 1 0 674 | 0 0 1 0 0 0 1 1 675 | 1 0 1 0 0 0 1 0 676 | 0 0 0 0 0 0 1 0 677 | 0 0 0 0 0 0 1 0 678 | 0 0 0 0 0 0 1 0 679 | 1 0 0 0 0 0 1 1 680 | 1 1 0 0 0 1 0 1 681 | 1 0 1 0 0 0 1 1 682 | 1 0 1 0 0 0 1 0 683 | 0 0 0 0 0 0 1 0 684 | 1 0 1 0 0 0 1 1 685 | 0 0 0 0 0 0 1 0 686 | 1 0 1 0 0 0 1 1 687 | 0 0 1 0 0 0 1 1 688 | 0 0 1 0 0 0 1 1 689 | 0 0 1 0 0 0 1 1 690 | 0 0 1 0 0 0 1 1 691 | 1 0 1 0 0 0 0 0 692 | 0 0 1 0 0 0 1 1 693 | 1 0 1 0 0 0 1 1 694 | 1 0 1 0 0 0 1 1 695 | 0 0 1 0 0 0 1 1 696 | 0 0 1 0 0 0 1 1 697 | 1 0 0 0 0 0 1 0 698 | 1 0 0 0 0 0 1 0 699 | 0 0 1 0 0 0 1 1 700 | 1 0 0 0 0 0 1 0 701 | 0 0 0 0 0 0 1 1 702 | 0 0 0 0 0 0 1 0 703 | 0 0 0 0 0 0 1 0 704 | 0 0 0 0 0 0 1 0 705 | 1 0 1 0 0 0 1 1 706 | 1 0 0 0 0 0 1 0 707 | 0 0 0 0 0 0 1 0 708 | 0 0 1 0 0 0 1 1 709 | 0 0 0 0 0 0 1 0 710 | 1 0 1 0 0 0 1 1 711 | 0 0 1 0 0 0 1 1 712 | 1 0 1 0 0 0 1 1 713 | 1 0 1 0 0 0 1 1 714 | 1 0 1 0 0 0 1 0 715 | 1 0 1 0 0 0 1 1 716 | 1 0 0 0 0 0 1 0 717 | 1 0 0 0 0 0 1 0 718 | 1 0 1 0 0 0 1 1 719 | 1 0 0 0 0 0 0 0 720 | 1 0 0 0 0 0 1 0 721 | 1 0 1 0 0 0 0 0 722 | 1 0 1 0 0 0 1 1 723 | 0 0 0 0 0 0 1 0 724 | 1 0 1 0 0 0 1 1 725 | 0 0 1 0 0 0 1 1 726 | 1 0 1 0 0 0 1 1 727 | 1 0 0 0 0 0 1 0 728 | 1 0 1 0 0 0 1 1 729 | 0 0 0 0 0 0 1 0 730 | 0 0 0 0 0 0 1 1 731 | 0 0 1 0 0 0 1 1 732 | 1 0 1 0 0 0 1 1 733 | 1 0 0 0 0 0 1 0 734 | 1 0 1 0 0 0 1 1 735 | 1 0 0 0 0 0 1 0 736 | 0 0 1 0 0 0 1 1 737 | 1 0 1 0 0 0 1 1 738 | 1 0 1 0 0 0 1 1 739 | 0 0 0 0 0 0 1 0 740 | 0 0 1 0 0 0 1 1 741 | 1 0 1 0 0 0 1 1 742 | 0 0 1 0 0 0 1 1 743 | 1 1 1 0 0 1 0 1 744 | 0 0 0 0 0 0 1 0 745 | 0 0 0 0 0 0 1 0 746 | 0 0 0 0 0 0 1 0 747 | 1 0 0 0 0 0 1 0 748 | 0 0 1 0 0 0 1 1 749 | 1 0 1 0 0 0 1 1 750 | 1 0 1 0 0 0 1 0 751 | 1 0 0 0 0 0 1 0 752 | 0 0 0 0 0 0 1 1 753 | 0 0 1 0 0 0 1 0 754 | 1 0 0 0 0 0 1 0 755 | 0 0 0 0 0 0 1 0 756 | 0 0 0 0 0 0 1 0 757 | 1 0 1 0 0 0 1 0 758 | 1 0 1 0 0 0 1 1 759 | 0 0 0 0 0 0 1 0 760 | 1 1 1 0 0 1 0 1 761 | 0 0 0 0 0 0 0 0 762 | 0 0 0 0 0 0 1 0 763 | 1 0 1 0 0 0 1 1 764 | 1 0 1 1 1 1 0 1 765 | 1 0 0 0 0 0 1 0 766 | 1 0 1 0 0 0 1 0 767 | 1 0 1 0 0 0 1 1 768 | 0 0 0 0 0 0 1 0 769 | 1 0 0 0 0 0 1 0 770 | 1 0 0 0 0 0 1 0 771 | 0 0 1 0 0 0 1 1 772 | 1 0 1 0 0 0 1 1 773 | 1 0 0 0 0 0 1 0 774 | 0 0 0 0 0 0 1 0 775 | 0 0 1 0 0 0 1 1 776 | 1 0 1 0 0 0 1 1 777 | 1 0 0 0 0 0 1 0 778 | 0 0 1 0 0 0 1 1 779 | 1 0 0 0 0 0 1 0 780 | 0 0 1 0 0 0 1 1 781 | 0 0 0 0 0 0 1 0 782 | 0 0 0 0 0 0 1 0 783 | 0 0 0 0 0 0 1 0 784 | 0 0 0 0 0 0 1 0 785 | 1 0 0 0 0 0 1 0 786 | 0 0 0 0 0 0 1 0 787 | 1 0 0 0 0 0 1 0 788 | 0 0 1 0 0 0 1 0 789 | 0 0 0 0 0 0 1 0 790 | 1 0 0 0 0 0 1 0 791 | 0 0 0 0 0 0 1 0 792 | 0 0 1 0 0 0 1 1 793 | 0 0 0 0 0 0 1 1 794 | 1 0 1 0 0 0 1 0 795 | 0 0 0 0 0 0 1 0 796 | 1 0 1 0 0 0 0 1 797 | 0 0 0 0 0 0 1 0 798 | 0 0 0 0 0 0 1 0 799 | 0 0 0 0 0 0 1 0 800 | 1 0 1 0 0 0 1 1 801 | 0 0 0 0 0 0 1 0 802 | 0 0 0 0 0 0 1 0 803 | 1 0 1 0 0 0 1 1 804 | 1 0 0 0 0 0 1 1 805 | 1 0 1 0 0 0 1 1 806 | 1 0 0 0 0 0 1 0 807 | 0 0 0 0 0 0 1 1 808 | 1 0 0 0 0 0 1 0 809 | 1 0 1 0 0 0 1 1 810 | 1 1 1 0 0 1 0 1 811 | 1 0 0 0 0 0 1 0 812 | 0 0 1 0 0 0 1 1 813 | 0 0 1 0 0 0 1 1 814 | 0 0 1 0 0 0 1 1 815 | 0 0 0 0 0 0 1 0 816 | 0 0 1 0 0 0 1 1 817 | 1 0 1 0 0 0 1 1 818 | 0 0 0 0 0 0 1 1 819 | 1 0 1 0 0 0 1 1 820 | 0 0 0 0 0 0 1 0 821 | 0 0 0 0 0 0 1 0 822 | 1 0 1 0 0 0 1 1 823 | 1 0 1 0 0 0 1 1 824 | 0 0 0 0 0 0 1 0 825 | 1 1 0 0 0 1 0 1 826 | 0 0 0 0 0 0 1 0 827 | 1 0 1 0 0 0 1 1 828 | 1 0 1 0 0 0 1 1 829 | 1 0 1 0 0 0 1 1 830 | 0 0 0 0 0 0 1 0 831 | 1 0 1 0 0 0 1 0 832 | 0 0 0 0 0 0 1 0 833 | 0 0 0 1 0 0 1 0 834 | 0 0 0 0 0 0 1 1 835 | 0 0 1 0 0 0 1 0 836 | 1 0 1 0 0 0 1 1 837 | 0 0 0 0 0 0 1 0 838 | 1 1 1 0 0 1 0 1 839 | 1 0 0 0 0 0 1 1 840 | 1 1 0 0 0 1 0 0 841 | 1 0 0 0 0 0 0 0 842 | 0 0 0 0 0 0 1 0 843 | 0 0 0 0 0 0 1 0 844 | 0 0 1 0 0 0 1 1 845 | 0 0 1 0 0 0 1 0 846 | 1 0 1 0 0 0 1 1 847 | 1 0 0 0 0 0 0 0 848 | 0 0 1 0 0 0 1 1 849 | 1 0 0 0 0 0 1 0 850 | 0 0 0 0 0 0 1 0 851 | 0 0 0 0 0 0 1 0 852 | 0 0 0 0 0 0 1 0 853 | 0 0 0 0 0 0 1 0 854 | 1 0 1 0 0 0 1 1 855 | 1 0 0 0 0 0 1 0 856 | 0 0 0 0 0 0 1 1 857 | 0 1 0 0 0 1 0 1 858 | 0 0 0 0 0 0 1 1 859 | 0 0 0 0 0 0 1 0 860 | 0 0 0 0 0 0 1 0 861 | 1 0 0 0 0 0 1 0 862 | 0 0 0 0 0 0 1 0 863 | 1 0 0 0 0 0 1 0 864 | 1 0 0 0 0 0 1 0 865 | 0 0 1 0 0 0 1 1 866 | 1 0 0 0 0 0 1 0 867 | 0 0 0 0 0 0 1 0 868 | 1 0 0 0 0 0 1 0 869 | 0 0 0 0 0 0 1 1 870 | 0 0 0 0 0 0 1 0 871 | 1 0 0 0 0 0 1 0 872 | 0 0 0 0 0 0 1 0 873 | 0 0 0 0 0 0 1 0 874 | 1 0 0 0 0 0 1 0 875 | 0 0 0 0 0 0 1 0 876 | 0 0 1 0 0 0 1 1 877 | 1 0 1 0 0 0 0 1 878 | 1 0 1 0 0 0 1 1 879 | 1 0 1 0 0 0 1 1 880 | 1 0 1 0 0 0 1 1 881 | 0 0 1 0 0 0 1 0 882 | 1 0 0 0 0 0 1 0 883 | 1 0 1 0 0 0 1 1 884 | 0 0 0 0 0 0 1 0 885 | 1 0 0 0 0 0 0 0 886 | 1 0 1 0 0 0 1 1 887 | 0 0 0 0 0 0 1 0 888 | 1 0 0 0 0 0 1 0 889 | 1 0 0 0 0 0 1 0 890 | 0 0 0 0 0 0 1 0 891 | 0 0 1 0 0 0 1 1 892 | 1 0 0 0 0 0 1 0 893 | 0 0 0 0 0 0 1 0 894 | 1 0 0 0 0 0 1 0 895 | 1 0 0 0 0 0 1 0 896 | 1 0 1 0 0 0 1 1 897 | 1 0 1 0 0 0 1 1 898 | 1 1 0 0 0 1 0 1 899 | 0 0 0 0 0 0 1 0 900 | 1 0 0 0 0 0 1 0 901 | 1 0 0 0 0 0 1 0 902 | 1 0 1 0 0 0 1 0 903 | 0 0 1 0 0 0 1 0 904 | 0 0 0 0 0 0 1 0 905 | 0 0 1 0 0 0 1 1 906 | 1 0 0 0 0 0 1 0 907 | 0 0 1 0 0 0 1 1 908 | 0 0 1 0 0 0 1 1 909 | 0 0 1 0 0 0 1 1 910 | 0 0 1 0 0 0 1 1 911 | 0 0 1 0 0 0 1 1 912 | 1 1 1 0 0 1 0 1 913 | 1 0 0 0 0 0 1 1 914 | 0 0 1 0 0 0 1 1 915 | 1 1 0 0 0 1 0 0 916 | 0 0 1 0 0 0 1 1 917 | 1 0 0 0 0 0 1 0 918 | 0 0 0 0 0 0 1 0 919 | 1 0 0 0 0 0 1 0 920 | 1 1 0 0 0 1 0 0 921 | 0 0 0 0 0 0 1 0 922 | 1 0 0 0 0 0 1 1 923 | 0 0 0 0 0 0 1 0 924 | 1 0 1 0 0 0 1 1 925 | 0 0 0 0 0 0 1 0 926 | 1 1 1 0 0 1 0 1 927 | 0 0 0 0 0 0 1 0 928 | 1 0 0 0 0 0 1 0 929 | 1 0 1 0 0 0 1 1 930 | 1 0 1 0 0 0 1 1 931 | 1 0 1 0 0 0 1 1 932 | 1 0 1 0 0 0 1 1 933 | 0 0 0 0 0 0 1 0 934 | 1 0 1 0 0 0 1 1 935 | 1 0 1 0 0 0 1 1 936 | 0 0 0 0 0 0 1 0 937 | 1 0 1 0 0 0 1 1 938 | 0 0 1 0 0 0 1 1 939 | 1 0 1 0 0 0 1 0 940 | 1 0 1 0 0 0 1 1 941 | 0 0 0 0 0 0 1 0 942 | 1 0 1 0 0 0 1 1 943 | 0 0 0 0 0 0 1 0 944 | 1 0 1 0 0 0 1 1 945 | 0 0 0 0 0 0 1 0 946 | 0 0 1 0 0 0 1 0 947 | 1 0 0 0 0 0 1 1 948 | 1 0 0 0 0 0 1 0 949 | 0 0 0 0 0 0 1 0 950 | 1 0 1 0 0 0 1 1 951 | 0 1 1 0 0 1 0 1 952 | 1 0 1 0 0 0 1 1 953 | 0 0 1 0 0 0 1 1 954 | 1 0 1 0 0 0 1 1 955 | 0 0 1 0 0 0 0 1 956 | 1 0 1 0 0 0 1 1 957 | 1 0 0 0 0 0 1 0 958 | 1 0 0 0 0 0 1 0 959 | 1 0 0 0 0 0 1 0 960 | 0 0 0 0 0 0 1 0 961 | 1 1 0 0 0 1 0 1 962 | 1 0 1 0 0 0 1 1 963 | 1 0 1 0 0 0 1 1 964 | 0 0 0 0 0 0 1 0 965 | 1 0 0 0 0 0 1 0 966 | 0 0 0 0 0 0 1 0 967 | 1 0 0 0 0 0 1 0 968 | 1 0 0 0 0 0 1 1 969 | 1 0 0 0 0 0 1 0 970 | 1 0 0 0 0 0 1 0 971 | 0 0 0 0 0 0 1 0 972 | 1 0 1 0 0 0 1 1 973 | 0 0 0 0 0 0 1 0 974 | 0 0 0 0 0 0 0 0 975 | 1 0 1 0 0 0 1 1 976 | 1 0 1 0 0 0 1 1 977 | 1 0 0 0 0 0 1 0 978 | 0 0 1 0 0 0 1 1 979 | 1 0 0 0 0 0 1 0 980 | 0 0 0 0 0 0 1 1 981 | 0 0 0 0 0 0 1 0 982 | 0 0 1 0 0 0 1 1 983 | 0 0 0 0 0 0 1 1 984 | 0 0 0 0 0 0 1 0 985 | 0 0 0 0 0 0 1 0 986 | 1 1 0 0 0 1 0 1 987 | 0 0 1 0 0 0 1 0 988 | 1 0 0 0 0 0 1 0 989 | 0 0 0 0 0 0 1 0 990 | 1 0 0 0 0 0 1 0 991 | 1 0 1 0 0 0 1 1 992 | 0 0 0 0 0 0 1 0 993 | 0 0 1 0 0 0 0 1 994 | 1 0 1 0 0 0 1 1 995 | 0 0 1 0 0 0 1 1 996 | 1 0 1 0 0 0 1 1 997 | 1 0 0 0 0 0 1 0 998 | 1 0 0 0 0 0 1 0 999 | 1 0 1 0 0 0 0 1 1000 | 0 0 0 0 0 0 1 0 1001 | 0 0 0 0 0 0 1 0 1002 | -------------------------------------------------------------------------------- /Docmentation/Report.bbl: -------------------------------------------------------------------------------- 1 | % $ biblatex auxiliary file $ 2 | % $ biblatex bbl format version 3.0 $ 3 | % Do not modify the above lines! 4 | % 5 | % This is an auxiliary file used by the 'biblatex' package. 6 | % This file may safely be deleted. It will be recreated by 7 | % biber as required. 8 | % 9 | \begingroup 10 | \makeatletter 11 | \@ifundefined{ver@biblatex.sty} 12 | {\@latex@error 13 | {Missing 'biblatex' package} 14 | {The bibliography requires the 'biblatex' package.} 15 | \aftergroup\endinput} 16 | {} 17 | \endgroup 18 | 19 | 20 | \refsection{0} 21 | \datalist[entry]{none/global//global/global} 22 | \entry{spirtes1991algorithm}{article}{} 23 | \name{author}{2}{}{% 24 | {{hash=f0924fa092ce0a8f24b79fcf1e746c8f}{% 25 | family={Spirtes}, 26 | familyi={S\bibinitperiod}, 27 | given={Peter}, 28 | giveni={P\bibinitperiod}}}% 29 | {{hash=d92f65fed9d3110577c6ff13a43603b6}{% 30 | family={Glymour}, 31 | familyi={G\bibinitperiod}, 32 | given={Clark}, 33 | giveni={C\bibinitperiod}}}% 34 | } 35 | \list{publisher}{1}{% 36 | {Sage Publications Sage CA: Thousand Oaks, CA}% 37 | } 38 | \strng{namehash}{1a7a60fd207ba93151ece7d4c9929a8d} 39 | \strng{fullhash}{1a7a60fd207ba93151ece7d4c9929a8d} 40 | \strng{bibnamehash}{1a7a60fd207ba93151ece7d4c9929a8d} 41 | \strng{authorbibnamehash}{1a7a60fd207ba93151ece7d4c9929a8d} 42 | \strng{authornamehash}{1a7a60fd207ba93151ece7d4c9929a8d} 43 | \strng{authorfullhash}{1a7a60fd207ba93151ece7d4c9929a8d} 44 | \field{sortinit}{1} 45 | \field{sortinithash}{2174f786c6195e7fe2ee1c229b416e29} 46 | \field{labelnamesource}{author} 47 | \field{labeltitlesource}{title} 48 | \field{journaltitle}{Social science computer review} 49 | \field{number}{1} 50 | \field{title}{An algorithm for fast recovery of sparse causal graphs} 51 | \field{volume}{9} 52 | \field{year}{1991} 53 | \field{pages}{62\bibrangedash 72} 54 | \range{pages}{11} 55 | \endentry 56 | \entry{colombo2012learning}{article}{} 57 | \name{author}{4}{}{% 58 | {{hash=e1fbe553ae8384b11ac51e5da7d67b1f}{% 59 | family={Colombo}, 60 | familyi={C\bibinitperiod}, 61 | given={Diego}, 62 | giveni={D\bibinitperiod}}}% 63 | {{hash=8f905a89e7bf1cc9d54e6934783ebb3f}{% 64 | family={Maathuis}, 65 | familyi={M\bibinitperiod}, 66 | given={Marloes\bibnamedelima H}, 67 | giveni={M\bibinitperiod\bibinitdelim H\bibinitperiod}}}% 68 | {{hash=df9a0e9859bb9965919cd59d2523022d}{% 69 | family={Kalisch}, 70 | familyi={K\bibinitperiod}, 71 | given={Markus}, 72 | giveni={M\bibinitperiod}}}% 73 | {{hash=eabf99a26b5a1ac7dd40719ea6e697e2}{% 74 | family={Richardson}, 75 | familyi={R\bibinitperiod}, 76 | given={Thomas\bibnamedelima S}, 77 | giveni={T\bibinitperiod\bibinitdelim S\bibinitperiod}}}% 78 | } 79 | \list{publisher}{1}{% 80 | {JSTOR}% 81 | } 82 | \strng{namehash}{1716a3dca8d3cc0e64ec4faef0ef9597} 83 | \strng{fullhash}{0e42da14e178e2444a6ed09f14ec437d} 84 | \strng{bibnamehash}{0e42da14e178e2444a6ed09f14ec437d} 85 | \strng{authorbibnamehash}{0e42da14e178e2444a6ed09f14ec437d} 86 | \strng{authornamehash}{1716a3dca8d3cc0e64ec4faef0ef9597} 87 | \strng{authorfullhash}{0e42da14e178e2444a6ed09f14ec437d} 88 | \field{extraname}{1} 89 | \field{sortinit}{2} 90 | \field{sortinithash}{cbff857e587bcb4635511624d773949e} 91 | \field{labelnamesource}{author} 92 | \field{labeltitlesource}{title} 93 | \field{journaltitle}{The Annals of Statistics} 94 | \field{title}{Learning high-dimensional directed acyclic graphs with latent and selection variables} 95 | \field{year}{2012} 96 | \field{pages}{294\bibrangedash 321} 97 | \range{pages}{28} 98 | \endentry 99 | \entry{kalisch_hauser_maechler}{misc}{} 100 | \name{author}{3}{}{% 101 | {{hash=df9a0e9859bb9965919cd59d2523022d}{% 102 | family={Kalisch}, 103 | familyi={K\bibinitperiod}, 104 | given={Markus}, 105 | giveni={M\bibinitperiod}}}% 106 | {{hash=306794240c0c21f49e64540286ef1fda}{% 107 | family={Hauser}, 108 | familyi={H\bibinitperiod}, 109 | given={Alain}, 110 | giveni={A\bibinitperiod}}}% 111 | {{hash=0041cc0eb4aa28929ffbd059d5e4add5}{% 112 | family={Maechler}, 113 | familyi={M\bibinitperiod}, 114 | given={Martin}, 115 | giveni={M\bibinitperiod}}}% 116 | } 117 | \list{publisher}{1}{% 118 | {Comprehensive R Archive Network (CRAN)}% 119 | } 120 | \strng{namehash}{6e2149147e7d17f211def7d0e5cd65f9} 121 | \strng{fullhash}{6e2149147e7d17f211def7d0e5cd65f9} 122 | \strng{bibnamehash}{6e2149147e7d17f211def7d0e5cd65f9} 123 | \strng{authorbibnamehash}{6e2149147e7d17f211def7d0e5cd65f9} 124 | \strng{authornamehash}{6e2149147e7d17f211def7d0e5cd65f9} 125 | \strng{authorfullhash}{6e2149147e7d17f211def7d0e5cd65f9} 126 | \field{sortinit}{4} 127 | \field{sortinithash}{11cdaee3b18e01d77f3f428b13c1fc76} 128 | \field{labelnamesource}{author} 129 | \field{labeltitlesource}{title} 130 | \field{journaltitle}{The Comprehensive R Archive Network} 131 | \field{title}{Methods for Graphical Models and Causal Inference [R package pcalg version 2.6-0]} 132 | \verb{urlraw} 133 | \verb https://cran.r-project.org/web/packages/pcalg/index.html 134 | \endverb 135 | \verb{url} 136 | \verb https://cran.r-project.org/web/packages/pcalg/index.html 137 | \endverb 138 | \endentry 139 | \entry{colombo2014order}{article}{} 140 | \name{author}{2}{}{% 141 | {{hash=e1fbe553ae8384b11ac51e5da7d67b1f}{% 142 | family={Colombo}, 143 | familyi={C\bibinitperiod}, 144 | given={Diego}, 145 | giveni={D\bibinitperiod}}}% 146 | {{hash=8f905a89e7bf1cc9d54e6934783ebb3f}{% 147 | family={Maathuis}, 148 | familyi={M\bibinitperiod}, 149 | given={Marloes\bibnamedelima H}, 150 | giveni={M\bibinitperiod\bibinitdelim H\bibinitperiod}}}% 151 | } 152 | \list{publisher}{1}{% 153 | {JMLR. org}% 154 | } 155 | \strng{namehash}{9c9483fa0d5049c233794e89576c46cf} 156 | \strng{fullhash}{9c9483fa0d5049c233794e89576c46cf} 157 | \strng{bibnamehash}{9c9483fa0d5049c233794e89576c46cf} 158 | \strng{authorbibnamehash}{9c9483fa0d5049c233794e89576c46cf} 159 | \strng{authornamehash}{9c9483fa0d5049c233794e89576c46cf} 160 | \strng{authorfullhash}{9c9483fa0d5049c233794e89576c46cf} 161 | \field{sortinit}{5} 162 | \field{sortinithash}{3c19c3776b658b3558e9e2e4840c01e2} 163 | \field{labelnamesource}{author} 164 | \field{labeltitlesource}{title} 165 | \field{journaltitle}{The Journal of Machine Learning Research} 166 | \field{number}{1} 167 | \field{title}{Order-independent constraint-based causal structure learning} 168 | \field{volume}{15} 169 | \field{year}{2014} 170 | \field{pages}{3741\bibrangedash 3782} 171 | \range{pages}{42} 172 | \endentry 173 | \entry{piatetsky}{misc}{} 174 | \name{author}{1}{}{% 175 | {{hash=e103478863614965865b6b083d948f40}{% 176 | family={Piatetsky}, 177 | familyi={P\bibinitperiod}, 178 | given={Gregory}, 179 | giveni={G\bibinitperiod}}}% 180 | } 181 | \strng{namehash}{e103478863614965865b6b083d948f40} 182 | \strng{fullhash}{e103478863614965865b6b083d948f40} 183 | \strng{bibnamehash}{e103478863614965865b6b083d948f40} 184 | \strng{authorbibnamehash}{e103478863614965865b6b083d948f40} 185 | \strng{authornamehash}{e103478863614965865b6b083d948f40} 186 | \strng{authorfullhash}{e103478863614965865b6b083d948f40} 187 | \field{sortinit}{1} 188 | \field{sortinithash}{2174f786c6195e7fe2ee1c229b416e29} 189 | \field{labelnamesource}{author} 190 | \field{labeltitlesource}{title} 191 | \field{journaltitle}{KDnuggets Analytics Big Data Data Mining and Data Science} 192 | \field{title}{KDnuggets} 193 | \verb{urlraw} 194 | \verb https://www.kdnuggets.com/2018/05/poll-tools-analytics-data-science-machine-learning-results.html 195 | \endverb 196 | \verb{url} 197 | \verb https://www.kdnuggets.com/2018/05/poll-tools-analytics-data-science-machine-learning-results.html 198 | \endverb 199 | \endentry 200 | \entry{ogrady_2019}{misc}{} 201 | \name{author}{1}{}{% 202 | {{hash=12dfa4fd8508311b6d197502576434fe}{% 203 | family={O'Grady}, 204 | familyi={O\bibinitperiod}, 205 | given={Stephen}, 206 | giveni={S\bibinitperiod}}}% 207 | } 208 | \strng{namehash}{12dfa4fd8508311b6d197502576434fe} 209 | \strng{fullhash}{12dfa4fd8508311b6d197502576434fe} 210 | \strng{bibnamehash}{12dfa4fd8508311b6d197502576434fe} 211 | \strng{authorbibnamehash}{12dfa4fd8508311b6d197502576434fe} 212 | \strng{authornamehash}{12dfa4fd8508311b6d197502576434fe} 213 | \strng{authorfullhash}{12dfa4fd8508311b6d197502576434fe} 214 | \field{sortinit}{1} 215 | \field{sortinithash}{2174f786c6195e7fe2ee1c229b416e29} 216 | \field{labelnamesource}{author} 217 | \field{labeltitlesource}{title} 218 | \field{journaltitle}{tecosystems} 219 | \field{month}{3} 220 | \field{title}{The RedMonk Programming Language Rankings: January 2019} 221 | \field{year}{2019} 222 | \verb{urlraw} 223 | \verb https://redmonk.com/sogrady/2019/03/20/language-rankings-1-19/ 224 | \endverb 225 | \verb{url} 226 | \verb https://redmonk.com/sogrady/2019/03/20/language-rankings-1-19/ 227 | \endverb 228 | \endentry 229 | \entry{verma1990causal}{incollection}{} 230 | \name{author}{2}{}{% 231 | {{hash=2e06f78670eb35570c8e647e35752258}{% 232 | family={Verma}, 233 | familyi={V\bibinitperiod}, 234 | given={Thomas}, 235 | giveni={T\bibinitperiod}}}% 236 | {{hash=809f695b398afbb54b544c49e8d1bbbb}{% 237 | family={Pearl}, 238 | familyi={P\bibinitperiod}, 239 | given={Judea}, 240 | giveni={J\bibinitperiod}}}% 241 | } 242 | \list{publisher}{1}{% 243 | {Elsevier}% 244 | } 245 | \strng{namehash}{d6bfa96cdb6186a1452295c2e7176070} 246 | \strng{fullhash}{d6bfa96cdb6186a1452295c2e7176070} 247 | \strng{bibnamehash}{d6bfa96cdb6186a1452295c2e7176070} 248 | \strng{authorbibnamehash}{d6bfa96cdb6186a1452295c2e7176070} 249 | \strng{authornamehash}{d6bfa96cdb6186a1452295c2e7176070} 250 | \strng{authorfullhash}{d6bfa96cdb6186a1452295c2e7176070} 251 | \field{sortinit}{1} 252 | \field{sortinithash}{2174f786c6195e7fe2ee1c229b416e29} 253 | \field{labelnamesource}{author} 254 | \field{labeltitlesource}{title} 255 | \field{booktitle}{Machine Intelligence and Pattern Recognition} 256 | \field{title}{Causal networks: Semantics and expressiveness} 257 | \field{volume}{9} 258 | \field{year}{1990} 259 | \field{pages}{69\bibrangedash 76} 260 | \range{pages}{8} 261 | \endentry 262 | \entry{zhang2008causal}{article}{} 263 | \name{author}{1}{}{% 264 | {{hash=00b06765d4d041da464652a126cfa7c1}{% 265 | family={Zhang}, 266 | familyi={Z\bibinitperiod}, 267 | given={Jiji}, 268 | giveni={J\bibinitperiod}}}% 269 | } 270 | \strng{namehash}{00b06765d4d041da464652a126cfa7c1} 271 | \strng{fullhash}{00b06765d4d041da464652a126cfa7c1} 272 | \strng{bibnamehash}{00b06765d4d041da464652a126cfa7c1} 273 | \strng{authorbibnamehash}{00b06765d4d041da464652a126cfa7c1} 274 | \strng{authornamehash}{00b06765d4d041da464652a126cfa7c1} 275 | \strng{authorfullhash}{00b06765d4d041da464652a126cfa7c1} 276 | \field{extraname}{1} 277 | \field{sortinit}{1} 278 | \field{sortinithash}{2174f786c6195e7fe2ee1c229b416e29} 279 | \field{labelnamesource}{author} 280 | \field{labeltitlesource}{title} 281 | \field{journaltitle}{Journal of Machine Learning Research} 282 | \field{number}{Jul} 283 | \field{title}{Causal reasoning with ancestral graphs} 284 | \field{volume}{9} 285 | \field{year}{2008} 286 | \field{pages}{1437\bibrangedash 1474} 287 | \range{pages}{38} 288 | \endentry 289 | \entry{barber_2012}{book}{} 290 | \name{author}{1}{}{% 291 | {{hash=9a97f74e5fb11fe785cbe0a83fc5276c}{% 292 | family={Barber}, 293 | familyi={B\bibinitperiod}, 294 | given={David}, 295 | giveni={D\bibinitperiod}}}% 296 | } 297 | \list{publisher}{1}{% 298 | {Cambridge University Press}% 299 | } 300 | \strng{namehash}{9a97f74e5fb11fe785cbe0a83fc5276c} 301 | \strng{fullhash}{9a97f74e5fb11fe785cbe0a83fc5276c} 302 | \strng{bibnamehash}{9a97f74e5fb11fe785cbe0a83fc5276c} 303 | \strng{authorbibnamehash}{9a97f74e5fb11fe785cbe0a83fc5276c} 304 | \strng{authornamehash}{9a97f74e5fb11fe785cbe0a83fc5276c} 305 | \strng{authorfullhash}{9a97f74e5fb11fe785cbe0a83fc5276c} 306 | \field{sortinit}{1} 307 | \field{sortinithash}{2174f786c6195e7fe2ee1c229b416e29} 308 | \field{labelnamesource}{author} 309 | \field{labeltitlesource}{title} 310 | \field{title}{Bayesian Reasoning and Machine Learning} 311 | \field{year}{2012} 312 | \verb{doi} 313 | \verb 10.1017/CBO9780511804779 314 | \endverb 315 | \endentry 316 | \entry{pearl2003causality}{article}{} 317 | \name{author}{1}{}{% 318 | {{hash=809f695b398afbb54b544c49e8d1bbbb}{% 319 | family={Pearl}, 320 | familyi={P\bibinitperiod}, 321 | given={Judea}, 322 | giveni={J\bibinitperiod}}}% 323 | } 324 | \strng{namehash}{809f695b398afbb54b544c49e8d1bbbb} 325 | \strng{fullhash}{809f695b398afbb54b544c49e8d1bbbb} 326 | \strng{bibnamehash}{809f695b398afbb54b544c49e8d1bbbb} 327 | \strng{authorbibnamehash}{809f695b398afbb54b544c49e8d1bbbb} 328 | \strng{authornamehash}{809f695b398afbb54b544c49e8d1bbbb} 329 | \strng{authorfullhash}{809f695b398afbb54b544c49e8d1bbbb} 330 | \field{extraname}{1} 331 | \field{sortinit}{2} 332 | \field{sortinithash}{cbff857e587bcb4635511624d773949e} 333 | \field{labelnamesource}{author} 334 | \field{labeltitlesource}{title} 335 | \field{journaltitle}{Econometric Theory} 336 | \field{number}{675-685} 337 | \field{title}{Causality: models, reasoning, and inference} 338 | \field{volume}{19} 339 | \field{year}{2003} 340 | \field{pages}{46} 341 | \range{pages}{1} 342 | \endentry 343 | \entry{pearl2009}{article}{} 344 | \name{author}{1}{}{% 345 | {{hash=809f695b398afbb54b544c49e8d1bbbb}{% 346 | family={Pearl}, 347 | familyi={P\bibinitperiod}, 348 | given={Judea}, 349 | giveni={J\bibinitperiod}}}% 350 | } 351 | \list{publisher}{2}{% 352 | {The American Statistical Association, the Bernoulli Society, the Institute of Mathematical Statistics,}% 353 | {the Statistical Society of Canada}% 354 | } 355 | \strng{namehash}{809f695b398afbb54b544c49e8d1bbbb} 356 | \strng{fullhash}{809f695b398afbb54b544c49e8d1bbbb} 357 | \strng{bibnamehash}{809f695b398afbb54b544c49e8d1bbbb} 358 | \strng{authorbibnamehash}{809f695b398afbb54b544c49e8d1bbbb} 359 | \strng{authornamehash}{809f695b398afbb54b544c49e8d1bbbb} 360 | \strng{authorfullhash}{809f695b398afbb54b544c49e8d1bbbb} 361 | \field{extraname}{2} 362 | \field{sortinit}{2} 363 | \field{sortinithash}{cbff857e587bcb4635511624d773949e} 364 | \field{labelnamesource}{author} 365 | \field{labeltitlesource}{title} 366 | \field{journaltitle}{Statist. Surv.} 367 | \field{title}{Causal inference in statistics: An overview} 368 | \field{volume}{3} 369 | \field{year}{2009} 370 | \field{pages}{96\bibrangedash 146} 371 | \range{pages}{51} 372 | \verb{doi} 373 | \verb 10.1214/09-SS057 374 | \endverb 375 | \verb{urlraw} 376 | \verb https://doi.org/10.1214/09-SS057 377 | \endverb 378 | \verb{url} 379 | \verb https://doi.org/10.1214/09-SS057 380 | \endverb 381 | \endentry 382 | \entry{scheines1997introduction}{article}{} 383 | \name{author}{1}{}{% 384 | {{hash=02f6653c0e96cdc7d40f942944d5e3fb}{% 385 | family={Scheines}, 386 | familyi={S\bibinitperiod}, 387 | given={Richard}, 388 | giveni={R\bibinitperiod}}}% 389 | } 390 | \list{publisher}{1}{% 391 | {Citeseer}% 392 | } 393 | \strng{namehash}{02f6653c0e96cdc7d40f942944d5e3fb} 394 | \strng{fullhash}{02f6653c0e96cdc7d40f942944d5e3fb} 395 | \strng{bibnamehash}{02f6653c0e96cdc7d40f942944d5e3fb} 396 | \strng{authorbibnamehash}{02f6653c0e96cdc7d40f942944d5e3fb} 397 | \strng{authornamehash}{02f6653c0e96cdc7d40f942944d5e3fb} 398 | \strng{authorfullhash}{02f6653c0e96cdc7d40f942944d5e3fb} 399 | \field{sortinit}{2} 400 | \field{sortinithash}{cbff857e587bcb4635511624d773949e} 401 | \field{labelnamesource}{author} 402 | \field{labeltitlesource}{title} 403 | \field{title}{An introduction to causal inference} 404 | \endentry 405 | \entry{colombo2012learning2}{article}{} 406 | \name{author}{4}{}{% 407 | {{hash=e1fbe553ae8384b11ac51e5da7d67b1f}{% 408 | family={Colombo}, 409 | familyi={C\bibinitperiod}, 410 | given={Diego}, 411 | giveni={D\bibinitperiod}}}% 412 | {{hash=8f905a89e7bf1cc9d54e6934783ebb3f}{% 413 | family={Maathuis}, 414 | familyi={M\bibinitperiod}, 415 | given={Marloes\bibnamedelima H}, 416 | giveni={M\bibinitperiod\bibinitdelim H\bibinitperiod}}}% 417 | {{hash=df9a0e9859bb9965919cd59d2523022d}{% 418 | family={Kalisch}, 419 | familyi={K\bibinitperiod}, 420 | given={Markus}, 421 | giveni={M\bibinitperiod}}}% 422 | {{hash=eabf99a26b5a1ac7dd40719ea6e697e2}{% 423 | family={Richardson}, 424 | familyi={R\bibinitperiod}, 425 | given={Thomas\bibnamedelima S}, 426 | giveni={T\bibinitperiod\bibinitdelim S\bibinitperiod}}}% 427 | } 428 | \list{publisher}{1}{% 429 | {JSTOR}% 430 | } 431 | \strng{namehash}{1716a3dca8d3cc0e64ec4faef0ef9597} 432 | \strng{fullhash}{0e42da14e178e2444a6ed09f14ec437d} 433 | \strng{bibnamehash}{0e42da14e178e2444a6ed09f14ec437d} 434 | \strng{authorbibnamehash}{0e42da14e178e2444a6ed09f14ec437d} 435 | \strng{authornamehash}{1716a3dca8d3cc0e64ec4faef0ef9597} 436 | \strng{authorfullhash}{0e42da14e178e2444a6ed09f14ec437d} 437 | \field{extraname}{2} 438 | \field{sortinit}{2} 439 | \field{sortinithash}{cbff857e587bcb4635511624d773949e} 440 | \field{labelnamesource}{author} 441 | \field{labeltitlesource}{title} 442 | \field{journaltitle}{The Annals of Statistics} 443 | \field{title}{Supplement to “Learning high-dimensional directed acyclic graphs with latent and selection variables} 444 | \field{year}{2012} 445 | \endentry 446 | \entry{Pearson}{article}{} 447 | \name{author}{1}{}{% 448 | {{hash=716c197f50c5e070b09b67f32636d3e7}{% 449 | family={F.R.S.}, 450 | familyi={F\bibinitperiod}, 451 | given={Karl\bibnamedelima Pearson}, 452 | giveni={K\bibinitperiod\bibinitdelim P\bibinitperiod}}}% 453 | } 454 | \list{publisher}{1}{% 455 | {Taylor & Francis}% 456 | } 457 | \strng{namehash}{716c197f50c5e070b09b67f32636d3e7} 458 | \strng{fullhash}{716c197f50c5e070b09b67f32636d3e7} 459 | \strng{bibnamehash}{716c197f50c5e070b09b67f32636d3e7} 460 | \strng{authorbibnamehash}{716c197f50c5e070b09b67f32636d3e7} 461 | \strng{authornamehash}{716c197f50c5e070b09b67f32636d3e7} 462 | \strng{authorfullhash}{716c197f50c5e070b09b67f32636d3e7} 463 | \field{sortinit}{3} 464 | \field{sortinithash}{a4b52e5432884761f50fb9571273b93e} 465 | \field{labelnamesource}{author} 466 | \field{labeltitlesource}{title} 467 | \field{journaltitle}{The London, Edinburgh, and Dublin Philosophical Magazine and Journal of Science} 468 | \field{number}{302} 469 | \field{title}{X. On the criterion that a given system of deviations from the probable in the case of a correlated system of variables is such that it can be reasonably supposed to have arisen from random sampling} 470 | \field{volume}{50} 471 | \field{year}{1900} 472 | \field{pages}{157\bibrangedash 175} 473 | \range{pages}{19} 474 | \verb{doi} 475 | \verb 10.1080/14786440009463897 476 | \endverb 477 | \verb{eprint} 478 | \verb https://doi.org/10.1080/14786440009463897 479 | \endverb 480 | \verb{urlraw} 481 | \verb https://doi.org/10.1080/14786440009463897 482 | \endverb 483 | \verb{url} 484 | \verb https://doi.org/10.1080/14786440009463897 485 | \endverb 486 | \endentry 487 | \entry{spirtes2001anytime}{inproceedings}{} 488 | \name{author}{1}{}{% 489 | {{hash=f0924fa092ce0a8f24b79fcf1e746c8f}{% 490 | family={Spirtes}, 491 | familyi={S\bibinitperiod}, 492 | given={Peter}, 493 | giveni={P\bibinitperiod}}}% 494 | } 495 | \strng{namehash}{f0924fa092ce0a8f24b79fcf1e746c8f} 496 | \strng{fullhash}{f0924fa092ce0a8f24b79fcf1e746c8f} 497 | \strng{bibnamehash}{f0924fa092ce0a8f24b79fcf1e746c8f} 498 | \strng{authorbibnamehash}{f0924fa092ce0a8f24b79fcf1e746c8f} 499 | \strng{authornamehash}{f0924fa092ce0a8f24b79fcf1e746c8f} 500 | \strng{authorfullhash}{f0924fa092ce0a8f24b79fcf1e746c8f} 501 | \field{sortinit}{4} 502 | \field{sortinithash}{11cdaee3b18e01d77f3f428b13c1fc76} 503 | \field{labelnamesource}{author} 504 | \field{labeltitlesource}{title} 505 | \field{title}{An Anytime Algorithm for Causal Inference.} 506 | \endentry 507 | \entry{ZHANG20081873}{article}{} 508 | \name{author}{1}{}{% 509 | {{hash=00b06765d4d041da464652a126cfa7c1}{% 510 | family={Zhang}, 511 | familyi={Z\bibinitperiod}, 512 | given={Jiji}, 513 | giveni={J\bibinitperiod}}}% 514 | } 515 | \strng{namehash}{00b06765d4d041da464652a126cfa7c1} 516 | \strng{fullhash}{00b06765d4d041da464652a126cfa7c1} 517 | \strng{bibnamehash}{00b06765d4d041da464652a126cfa7c1} 518 | \strng{authorbibnamehash}{00b06765d4d041da464652a126cfa7c1} 519 | \strng{authornamehash}{00b06765d4d041da464652a126cfa7c1} 520 | \strng{authorfullhash}{00b06765d4d041da464652a126cfa7c1} 521 | \field{extraname}{2} 522 | \field{sortinit}{4} 523 | \field{sortinithash}{11cdaee3b18e01d77f3f428b13c1fc76} 524 | \field{labelnamesource}{author} 525 | \field{labeltitlesource}{title} 526 | \field{issn}{0004-3702} 527 | \field{journaltitle}{Artificial Intelligence} 528 | \field{number}{16} 529 | \field{title}{On the completeness of orientation rules for causal discovery in the presence of latent confounders and selection bias} 530 | \field{volume}{172} 531 | \field{year}{2008} 532 | \field{pages}{1873\bibrangedash 1896} 533 | \range{pages}{24} 534 | \verb{doi} 535 | \verb https://doi.org/10.1016/j.artint.2008.08.001 536 | \endverb 537 | \verb{urlraw} 538 | \verb http://www.sciencedirect.com/science/article/pii/S0004370208001008 539 | \endverb 540 | \verb{url} 541 | \verb http://www.sciencedirect.com/science/article/pii/S0004370208001008 542 | \endverb 543 | \keyw{Ancestral graphs,Automated causal discovery,Bayesian networks,Causal models,Markov equivalence,Latent variables} 544 | \endentry 545 | \entry{royce1987managing}{inproceedings}{} 546 | \name{author}{1}{}{% 547 | {{hash=541e173109dab443b9fc826b342e8e6f}{% 548 | family={Royce}, 549 | familyi={R\bibinitperiod}, 550 | given={Winston\bibnamedelima W}, 551 | giveni={W\bibinitperiod\bibinitdelim W\bibinitperiod}}}% 552 | } 553 | \list{organization}{1}{% 554 | {IEEE Computer Society Press}% 555 | } 556 | \strng{namehash}{541e173109dab443b9fc826b342e8e6f} 557 | \strng{fullhash}{541e173109dab443b9fc826b342e8e6f} 558 | \strng{bibnamehash}{541e173109dab443b9fc826b342e8e6f} 559 | \strng{authorbibnamehash}{541e173109dab443b9fc826b342e8e6f} 560 | \strng{authornamehash}{541e173109dab443b9fc826b342e8e6f} 561 | \strng{authorfullhash}{541e173109dab443b9fc826b342e8e6f} 562 | \field{sortinit}{5} 563 | \field{sortinithash}{3c19c3776b658b3558e9e2e4840c01e2} 564 | \field{labelnamesource}{author} 565 | \field{labeltitlesource}{title} 566 | \field{booktitle}{Proceedings of the 9th international conference on Software Engineering} 567 | \field{title}{Managing the development of large software systems: concepts and techniques} 568 | \field{year}{1987} 569 | \field{pages}{328\bibrangedash 338} 570 | \range{pages}{11} 571 | \endentry 572 | \entry{beck2001agile}{misc}{} 573 | \name{author}{17}{}{% 574 | {{hash=c5dcbe71f60a8d55caa11fe1493614d0}{% 575 | family={Beck}, 576 | familyi={B\bibinitperiod}, 577 | given={Kent}, 578 | giveni={K\bibinitperiod}}}% 579 | {{hash=b081a82bcbc247aeb2a2ca9ae72f9566}{% 580 | family={Beedle}, 581 | familyi={B\bibinitperiod}, 582 | given={Mike}, 583 | giveni={M\bibinitperiod}}}% 584 | {{hash=a3d49db7c8b6de036095a80d96ee1461}{% 585 | family={Bennekum}, 586 | familyi={B\bibinitperiod}, 587 | given={Arie}, 588 | giveni={A\bibinitperiod}, 589 | prefix={van}, 590 | prefixi={v\bibinitperiod}}}% 591 | {{hash=c1e5acec4259bb4c17ca1a00866f32e1}{% 592 | family={Cockburn}, 593 | familyi={C\bibinitperiod}, 594 | given={Alistair}, 595 | giveni={A\bibinitperiod}}}% 596 | {{hash=dc98036d5d01f88b9fdd0b5ff2bc8a2d}{% 597 | family={Cunningham}, 598 | familyi={C\bibinitperiod}, 599 | given={Ward}, 600 | giveni={W\bibinitperiod}}}% 601 | {{hash=312ac886938a9b2be4f8eb607567fe4c}{% 602 | family={Fowler}, 603 | familyi={F\bibinitperiod}, 604 | given={Martin}, 605 | giveni={M\bibinitperiod}}}% 606 | {{hash=61bdeb09cfbfab0465639014ab3b69be}{% 607 | family={Grenning}, 608 | familyi={G\bibinitperiod}, 609 | given={James}, 610 | giveni={J\bibinitperiod}}}% 611 | {{hash=bae406ad0a87e2f65be045fff38c80ad}{% 612 | family={Highsmith}, 613 | familyi={H\bibinitperiod}, 614 | given={Jim}, 615 | giveni={J\bibinitperiod}}}% 616 | {{hash=10383d05f32f2a21518b493a3c546e5c}{% 617 | family={Hunt}, 618 | familyi={H\bibinitperiod}, 619 | given={Andrew}, 620 | giveni={A\bibinitperiod}}}% 621 | {{hash=3673ee61a410ba25401f2aeaf593748a}{% 622 | family={Jeffries}, 623 | familyi={J\bibinitperiod}, 624 | given={Ron}, 625 | giveni={R\bibinitperiod}}}% 626 | {{hash=0dd621758d63b6f0b80fb66db4c3f61e}{% 627 | family={Kern}, 628 | familyi={K\bibinitperiod}, 629 | given={Jon}, 630 | giveni={J\bibinitperiod}}}% 631 | {{hash=f520225da3039cab062eedb1e4ddc8d0}{% 632 | family={Marick}, 633 | familyi={M\bibinitperiod}, 634 | given={Brian}, 635 | giveni={B\bibinitperiod}}}% 636 | {{hash=6f41df64eb0dc4855be70172368604c2}{% 637 | family={Martin}, 638 | familyi={M\bibinitperiod}, 639 | given={Robert\bibnamedelima C.}, 640 | giveni={R\bibinitperiod\bibinitdelim C\bibinitperiod}}}% 641 | {{hash=6ec958c6516fd90847b3266799d82f77}{% 642 | family={Mellor}, 643 | familyi={M\bibinitperiod}, 644 | given={Steve}, 645 | giveni={S\bibinitperiod}}}% 646 | {{hash=ee6f08fcba839e09471a0bc69152b6a5}{% 647 | family={Schwaber}, 648 | familyi={S\bibinitperiod}, 649 | given={Ken}, 650 | giveni={K\bibinitperiod}}}% 651 | {{hash=6e3f26f6f816a26c6ab36bc7a899bcde}{% 652 | family={Sutherland}, 653 | familyi={S\bibinitperiod}, 654 | given={Jeff}, 655 | giveni={J\bibinitperiod}}}% 656 | {{hash=eb92fc3e1bc50392c9349cc38124af4c}{% 657 | family={Thomas}, 658 | familyi={T\bibinitperiod}, 659 | given={Dave}, 660 | giveni={D\bibinitperiod}}}% 661 | } 662 | \strng{namehash}{313c39d432f5bfc7cc4b41bada35a724} 663 | \strng{fullhash}{6319ce73345b9ed5d04efa6747044498} 664 | \strng{bibnamehash}{6319ce73345b9ed5d04efa6747044498} 665 | \strng{authorbibnamehash}{6319ce73345b9ed5d04efa6747044498} 666 | \strng{authornamehash}{313c39d432f5bfc7cc4b41bada35a724} 667 | \strng{authorfullhash}{6319ce73345b9ed5d04efa6747044498} 668 | \field{sortinit}{6} 669 | \field{sortinithash}{57e57fb8451e7fcfa45d1e069f6d3136} 670 | \field{labelnamesource}{author} 671 | \field{labeltitlesource}{title} 672 | \field{booktitle}{Manifesto for Agile Software Development} 673 | \field{title}{Manifesto for Agile Software Development} 674 | \field{year}{2001} 675 | \verb{urlraw} 676 | \verb http://www.agilemanifesto.org/ 677 | \endverb 678 | \verb{url} 679 | \verb http://www.agilemanifesto.org/ 680 | \endverb 681 | \keyw{imported} 682 | \endentry 683 | \entry{boehm1988spiral}{article}{} 684 | \name{author}{1}{}{% 685 | {{hash=30901c504c4e9f9f386b59986264609c}{% 686 | family={Boehm}, 687 | familyi={B\bibinitperiod}, 688 | given={Barry\bibnamedelima W}, 689 | giveni={B\bibinitperiod\bibinitdelim W\bibinitperiod}}}% 690 | } 691 | \list{publisher}{1}{% 692 | {IEEE}% 693 | } 694 | \strng{namehash}{30901c504c4e9f9f386b59986264609c} 695 | \strng{fullhash}{30901c504c4e9f9f386b59986264609c} 696 | \strng{bibnamehash}{30901c504c4e9f9f386b59986264609c} 697 | \strng{authorbibnamehash}{30901c504c4e9f9f386b59986264609c} 698 | \strng{authornamehash}{30901c504c4e9f9f386b59986264609c} 699 | \strng{authorfullhash}{30901c504c4e9f9f386b59986264609c} 700 | \field{sortinit}{6} 701 | \field{sortinithash}{57e57fb8451e7fcfa45d1e069f6d3136} 702 | \field{labelnamesource}{author} 703 | \field{labeltitlesource}{title} 704 | \field{journaltitle}{Computer} 705 | \field{number}{5} 706 | \field{title}{A spiral model of software development and enhancement} 707 | \field{year}{1988} 708 | \field{pages}{61\bibrangedash 72} 709 | \range{pages}{12} 710 | \endentry 711 | \entry{schwaber1997scrum}{incollection}{} 712 | \name{author}{1}{}{% 713 | {{hash=ee6f08fcba839e09471a0bc69152b6a5}{% 714 | family={Schwaber}, 715 | familyi={S\bibinitperiod}, 716 | given={Ken}, 717 | giveni={K\bibinitperiod}}}% 718 | } 719 | \list{publisher}{1}{% 720 | {Springer}% 721 | } 722 | \strng{namehash}{ee6f08fcba839e09471a0bc69152b6a5} 723 | \strng{fullhash}{ee6f08fcba839e09471a0bc69152b6a5} 724 | \strng{bibnamehash}{ee6f08fcba839e09471a0bc69152b6a5} 725 | \strng{authorbibnamehash}{ee6f08fcba839e09471a0bc69152b6a5} 726 | \strng{authornamehash}{ee6f08fcba839e09471a0bc69152b6a5} 727 | \strng{authorfullhash}{ee6f08fcba839e09471a0bc69152b6a5} 728 | \field{sortinit}{6} 729 | \field{sortinithash}{57e57fb8451e7fcfa45d1e069f6d3136} 730 | \field{labelnamesource}{author} 731 | \field{labeltitlesource}{title} 732 | \field{booktitle}{Business object design and implementation} 733 | \field{title}{Scrum development process} 734 | \field{year}{1997} 735 | \field{pages}{117\bibrangedash 134} 736 | \range{pages}{18} 737 | \endentry 738 | \entry{cohn2004user}{book}{} 739 | \name{author}{1}{}{% 740 | {{hash=d33712bcde2d63bad054a832b61d01e8}{% 741 | family={Cohn}, 742 | familyi={C\bibinitperiod}, 743 | given={Mike}, 744 | giveni={M\bibinitperiod}}}% 745 | } 746 | \list{publisher}{1}{% 747 | {Addison-Wesley Professional}% 748 | } 749 | \strng{namehash}{d33712bcde2d63bad054a832b61d01e8} 750 | \strng{fullhash}{d33712bcde2d63bad054a832b61d01e8} 751 | \strng{bibnamehash}{d33712bcde2d63bad054a832b61d01e8} 752 | \strng{authorbibnamehash}{d33712bcde2d63bad054a832b61d01e8} 753 | \strng{authornamehash}{d33712bcde2d63bad054a832b61d01e8} 754 | \strng{authorfullhash}{d33712bcde2d63bad054a832b61d01e8} 755 | \field{sortinit}{6} 756 | \field{sortinithash}{57e57fb8451e7fcfa45d1e069f6d3136} 757 | \field{labelnamesource}{author} 758 | \field{labeltitlesource}{title} 759 | \field{title}{User stories applied: For agile software development} 760 | \field{year}{2004} 761 | \endentry 762 | \entry{janzen2005test}{article}{} 763 | \name{author}{2}{}{% 764 | {{hash=0721732c9a4f6f7a5f20af598146daa8}{% 765 | family={Janzen}, 766 | familyi={J\bibinitperiod}, 767 | given={David}, 768 | giveni={D\bibinitperiod}}}% 769 | {{hash=d28b2ee210aad024eb6bbf2e15d494de}{% 770 | family={Saiedian}, 771 | familyi={S\bibinitperiod}, 772 | given={Hossein}, 773 | giveni={H\bibinitperiod}}}% 774 | } 775 | \list{publisher}{1}{% 776 | {IEEE}% 777 | } 778 | \strng{namehash}{84f1a344a772a815c6ac63d3f6bbf868} 779 | \strng{fullhash}{84f1a344a772a815c6ac63d3f6bbf868} 780 | \strng{bibnamehash}{84f1a344a772a815c6ac63d3f6bbf868} 781 | \strng{authorbibnamehash}{84f1a344a772a815c6ac63d3f6bbf868} 782 | \strng{authornamehash}{84f1a344a772a815c6ac63d3f6bbf868} 783 | \strng{authorfullhash}{84f1a344a772a815c6ac63d3f6bbf868} 784 | \field{sortinit}{6} 785 | \field{sortinithash}{57e57fb8451e7fcfa45d1e069f6d3136} 786 | \field{labelnamesource}{author} 787 | \field{labeltitlesource}{title} 788 | \field{journaltitle}{Computer} 789 | \field{number}{9} 790 | \field{title}{Test-driven development concepts, taxonomy, and future direction} 791 | \field{volume}{38} 792 | \field{year}{2005} 793 | \field{pages}{43\bibrangedash 50} 794 | \range{pages}{8} 795 | \endentry 796 | \entry{Numpy}{misc}{} 797 | \field{sortinit}{6} 798 | \field{sortinithash}{57e57fb8451e7fcfa45d1e069f6d3136} 799 | \field{labeltitlesource}{title} 800 | \field{journaltitle}{Example NumPy Style Python Docstrings - napoleon 0.7 documentation} 801 | \field{title}{Example NumPy Style Python Docstrings¶} 802 | \verb{urlraw} 803 | \verb https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html 804 | \endverb 805 | \verb{url} 806 | \verb https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html 807 | \endverb 808 | \endentry 809 | \entry{pandas}{misc}{} 810 | \field{sortinit}{6} 811 | \field{sortinithash}{57e57fb8451e7fcfa45d1e069f6d3136} 812 | \field{labeltitlesource}{title} 813 | \field{journaltitle}{pandas} 814 | \field{title}{Python Data Analysis Library¶} 815 | \verb{urlraw} 816 | \verb https://pandas.pydata.org/ 817 | \endverb 818 | \verb{url} 819 | \verb https://pandas.pydata.org/ 820 | \endverb 821 | \endentry 822 | \entry{networkx}{misc}{} 823 | \field{sortinit}{6} 824 | \field{sortinithash}{57e57fb8451e7fcfa45d1e069f6d3136} 825 | \field{labeltitlesource}{title} 826 | \field{journaltitle}{NetworkX} 827 | \field{title}{NetworkX} 828 | \verb{urlraw} 829 | \verb https://networkx.github.io/ 830 | \endverb 831 | \verb{url} 832 | \verb https://networkx.github.io/ 833 | \endverb 834 | \endentry 835 | \entry{scipy}{misc}{} 836 | \field{sortinit}{6} 837 | \field{sortinithash}{57e57fb8451e7fcfa45d1e069f6d3136} 838 | \field{labeltitlesource}{title} 839 | \field{journaltitle}{Statistical functions (scipy.stats) - SciPy v1.2.1 Reference Guide} 840 | \field{title}{Statistical functions (scipy.stats)¶} 841 | \verb{urlraw} 842 | \verb https://docs.scipy.org/doc/scipy/reference/stats.html 843 | \endverb 844 | \verb{url} 845 | \verb https://docs.scipy.org/doc/scipy/reference/stats.html 846 | \endverb 847 | \endentry 848 | \entry{numpy}{misc}{} 849 | \field{sortinit}{7} 850 | \field{sortinithash}{c818dd9105a2852444fc9f5e145c294e} 851 | \field{labeltitlesource}{title} 852 | \field{journaltitle}{NumPy} 853 | \field{title}{NumPy¶} 854 | \verb{urlraw} 855 | \verb http://www.numpy.org/ 856 | \endverb 857 | \verb{url} 858 | \verb http://www.numpy.org/ 859 | \endverb 860 | \endentry 861 | \entry{data}{misc}{} 862 | \field{sortinit}{7} 863 | \field{sortinithash}{c818dd9105a2852444fc9f5e145c294e} 864 | \field{journaltitle}{GOBNILP DATA} 865 | \verb{urlraw} 866 | \verb https://www.cs.york.ac.uk/aig/sw/gobnilp/data/ 867 | \endverb 868 | \verb{url} 869 | \verb https://www.cs.york.ac.uk/aig/sw/gobnilp/data/ 870 | \endverb 871 | \endentry 872 | \entry{wilbers2009using}{article}{} 873 | \name{author}{3}{}{% 874 | {{hash=2fa0a0e8f29b7f05b71affd3449933e8}{% 875 | family={Wilbers}, 876 | familyi={W\bibinitperiod}, 877 | given={Ilmar\bibnamedelima M}, 878 | giveni={I\bibinitperiod\bibinitdelim M\bibinitperiod}}}% 879 | {{hash=b1ba9610a18cb091d0a9602e75b8476f}{% 880 | family={Langtangen}, 881 | familyi={L\bibinitperiod}, 882 | given={Hans\bibnamedelima Petter}, 883 | giveni={H\bibinitperiod\bibinitdelim P\bibinitperiod}}}% 884 | {{hash=b7c963afdc1ba711b8f337118b9f2447}{% 885 | family={{Ø}deg{å}rd}, 886 | familyi={Ø\bibinitperiod}, 887 | given={{Å}smund}, 888 | giveni={Å\bibinitperiod}}}% 889 | } 890 | \strng{namehash}{15fea666cf18faef33e7ab8d0d6e6969} 891 | \strng{fullhash}{15fea666cf18faef33e7ab8d0d6e6969} 892 | \strng{bibnamehash}{15fea666cf18faef33e7ab8d0d6e6969} 893 | \strng{authorbibnamehash}{15fea666cf18faef33e7ab8d0d6e6969} 894 | \strng{authornamehash}{15fea666cf18faef33e7ab8d0d6e6969} 895 | \strng{authorfullhash}{15fea666cf18faef33e7ab8d0d6e6969} 896 | \field{sortinit}{7} 897 | \field{sortinithash}{c818dd9105a2852444fc9f5e145c294e} 898 | \field{labelnamesource}{author} 899 | \field{labeltitlesource}{title} 900 | \field{journaltitle}{Proceedings of MekIT} 901 | \field{title}{Using cython to speed up numerical python programs} 902 | \field{volume}{9} 903 | \field{year}{2009} 904 | \field{pages}{495\bibrangedash 512} 905 | \range{pages}{18} 906 | \endentry 907 | \entry{wilkinson_2014}{misc}{} 908 | \name{author}{1}{}{% 909 | {{hash=19479302b75fdb401e30ad7309f36e9d}{% 910 | family={Wilkinson}, 911 | familyi={W\bibinitperiod}, 912 | given={Darren\bibnamedelima j}, 913 | giveni={D\bibinitperiod\bibinitdelim j\bibinitperiod}}}% 914 | } 915 | \list{publisher}{1}{% 916 | {Gibbs sampler in various languages}% 917 | } 918 | \strng{namehash}{19479302b75fdb401e30ad7309f36e9d} 919 | \strng{fullhash}{19479302b75fdb401e30ad7309f36e9d} 920 | \strng{bibnamehash}{19479302b75fdb401e30ad7309f36e9d} 921 | \strng{authorbibnamehash}{19479302b75fdb401e30ad7309f36e9d} 922 | \strng{authornamehash}{19479302b75fdb401e30ad7309f36e9d} 923 | \strng{authorfullhash}{19479302b75fdb401e30ad7309f36e9d} 924 | \field{sortinit}{7} 925 | \field{sortinithash}{c818dd9105a2852444fc9f5e145c294e} 926 | \field{labelnamesource}{author} 927 | \field{labeltitlesource}{title} 928 | \field{journaltitle}{Darren Wilkinson's research blog} 929 | \field{month}{11} 930 | \field{title}{Gibbs sampler in various languages (revisited)} 931 | \field{year}{2014} 932 | \verb{urlraw} 933 | \verb https://darrenjw.wordpress.com/2011/07/16/gibbs-sampler-in-various-languages-revisited/ 934 | \endverb 935 | \verb{url} 936 | \verb https://darrenjw.wordpress.com/2011/07/16/gibbs-sampler-in-various-languages-revisited/ 937 | \endverb 938 | \endentry 939 | \entry{cython}{misc}{} 940 | \field{sortinit}{8} 941 | \field{sortinithash}{07edf88d4ea82509b9c4b4d13f41c452} 942 | \field{labeltitlesource}{title} 943 | \field{journaltitle}{Cython} 944 | \field{title}{C-Extensions for Python} 945 | \verb{urlraw} 946 | \verb https://cython.org/ 947 | \endverb 948 | \verb{url} 949 | \verb https://cython.org/ 950 | \endverb 951 | \endentry 952 | \enddatalist 953 | \endrefsection 954 | \endinput 955 | 956 | --------------------------------------------------------------------------------