├── .gitignore ├── MANIFEST.in ├── Makefile ├── README.mkd ├── bench-opti.txt ├── data ├── H10FW_vs_H10SW.lp ├── abnormal.lp ├── bintree.lp ├── clique.lp ├── cliques.lp ├── complex-case-1.lp ├── concept-loop.lp ├── concomp.lp ├── consider-included-nodes.lp ├── ddiam.lp ├── diacli.lp ├── diamond.lp ├── disjoint-subpnodes.lp ├── double-p-groups.lp ├── double_biclique_unambiguous.lp ├── empty.lp ├── hanging-bio-notree-cc0.lp ├── horrible_data.lp ├── inclusions.lp ├── matrixdb-core27.sif ├── miRNA_mRNA_diff.sif ├── miRNA_mRNA_diff_no3019.sif ├── motif-overlapping.lp ├── multiple-optimals.lp ├── n8_d0.7.lp ├── one_edge.lp ├── order.lp ├── overlapping-bicliques.lp ├── partition.lp ├── perfectfit.lp ├── phosphatase.lp ├── pnode-to-clique.lp ├── prio_deg.lp ├── puceron-data-2018.lp ├── quasibiclique.lp ├── quoting.lp ├── recipe-option-test.lp ├── recipe-option-test.txt ├── recipe-test-inclusion.lp ├── recipe-test.lp ├── recipe-test.txt ├── single-node.lp ├── star.lp ├── structural-binding-maincc.lp ├── structural-binding-nobridge.lp ├── structural-binding.lp ├── suboptimal.lp ├── test.gml ├── test.graphml ├── testblocks.lp ├── thesis.lp ├── todel.lp ├── triplets.lp ├── typical-use-case.lp ├── unclique.lp ├── variable-name.gml ├── wiki-tree-decomposition.lp └── zorro.lp ├── out ├── .gitignore └── thesis │ ├── concept-cycle-4.sif │ ├── matrixdb-extended.sif │ ├── matrixdb_CORE27_example__a_0-_b_0-_c_3-.png │ ├── matrixdb_CORE27_example__a_0-_b_0-_c_3-zoom.png.png │ ├── matrixdb_CORE27_example__a_0-_b_0-_c_3-zoom.png.png.png │ ├── matrixdb_CORE27_example__a_3-_b_3-_c_0-.png │ ├── miRNA_mRNA_diff-no3019.png │ ├── miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.bbl.png │ ├── thesis-network-triplet-zoom-a_0-_b_0-_c_0-.bbl.png │ ├── triplet.sif │ ├── zorro-annotated.png │ ├── zorro-c1-c2.png │ ├── zorro-c1-c21-annotated.png │ ├── zorro-c1-c21-c31-c32-c22.png │ ├── zorro-c1-c22-annotated.png │ ├── zorro-c1-c3-annotated.png │ ├── zorro-c1-c3-c21-annotated.png │ ├── zorro-c1-c3-c22-annotated.png │ ├── zorro-c1-c3.png │ ├── zorro-c1-c31-c21-c22-c32.png │ ├── zorro-c1.png │ ├── zorro-compression-middle-first.png │ ├── zorro-compression-per-concept.png │ ├── zorro-compression-regular.png │ ├── zorro.png │ └── zorro.sif ├── powergrasp ├── __init__.py ├── __main__.py ├── asp.py ├── asp │ ├── block-constraint-cpu.lp │ ├── block-constraint-memory.lp │ ├── extract-ccs.lp │ ├── process-motif.lp │ ├── scoring_powergraph.lp │ ├── search-biclique.lp │ ├── search-clique.lp │ ├── search-fullbiclique.lp │ ├── search-quasibiclique.lp │ ├── search-star.lp │ └── search-triplet.lp ├── cli.py ├── constants.py ├── edge_filtering.py ├── graph.py ├── metrics.py ├── motif.py ├── motif_batch.py ├── recipe.py ├── routines.py ├── searchers.py └── utils.py ├── recipe ├── setup.cfg ├── setup.py ├── test ├── __init__.py ├── ambiguous_test_cases.py ├── definitions.py ├── powergrasp.default.cfg ├── powergrasp.manyoptions.cfg ├── powergrasp.nostarsearch.cfg ├── powergrasp.oneshot.cfg ├── test_cases.py ├── test_multishot_compression.py ├── test_recipes.py ├── test_unambiguous_compression.py └── test_utils.py └── triplet ├── .gitignore ├── Makefile ├── README ├── cases_cache ├── backup-incomplete │ ├── miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.concepts.dat │ ├── miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.dat │ ├── miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.concepts.dat │ └── miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.dat ├── double_biclique_unambiguous__a_0-_b_0-_c_0-.concepts.dat ├── double_biclique_unambiguous__a_0-_b_0-_c_0-.dat ├── matrixdb_CORE27_example__a_0-_b_0-_c_0-.concepts.dat ├── matrixdb_CORE27_example__a_0-_b_0-_c_0-.dat ├── matrixdb_CORE27_example__a_0-_b_0-_c_2-.concepts.dat ├── matrixdb_CORE27_example__a_0-_b_0-_c_2-.dat ├── matrixdb_CORE27_example__a_0-_b_0-_c_3-.concepts.dat ├── matrixdb_CORE27_example__a_0-_b_0-_c_3-.dat ├── matrixdb_CORE27_example__a_3-_b_3-_c_0-.concepts.dat ├── matrixdb_CORE27_example__a_3-_b_3-_c_0-.dat ├── miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.concepts.dat ├── miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.dat ├── miRNA_mRNA_diff-no3019__a_0-_b_0-_c_2-.concepts.dat ├── miRNA_mRNA_diff-no3019__a_0-_b_0-_c_2-.dat ├── miRNA_mRNA_diff-no3019__a_0-_b_0-_c_3-.concepts.dat ├── miRNA_mRNA_diff-no3019__a_0-_b_0-_c_3-.dat ├── miRNA_mRNA_diff-no3019__a_3-_b_2-_c_0-.concepts.dat ├── miRNA_mRNA_diff-no3019__a_3-_b_2-_c_0-.dat ├── miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.concepts.dat └── miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.dat ├── combinations.py ├── compute-concepts.lp ├── out ├── number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png ├── number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png ├── number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png ├── number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png ├── number_formal_concept_per_score_allindex_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png ├── number_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png ├── number_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png ├── number_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png ├── number_formal_concept_per_score_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png ├── number_formal_concept_per_score_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png ├── number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png ├── number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png ├── number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png ├── number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png ├── number_triplet_concept_formal_concept_per_score_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png ├── number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png ├── number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png ├── number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png ├── number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png ├── number_triplet_concept_per_score_allindex_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png ├── number_triplet_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png ├── number_triplet_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png ├── number_triplet_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png ├── number_triplet_concept_per_score_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png └── number_triplet_concept_per_score_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png ├── search-byconcept.lp ├── search-byenum.lp ├── search.lp └── search.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.bbl 2 | *.csv 3 | .cache/ 4 | .pytest_cache/ 5 | Session.vim 6 | __pycache__/ 7 | debug/ 8 | dist/ 9 | powergrasp.egg-info/ 10 | PowerGrASP.egg-info/ 11 | venv/ 12 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENCE MANIFEST.in README.mkd 2 | recursive-include powergrasp *.py *.lp 3 | exclude Makefile 4 | prune data 5 | prune test 6 | prune out 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | INFILE_DIR=data 3 | INFILE=double_biclique_unambiguous.lp 4 | TEST_CFG_FILE= 5 | 6 | SHOW_DURATIONS=--durations=22 7 | FAILED_FIRST=--ff 8 | 9 | ## Usage and tests 10 | compress: 11 | python -m powergrasp $(INFILE_DIR)/$(INFILE) out/out.bbl 12 | python -m bubbletools validate out/out.bbl 13 | 14 | config: 15 | python -m powergrasp --config 16 | 17 | test: t 18 | t: 19 | - mv powergrasp.cfg powergrasp.cfg.bak 20 | # try different option sets 21 | $(MAKE) _test_cfg_file TEST_CFG_FILE=default # with default values 22 | $(MAKE) _test_cfg_file TEST_CFG_FILE=oneshot 23 | $(MAKE) _test_cfg_file TEST_CFG_FILE=manyoptions 24 | $(MAKE) _test_cfg_file TEST_CFG_FILE=nostarsearch 25 | rm powergrasp.cfg 26 | - mv powergrasp.cfg.bak powergrasp.cfg 27 | _pure_tests: 28 | pytest powergrasp test -x -vv --doctest-module $(SHOW_DURATIONS) $(FAILED_FIRST) 29 | _test_cfg_file: 30 | cp test/powergrasp.$(TEST_CFG_FILE).cfg powergrasp.cfg 31 | $(MAKE) _pure_tests # with many options tweaked (edges from ASP, integrity,…) 32 | 33 | 34 | ## Packaging 35 | make_dist: 36 | python setup.py sdist 37 | upload: 38 | twine upload --repository pypi dist/PowerGrASP-*.tar.gz 39 | release: fullrelease 40 | fullrelease: 41 | fullrelease 42 | install_deps: 43 | python -c "import configparser; c = configparser.ConfigParser(); c.read('setup.cfg'); print(c['options']['install_requires'])" | xargs pip install -U 44 | 45 | 46 | .PHONY: test t compress upload 47 | 48 | ## All real test cases 49 | real-puceron-mi-m-diff: 50 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=miRNA_mRNA_diff.lp 51 | real-puceron-mi-m-diff-no3019: 52 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=miRNA_mRNA_diff-no3019.lp 53 | real-puceron-mi-lnc: 54 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=miRNA_lncRNA.lp 55 | real-puceron-lnc-m: 56 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=lncRNA_mRNA.lp 57 | real-puceron-mi-m-lnc: 58 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=ternary_concepts_mi_m_lnc-edge.lp 59 | real-matrixdb-core27: 60 | $(MAKE) compress INFILE_DIR=~/data/MatrixDb/compmatrixdb/matrixdb_CORE27_example INFILE=matrixdb_CORE27_example.lp 61 | real-matrixdb-90: 62 | $(MAKE) compress INFILE_DIR=~/data/MatrixDb/compmatrixdb/matrixdb_Human_Human_171107_extended INFILE=matrixdb_CORE27_example.lp 63 | real-matrixdb-all: 64 | $(MAKE) compress INFILE_DIR=~/data/MatrixDb/compmatrixdb/matrixdb_Human_Human_171107_extended INFILE=matrixdb_Human_Human_171107_extended_0.0.lp 65 | 66 | 67 | ## All test cases 68 | abnormal: 69 | $(MAKE) compress INFILE=abnormal.lp 70 | bintree: 71 | $(MAKE) compress INFILE=bintree.lp 72 | clique: 73 | $(MAKE) compress INFILE=clique.lp 74 | cliques: 75 | $(MAKE) compress INFILE=cliques.lp 76 | concomp: 77 | $(MAKE) compress INFILE=concomp.lp 78 | concept-loop: 79 | $(MAKE) compress INFILE=concept-loop.lp 80 | ddiam: 81 | $(MAKE) compress INFILE=ddiam.lp 82 | diacli: 83 | $(MAKE) compress INFILE=diacli.lp 84 | diamond: 85 | $(MAKE) compress INFILE=diamond.lp 86 | disjoint-subpnodes: 87 | $(MAKE) compress INFILE=disjoint-subpnodes.lp 88 | double_biclique_unambiguous: 89 | $(MAKE) compress INFILE=double_biclique_unambiguous.lp 90 | double-p-groups: 91 | $(MAKE) compress INFILE=double-p-groups.lp 92 | hanging-bio-notree-cc0: 93 | $(MAKE) compress INFILE=hanging-bio-notree-cc0.lp 94 | horrible_data: 95 | $(MAKE) compress INFILE=horrible_data.lp 96 | inclusions: 97 | $(MAKE) compress INFILE=inclusions.lp 98 | consider-included-nodes: 99 | $(MAKE) compress INFILE=consider-included-nodes.lp 100 | motif-overlapping: 101 | $(MAKE) compress INFILE=motif-overlapping.lp 102 | multiple-optimals: 103 | $(MAKE) compress INFILE=multiple-optimals.lp 104 | n8_d0: 105 | $(MAKE) compress INFILE=n8_d0.7.lp 106 | one_edge: 107 | $(MAKE) compress INFILE=one_edge.lp 108 | order: 109 | $(MAKE) compress INFILE=order.lp 110 | overlapping-bicliques: 111 | $(MAKE) compress INFILE=overlapping-bicliques.lp 112 | partition: 113 | $(MAKE) compress INFILE=partition.lp 114 | perfectfit: 115 | $(MAKE) compress INFILE=perfectfit.lp 116 | phosphatase: 117 | $(MAKE) compress INFILE=phosphatase.lp 118 | pnode-to-clique: 119 | $(MAKE) compress INFILE=pnode-to-clique.lp 120 | prio_deg: 121 | $(MAKE) compress INFILE=prio_deg.lp 122 | quasibiclique: 123 | $(MAKE) compress INFILE=quasibiclique.lp 124 | quoting: 125 | $(MAKE) compress INFILE=quoting.lp 126 | single-node: 127 | $(MAKE) compress INFILE=single-node.lp 128 | star: 129 | $(MAKE) compress INFILE=star.lp 130 | structural-binding: 131 | $(MAKE) compress INFILE=structural-binding.lp 132 | structural-binding-maincc: 133 | $(MAKE) compress INFILE=structural-binding-maincc.lp 134 | structural-binding-nobridge: 135 | $(MAKE) compress INFILE=structural-binding-nobridge.lp 136 | testblocks: 137 | $(MAKE) compress INFILE=testblocks.lp 138 | test-gml: 139 | $(MAKE) compress INFILE=test.gml 140 | test-graphml: 141 | $(MAKE) compress INFILE=test.graphml 142 | thesis: 143 | $(MAKE) compress INFILE=thesis.lp 144 | todel: 145 | $(MAKE) compress INFILE=todel.lp 146 | triplets: 147 | $(MAKE) compress INFILE=triplets.lp 148 | typical: 149 | $(MAKE) compress INFILE=typical-use-case.lp 150 | unclique: 151 | $(MAKE) compress INFILE=unclique.lp 152 | variable-name: 153 | $(MAKE) compress INFILE=variable-name.gml 154 | wiki-tree-decomposition: 155 | $(MAKE) compress INFILE=wiki-tree-decomposition.lp 156 | zorro: 157 | $(MAKE) compress INFILE=zorro.lp 158 | -------------------------------------------------------------------------------- /README.mkd: -------------------------------------------------------------------------------- 1 | # PowerGrASP 2 | Graph compression. 3 | 4 | Note that this is a full reimplementation of PowerGrASP, 5 | taking advantage of ASP and Python lifting and simplifications. 6 | For the version published in 2017, see [this repository](https://github.com/aluriak/PowerGrASP-1). 7 | 8 | 9 | ## CLI 10 | 11 | python -m powergrasp mygraph.gml -o compressed.bbl 12 | 13 | ### help ! 14 | 15 | python -m powergrasp --help 16 | 17 | ## API 18 | 19 | ```python 20 | import powergrasp 21 | with open('compressed.bbl', 'w') as fd: 22 | for line in powergrasp.compress_by_cc('mygraph.gml'): 23 | fd.write(line + '\n') 24 | ``` 25 | 26 | ### help ! 27 | Sorry, no technical doc for the moment. 28 | 29 | 30 | ## Bubble files usage 31 | The bubble file is the main output of PowerGrASP, and describes a power graph. 32 | The bubble is a format handled by the [CyOog plugin](http://www.biotec.tu-dresden.de/research/schroeder/powergraphs/download-cytoscape-plugin.html) for [Cytoscape 2](http://cytoscape.org/), allowing one to load a bubble formatted file and to visualize the corresponding graph. 33 | As a consequence, you have to [install Cytoscape 2](http://chianti.ucsd.edu/Cyto-2%5F8%5F3/), and put the `CyOog.jar` file into `path/to/cytoscape/install/dir/plugins/`. 34 | 35 | Another way to go is to convert the bubble to other formats handling hierarchical graphs, like [gexf](https://gephi.org/gexf/format/), 36 | [dot](https://www.graphviz.org/doc/info/lang.html) or the API of [cytoscape.js](http://js.cytoscape.org/). 37 | This is a task implemented by [bubbletools](https://github.com/Aluriak/bubble-tools/). 38 | 39 | 40 | ## Configuration 41 | PowerGrASP has some [configuration values](powergrasp/constants.py), 42 | that can be overwritten by a `powergrasp.cfg` file placed in the working directory. 43 | 44 | The configuration may be printed in stdout using: 45 | 46 | python -m powergrasp --config 47 | 48 | The config file may be either in ini or json format, as shown in [`test/powergrasp.oneshot.cfg`](test/powergrasp.oneshot.cfg) and [`test/powergrasp.manyoptions.cfg`](test/powergrasp.manyoptions.cfg). 49 | 50 | Configuration allow user to define how much text will be outputed by powergrasp, 51 | and to tune the core compression and related optimizations. 52 | 53 | See complete list in the [options section](#Options). 54 | 55 | 56 | ## installation 57 | 58 | pip install powergrasp 59 | 60 | On random error, try adding `--no-cache-dir` at the end of the command, 61 | and check that you are using python 3. 62 | 63 | You must have [`clingo`](https://potassco.org/doc/start/) in your path. Depending on your OS, it might be done with a system installation, 64 | or through [downloading](https://github.com/potassco/clingo/releases) and (compilation and) manual installation. 65 | 66 | 67 | ## Changelog 68 | 69 | - 8.17 70 | - support for [recipes options](#recipes), like `breakable` or `last` 71 | - 8.11 72 | - slight bounds improvements for non-star-biclique motif 73 | - statistics/timers now provides time needed to search for each motif 74 | - support for [recipes](#recipes), that small file that allows to define the compressions to do 75 | - 8.10 76 | - option [parallel cc compression](#parallel-cc-compression) to enable parallel compression of connected components 77 | - option [bubble embeds cc](#bubble-embeds-cc), to put each cc in a dedicated powernode 78 | - option [bubble with simple edges](#bubble-with-simple-edges), to keep or discard the simple edges from output 79 | - statistics on time and compression metrics are computed by cc and for all graph. See new options. 80 | - option [cc statistic file](#cc-statistic-file), to retrieve stats and metrics for connected components. 81 | - option [global statistics](#global-statistics), to compute statistics/metrics over all connected components. 82 | - option [bubble with statistics](#bubble-with-statistics), to include stats and metrics in output bubble file 83 | - [motif type order](#motif-type-order) option, allowing user to tune the order in which motifs are searched. 84 | - [parallel motif search](#parallel-motif-search) option, making motifs search in different threads, and the overhaul compression much slower. 85 | - CLI: --config flag to print the full configuration in stdout 86 | - handling spaces instead of _ in fields names for INI format 87 | - do not filter out nodes alone in their connected component (cf [keep-single-nodes option](#keep-single-nodes)) 88 | - perf gain: the first motif to reach the best score is compressed, instead of the last 89 | - improve handling of statistic files, that now contains cc idx and motif bounds 90 | - expose `__version__` attribute in the package 91 | - add a list of available options in the README 92 | - graph filtering: optimization leading to general performance gain when enabled 93 | - improvements on {low,upp}erbounds computations 94 | - 8.9 95 | - many bugfixes 96 | - CLINGO_OPTIONS can be a dict, mapping motif name to arbitrary parameters 97 | - 8.8 98 | - bugfix: lowerbound can't go under 2 (3 for cliques) 99 | - clique search: lowerbound is initially computed as the maximal degree of node of clustering coefficient equals to 1 100 | - use new versions of clyngor and bubbletools 101 | - 8.7 102 | - raise error when an invalid key is found in config file 103 | - StarSearch is dedicated to find stars, simplifying BicliqueSearch's job (enabled by default, user may use Biclique instead of both Star and NonStarBiclique) 104 | - specify a prefix for all (power) nodes with OUTPUT_NODE_PREFIX config field 105 | - arbitrary options for clingo using CLINGO_OPTIONS config field 106 | - bugfix on string options given in ini file, when unecessary quotes are kept 107 | - 8.6 108 | - bugfixes for INI format 109 | - 8.5 110 | - config may now be given in INI format 111 | - improve logging 112 | - config allow optimization target between memory or CPU (currently define a constraint implementation in ASP) 113 | - bugfix about edges yielded by ASP and multithreading parameter 114 | - no statistics file to write by default 115 | - timer for output writing 116 | - config allow user to define the number of CPU for clingo to use 117 | - simplify ASP code by removing useless arg in block/4 atoms 118 | - 8.4 119 | - replace ASP code constraint to achieve much more efficient grounding 120 | - configuration allow for improved lowerbound computation of bicliques 121 | - generated bubble allow client to give heading comments 122 | - handle keyboard interruption during search with grace 123 | - implement timers and statistics recording 124 | - enable multishot motif search by default 125 | - various bugfixes 126 | 127 | 128 | ## Recipes 129 | A recipe is a description of the motifs to compress. 130 | For instance, the [data/recipe-test.txt](data/recipe-test.txt): 131 | 132 | biclique c g h i 133 | biclique a b d e 134 | biclique a b f 135 | biclique c d e 136 | 137 | Using the `--recipe` option in CLI, user can provide a recipe for its own graph, 138 | allowing to specify prior motifs to search. 139 | The order of second and third columns does not have any influence. 140 | 141 | The first column usually contains the motif types separated by comma 142 | (altough it is not necessary), and allows to provide some options (separated by comma): 143 | 144 | - `primer`: allows the program to extend the given motif if possible 145 | - `breakable`: allows the program to compress the line with multiple motifs 146 | - `optional`: if not found, ignore instead of stopping 147 | - `last`: stop compression here (useful to avoid the compression process to take over) 148 | 149 | 150 | The recipe file will be read line by line. 151 | Once all lines have been applied, the normal compression compression takes over 152 | (unless `last` option is used). 153 | 154 | For a living example, see [data/recipe-option-test.txt](data/recipe-option-test.txt). 155 | 156 | 157 | ## Options 158 | Description of all powergrasp options. 159 | All values example are given for INI format. 160 | 161 | ### test integrity 162 | Run some integrity tests during runtime to ensure that compression is working well. 163 | May slow the compression a lot, and is mainly a debugging tool. 164 | 165 | Default value: 166 | 167 | test_integrity = true 168 | 169 | ### show story 170 | Print in stdout the main steps of compression. 171 | Default value: 172 | 173 | show_story = true 174 | 175 | ### show motif handling 176 | Print in stdout the motif transformation. 177 | Default value: 178 | 179 | show_motif_handling = false 180 | 181 | ### timers 182 | Maintain and print in stdout some timers. 183 | Default value: 184 | 185 | timers = true 186 | 187 | ### statistics file 188 | A file in which some statistics will be written in CSV format, giving among others size of compressed motifs, and their compression times (if *timers* option is enabled). 189 | Default value: 190 | 191 | statistics_file = None 192 | 193 | Example value: 194 | 195 | statistics_file = statistics.csv 196 | 197 | ### cc statistic file 198 | Filename in which the statistics about each connected component will be written. 199 | Data will contain one row for each connected component, with the following data: 200 | 201 | - connected component index 202 | - the convertion rate 203 | - the edge reduction 204 | - the compression rate 205 | - time needed to compress the connected component (if TIMERS is enabled) 206 | 207 | Default value stands for *no file*: 208 | 209 | cc_statistic_file = None 210 | 211 | Example value: 212 | 213 | cc_statistic_file = statistics-cc.csv 214 | 215 | ### global statistics 216 | When enabled, statistics and metrics computation on the overall graph will be performed at the end of compression. 217 | Default value: 218 | 219 | global_statistics = True 220 | 221 | ### bubble with statistics 222 | When enabled, output bubble will contain statistics about each connected component 223 | and the overall graph (if global_statistics is enabled). 224 | Default value: 225 | 226 | bubble_with_statistics = True 227 | 228 | ### bubble for each step 229 | Generate and save a bubble representation of the graph at each step. 230 | Mainly used for debugging. 231 | Default value: 232 | 233 | bubble_for_each_step = false 234 | 235 | ### output node prefix 236 | Prefix to add to all (power)nodes names in output. 237 | Default value: 238 | 239 | output_node_prefix = '' 240 | 241 | ### show debug 242 | Show full trace of the compression. Useful for debugging. 243 | Default value: 244 | 245 | show_debug = False 246 | 247 | ### covered edges from ASP 248 | Recover covered edges from ASP. If falsy, will ask motif searcher to compute the edges, which may be quicker. 249 | Default value: 250 | 251 | covered_edges_from_asp = False 252 | 253 | ### bubble with nodes 254 | Nodes and sets are optional in the output bubble. 255 | Default value: 256 | 257 | bubble_with_nodes = True 258 | bubble_with_sets = True 259 | 260 | ### bubble poweredge factor 261 | Edges in bubble are associated to a factor. 262 | Default value: 263 | 264 | bubble_poweredge_factor = '1.0' 265 | bubble_edge_factor = '1.0' 266 | 267 | ### bubble embeds cc 268 | If enabled, put each connected component in a dedicated powernode. 269 | Default value: 270 | 271 | bubble_embeds_cc = no 272 | 273 | 274 | ### bubble simplify quotes 275 | When possible, delete the quotes around identifiers in the bubble. May lead to node name collision. 276 | Default value: 277 | 278 | bubble_simplify_quotes = True 279 | 280 | ### bubble with simple edges 281 | If disabled, will discard simple (i.e. non-power) edges of output. 282 | Default value: 283 | 284 | bubble_with_simple_edges = True 285 | 286 | ### config file 287 | Load options found in given config file, if it exists. 288 | Default value: 289 | 290 | config_file = 'powergrasp.cfg' 291 | 292 | ### multishot motif search 293 | Search for multiple motif in a single search. 294 | Accelerate the solving for graph with lots of equivalent motifs. It is generally a good option to enable. 295 | Default value: 296 | 297 | multishot_motif_search = True 298 | 299 | ### biclique lowerbound maxnei 300 | Optimization on biclique lowerbound computation. Can be costly. Deactivate with 2. With value at n, up to n neighbors are considered. 301 | Default value: 302 | 303 | biclique_lowerbound_maxnei = 2 304 | 305 | ### clingo options 306 | Arbitrary parameters to give to clingo (note that some, like multithreading or optmode, may already be set by other options). 307 | Default value: 308 | 309 | clingo_options = {} 310 | 311 | Give a particular configuration for bicliques search: 312 | 313 | clingo_options = {'no-star-biclique': '--configuration=handy'} 314 | 315 | ### clingo multithreading 316 | Number of CPU available to clingo, or 0 for autodetect number of CPU. 317 | Default value: 318 | 319 | clingo_multithreading = 1 320 | 321 | Use as many thread there are available CPU: 322 | 323 | clingo_multithreading = 0 324 | 325 | Specify a competing search between 4 threads: 326 | 327 | clingo_multithreading = '4,compete' 328 | 329 | ### parallel cc compression 330 | To use to compress connected components in different processes. 331 | Default value (optimized in memory): 332 | 333 | parallel_cc_compression = 1 334 | 335 | Compress with 4 processes : 336 | 337 | parallel_cc_compression = 4 338 | 339 | Compress with one process for each connected component : 340 | 341 | parallel_cc_compression = 0 342 | 343 | ### use star motif 344 | Two different motifs for stars and bicliques, so the search space for bicliques is smaller. Yields good performance improvements on big graphs. 345 | Default value: 346 | 347 | use_star_motif = True 348 | 349 | ### optimize for memory 350 | When possible, prefer memory over CPU. 351 | Default value: 352 | 353 | optimize_for_memory = False 354 | 355 | ### graph filtering 356 | Ignore edges dynamically determined as impossible to compress. 357 | Default value: 358 | 359 | graph_filtering = True 360 | 361 | ### keep single nodes 362 | If a node is found to be alone in its connected component, it will be kept nonetheless. 363 | Default value: 364 | 365 | keep_single_nodes = True 366 | 367 | ### parallel motif search 368 | Use multithreading to search for all motifs in the same time, instead of sequentially. 369 | Interestingly, this yields very poor results, and it's even worse with multiprocessing. 370 | 371 | parallel_motif_search = False 372 | 373 | ### motif type order 374 | Define in which order the motifs are searched, e.g. cliques, then bicliques then stars. 375 | 376 | motif_type_order = star,clique,non-star-biclique,biclique 377 | 378 | Instead of expliciting the exact motif names and order, it is also possible to specify a bound-based order: 379 | 380 | motif_type_order = greatest-upperbound-first 381 | 382 | Or any variation with `worst`, `lowerbound` and `last`. 383 | -------------------------------------------------------------------------------- /bench-opti.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Benchs done with: 4 | 5 | m real-matrixdb-core27 ; tail out/out.bbl 6 | 7 | get mean and diff to vanilla: 8 | p -c "l=tuple(map(float,input().split(', ')));m=sum(l)/len(l);print(round(m,2), str(round(100*(m/51.62),2))+'%')" 9 | 10 | Run results: 11 | 12 | vanilla: 53.6, 50.62, 50.63 13 | GF: 35.39, 36.73, 34.02 14 | SM: 65.44, 64.82, 66.74 15 | PM: 45.79, 46.52, 46.13 16 | MM: 19.7, 19.68, 20.04 17 | all but SM: 17.27, 16.04, 16.64 18 | all: 14.85, 14.03, 14.79 19 | 20 | NB: MM is named parallel in the thesis… and PM is not used. 21 | 22 | 23 | vanilla config: 24 | 25 | [options] 26 | MULTISHOT_MOTIF_SEARCH=false 27 | PARALLEL_MOTIF_SEARCH=false 28 | USE_STAR_MOTIF=false 29 | GRAPH_FILTERING=false 30 | 31 | GF config: 32 | 33 | MULTISHOT_MOTIF_SEARCH=false 34 | PARALLEL_MOTIF_SEARCH=false 35 | USE_STAR_MOTIF=false 36 | GRAPH_FILTERING=true 37 | 38 | 39 | SM config: 40 | 41 | MULTISHOT_MOTIF_SEARCH=false 42 | PARALLEL_MOTIF_SEARCH=false 43 | USE_STAR_MOTIF=true 44 | GRAPH_FILTERING=false 45 | 46 | PM config: 47 | 48 | MULTISHOT_MOTIF_SEARCH=false 49 | PARALLEL_MOTIF_SEARCH=true 50 | USE_STAR_MOTIF=false 51 | GRAPH_FILTERING=false 52 | 53 | MM config: 54 | 55 | MULTISHOT_MOTIF_SEARCH=true 56 | PARALLEL_MOTIF_SEARCH=false 57 | USE_STAR_MOTIF=false 58 | GRAPH_FILTERING=false 59 | -------------------------------------------------------------------------------- /data/abnormal.lp: -------------------------------------------------------------------------------- 1 | % This network raises an abnormal situation multiple times: 2 | edge("YNL069C","YOR063W"). 3 | edge("YBL087C","YGL031C"). 4 | edge("YER117W","YGL031C"). 5 | edge("YIL133C","YNL067W"). 6 | edge("YGL147C","YNL069C"). 7 | edge("YBL087C","YOR063W"). 8 | edge("YGR148C","YOR063W"). 9 | edge("YNL067W","YNL069C"). 10 | edge("YGL147C","YIL133C"). 11 | edge("YIL133C","YOR063W"). 12 | edge("YER117W","YGR148C"). 13 | edge("YER117W","YOR063W"). 14 | edge("YBL087C","YGR148C"). 15 | edge("YGL031C","YOR063W"). 16 | edge("YGL147C","YNL067W"). 17 | 18 | % The same, but with letter (easier to debug): 19 | edge(b,c). 20 | edge(a,d). 21 | edge(e,d). 22 | edge(f,g). 23 | edge(h,b). 24 | edge(a,c). 25 | edge(i,c). 26 | edge(g,b). 27 | edge(h,f). 28 | edge(f,c). 29 | edge(e,i). 30 | edge(e,c). 31 | edge(a,i). 32 | edge(d,c). 33 | edge(h,g). 34 | -------------------------------------------------------------------------------- /data/bintree.lp: -------------------------------------------------------------------------------- 1 | edge(aa,ab). 2 | edge(aa,ac). 3 | edge(ab,ad). 4 | edge(ab,ae). 5 | edge(ac,af). 6 | edge(ac,ag). 7 | edge(ad,ah). 8 | edge(ad,ai). 9 | edge(ae,aj). 10 | edge(ae,ak). 11 | edge(af,al). 12 | edge(af,am). 13 | edge(ag,an). 14 | edge(ag,ao). 15 | edge(ah,ap). 16 | edge(ah,aq). 17 | edge(ai,ar). 18 | edge(ai,as). 19 | edge(aj,at). 20 | edge(aj,au). 21 | edge(ak,av). 22 | edge(ak,aw). 23 | edge(al,ax). 24 | edge(al,ay). 25 | edge(am,az). 26 | edge(am,ba). 27 | edge(an,bb). 28 | edge(an,bc). 29 | edge(ao,bd). 30 | edge(ao,be). 31 | edge(ap,bf). 32 | edge(ap,bg). 33 | edge(aq,bh). 34 | edge(aq,bi). 35 | edge(ar,bj). 36 | edge(ar,bk). 37 | edge(as,bl). 38 | edge(as,bm). 39 | edge(at,bn). 40 | edge(at,bo). 41 | edge(au,bp). 42 | edge(au,bq). 43 | edge(av,br). 44 | edge(av,bs). 45 | edge(aw,bt). 46 | edge(aw,bu). 47 | edge(ax,bv). 48 | edge(ax,bw). 49 | edge(ay,bx). 50 | edge(ay,by). 51 | edge(az,bz). 52 | edge(az,ca). 53 | edge(ba,cb). 54 | edge(ba,cC). 55 | edge(bb,cd). 56 | edge(bb,ce). 57 | edge(bc,cf). 58 | edge(bc,cg). 59 | edge(bd,ch). 60 | edge(bd,ci). 61 | edge(be,cj). 62 | edge(be,ck). 63 | edge(bf,cl). 64 | edge(bf,cm). 65 | edge(bg,cn). 66 | edge(bg,co). 67 | edge(bh,cp). 68 | edge(bh,cq). 69 | edge(bi,cr). 70 | edge(bi,cs). 71 | edge(bj,ct). 72 | edge(bj,cu). 73 | edge(bk,cv). 74 | edge(bk,cw). 75 | edge(bl,cx). 76 | edge(bl,cy). 77 | edge(bm,cz). 78 | edge(bm,da). 79 | edge(bn,db). 80 | edge(bn,dc). 81 | edge(bo,dd). 82 | edge(bo,de). 83 | edge(bp,df). 84 | edge(bp,dg). 85 | edge(bq,dh). 86 | edge(bq,di). 87 | edge(br,dj). 88 | edge(br,dk). 89 | edge(bs,dl). 90 | edge(bs,dm). 91 | edge(bt,dn). 92 | edge(bt,do). 93 | edge(bu,dp). 94 | edge(bu,dq). 95 | edge(bv,dr). 96 | edge(bv,ds). 97 | edge(bw,dt). 98 | edge(bw,du). 99 | edge(bx,dv). 100 | edge(bx,dw). 101 | edge(by,dx). 102 | edge(by,dy). 103 | edge(bz,dz). 104 | edge(bz,ea). 105 | edge(ca,eb). 106 | edge(ca,ec). 107 | edge(cb,ed). 108 | edge(cb,ee). 109 | edge(cC,ef). 110 | edge(cC,eg). 111 | edge(cd,eh). 112 | edge(cd,ei). 113 | edge(ce,ej). 114 | edge(ce,ek). 115 | edge(cf,el). 116 | edge(cf,em). 117 | edge(cg,en). 118 | edge(cg,eo). 119 | edge(ch,ep). 120 | edge(ch,eq). 121 | edge(ci,er). 122 | edge(ci,es). 123 | edge(cj,et). 124 | edge(cj,eu). 125 | edge(ck,ev). 126 | edge(ck,ew). 127 | edge(cl,ex). 128 | edge(cl,ey). 129 | edge(cm,ez). 130 | -------------------------------------------------------------------------------- /data/clique.lp: -------------------------------------------------------------------------------- 1 | % 2 | % Clique of 4 elements. 3 | % Must produce only one concept. 4 | % 5 | edge(a,b). 6 | edge(a,c). 7 | edge(b,c). 8 | edge(b,d). 9 | edge(c,d). 10 | edge(a,d). 11 | 12 | -------------------------------------------------------------------------------- /data/cliques.lp: -------------------------------------------------------------------------------- 1 | 2 | % Clique of 3 elements. 3 | edge(("a";"b";"c"),("a";"b";"c")). 4 | 5 | % Clique of 4 elements. 6 | edge(a,b). 7 | edge(a,c). 8 | edge(b,c). 9 | edge(b,d). 10 | edge(c,d). 11 | edge(a,d). 12 | 13 | % Clique of 6 elements. 14 | edge((u;v;w;x;y;z),(u;v;w;x;y;z)). 15 | 16 | % % Clique of 10 elements. 17 | edge((1;2;3;4;5;6;7;8;9;0),(1;2;3;4;5;6;7;8;9;0)). 18 | -------------------------------------------------------------------------------- /data/complex-case-1.lp: -------------------------------------------------------------------------------- 1 | 2 | 3 | edge(l,(k;p)). 4 | edge(o,(m;n)). 5 | 6 | edge((d;m),(h;i)). 7 | edge((c;k),(e;f;h)). 8 | edge((a;b;c;d),(e;f;g;h;i)). 9 | -------------------------------------------------------------------------------- /data/concept-loop.lp: -------------------------------------------------------------------------------- 1 | % Case described ip94 of thesis livre II: 2 | edge((a;b),(c;d;e;f;i)). 3 | edge((e;f),(a;b;g;h;j)). 4 | edge((g;h),(c;d;e;f;k)). 5 | edge((c;d),(a;b;g;h;l)). 6 | 7 | % rel(X,Y) :- rel(Y,X). 8 | -------------------------------------------------------------------------------- /data/concomp.lp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | edge((a;b;c;d),e). 5 | 6 | edge((1;6),(2;3;4;5)). 7 | 8 | 9 | edge(42,23). 10 | -------------------------------------------------------------------------------- /data/consider-included-nodes.lp: -------------------------------------------------------------------------------- 1 | % Show that a powernode must include all nodes in the powernodes he contains. 2 | % In opposition to inclusions.lp, this case shows when the powernode can't be created. 3 | % The final star motif a×bd can't be created because b and d are in different blocks. 4 | % However, until this test case, a powernode was created, with all nodes of the score 8 5 | % motif inside, linked to a, leading falsely to the observation that a was linked 6 | % to all nodes. 7 | % This was only detected because in some case such inconsistency is rendered 8 | % very poorly in cytoscape. 9 | 10 | % If this test case must fail, probably there is no enforcement of the following rule: 11 | % if a powernode P includes a node in a block B and a node outside B, 12 | % then all nodes in B must be in P. 13 | 14 | % All nodes are in a ubiquitous powernode. 15 | edge((root;root2;root3),(a;b;c;d;e;f;g;h;i;j;l;m)). % score 36 16 | 17 | % A motif is built inside the ubiquitous powernode. 18 | edge((b;c),(d;e;f;g;h)). % score 8 19 | 20 | % The star creating (theoretically) the powernode including the motif. 21 | edge(a,(b;d)). % score 6: note the absence of e, f, g and h 22 | -------------------------------------------------------------------------------- /data/ddiam.lp: -------------------------------------------------------------------------------- 1 | % Double biclique overlapping with a third one, unambiguous 2 | 3 | % first biclique 4 | edge((a;d;d2),(b1;b2;c;e;q;o)). 5 | edge(b1,c). 6 | 7 | % second biclique 8 | edge((i;h),(f1;f2;g;j;l;p)). 9 | edge(f1,g). 10 | 11 | % m and n are linked to l,p,q and o 12 | edge((m;m2;n),(l;p;q)). 13 | 14 | % m, m2 and n is a clique 15 | edge(n,(m;m2)). 16 | -------------------------------------------------------------------------------- /data/diacli.lp: -------------------------------------------------------------------------------- 1 | % first biclique 2 | edge((a;d),(b;c;e;q;o)). 3 | edge(b,c). 4 | 5 | % clique 6 | edge((f;g;j;p;l;r;s),(f;g;j;p;l;r;s)). 7 | 8 | % m and n are linked to l,p,q and o 9 | edge((m;n),(l;p;s;q;o)). 10 | edge(n,m). 11 | -------------------------------------------------------------------------------- /data/diamond.lp: -------------------------------------------------------------------------------- 1 | %* 2 | % Simple Test Graph with two components: 3 | % One on (1,2,3,4), one on (a,b,c,d) 4 | Cliques are (1,2,3) and (2,3,4) 5 | Concepts are (1,4)X(2,3), (2)X(1,3,4), (3)X(1,2,4), (b)X(a,c) and (c)X(b,d) 6 | % Solution cover : 1) (1,4)X(2,3) 2) (2,3) 3) (a,c)X(b) 4) 7 | update(1)... 8 | concept(1,1,2,2). concept(1,1,2,3). concept(1,1,1,1). concept(1,1,1,4). 9 | update(2)... 10 | clique(1,2,3). clique(1,2,2). 11 | 12 | update(1)... 13 | concept(a,1,2,b). concept(a,1,1,c). concept(a,1,1,a). 14 | update(2)... 15 | concept(a,2,2,c). concept(a,2,1,d). 16 | 17 | *% 18 | edge(i,f). 19 | edge(i,g). 20 | edge(f,g). 21 | edge(f,h). 22 | edge(g,h). 23 | -------------------------------------------------------------------------------- /data/disjoint-subpnodes.lp: -------------------------------------------------------------------------------- 1 | % Creation of two independant powernodes inside a bigger one. 2 | 3 | edge((a;b;c;d;e;f),(a;b;c;d;e;f)). 4 | 5 | edge(g,(d;e;f)). 6 | edge(h,(b;c)). 7 | -------------------------------------------------------------------------------- /data/double-p-groups.lp: -------------------------------------------------------------------------------- 1 | % Showcase of two powergroups with an interface. 2 | 3 | % First p-group 4 | edge((a;b;c;d),(m;l)). 5 | % Second p-group 6 | edge((e;f;g;h),(i;j)). 7 | 8 | % Interface 9 | edge(a,(h;i)). 10 | edge(m,i). 11 | -------------------------------------------------------------------------------- /data/double_biclique_unambiguous.lp: -------------------------------------------------------------------------------- 1 | % first biclique 2 | edge((a;d;d2),(b1;b2;c;e;q;o)). 3 | edge(b1,c). 4 | 5 | % second biclique 6 | edge((i;h),(f1;f2;g;j;l;p)). 7 | edge(f1,g). 8 | 9 | % m and n are linked to l,p,q and o 10 | edge((m;m2;n),(l;p;q)). 11 | 12 | % m, m2 and n is a clique 13 | edge(n,(m;m2)). 14 | -------------------------------------------------------------------------------- /data/empty.lp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/data/empty.lp -------------------------------------------------------------------------------- /data/horrible_data.lp: -------------------------------------------------------------------------------- 1 | edge("[a]",("\"echo coucou\"";"'echo coucou'")). 2 | edge("[a,b]","$PYTHONPATH"). 3 | -------------------------------------------------------------------------------- /data/inclusions.lp: -------------------------------------------------------------------------------- 1 | 2 | edge((a;b;c;d;e;f;g;h;i;j;k;l),(a;b;c;d;e;f;g;h;i;k;l)). 3 | edge((d;e;f;g),(m;n;o;p)). 4 | edge((e;f;g),(q;r)). 5 | edge((f;g),(v;w;v2;w2)). 6 | 7 | edge((1;2;3;m;n;o;p),(1;2;3;m;n;o;p)). 8 | edge((q;r;5;6;7;8;9;10),(q;r;5;6;7;8;9;10)). 9 | -------------------------------------------------------------------------------- /data/motif-overlapping.lp: -------------------------------------------------------------------------------- 1 | % Show examples of motif overlapping. 2 | 3 | % A biclique is compressed, revealing a clique of three elements. 4 | edge((a;b;c),(d;e;f)). 5 | edge((a;b;c),(a;b;c)). 6 | 7 | % Two cliques are shallowed by a star. 8 | edge((a1;a2;a3;a4;a5),(a1;a2;a3;a4;a5)). % first clique 9 | edge((b1;b2;b3;b4),(b1;b2;b3;b4)). % smaller clique 10 | edge(h,(a1;b4)). % hub 11 | edge(h,(c1;c2;c3;c4;c5;c6;c7;c8;c9)). % enough nodes to make the star the biggest motif 12 | 13 | % A clique is eaten by a biclique. 14 | edge((x1;x2;x3;x4),(x1;x2;x3;x4)). % the clique 15 | edge((x4;y1;y2),(z1;z2;z3)). % 3×3 biclique. 16 | -------------------------------------------------------------------------------- /data/multiple-optimals.lp: -------------------------------------------------------------------------------- 1 | % Multiple bicliques of same score, to test multishot motif search. 2 | 3 | edge((a1;b1),(c1;d1;e1)). 4 | edge((a2;b2),(c2;d2;e2)). 5 | edge((a3;b3),(c3;d3;e3)). 6 | 7 | % Make them in the same cc 8 | edge(a,(a1;a2;a3)). 9 | 10 | % Show that further compression is not impacted. 11 | edge((a;b),(f1;f2)). 12 | 13 | -------------------------------------------------------------------------------- /data/n8_d0.7.lp: -------------------------------------------------------------------------------- 1 | edge("1","5"). 2 | edge("1","6"). 3 | edge("1","7"). 4 | edge("2","8"). 5 | edge("2","3"). 6 | edge("2","5"). 7 | edge("2","6"). 8 | edge("3","8"). 9 | edge("3","4"). 10 | edge("3","5"). 11 | edge("3","7"). 12 | edge("4","8"). 13 | edge("4","5"). 14 | edge("4","6"). 15 | edge("4","7"). 16 | edge("5","8"). 17 | edge("5","6"). 18 | edge("5","7"). 19 | edge("6","8"). 20 | edge("6","7"). 21 | -------------------------------------------------------------------------------- /data/one_edge.lp: -------------------------------------------------------------------------------- 1 | 2 | edge(a,b). 3 | -------------------------------------------------------------------------------- /data/order.lp: -------------------------------------------------------------------------------- 1 | % This use case is about node ordering in the graph. 2 | % In ASP, nodes are ordered lexicographically, 3 | % but integers are always smaller than litterals, 4 | % that are always smaller than string. 5 | 6 | edge(10,4). 7 | edge(10,5). 8 | edge(10,6). 9 | 10 | edge(a,10). 11 | edge("b",a). 12 | -------------------------------------------------------------------------------- /data/overlapping-bicliques.lp: -------------------------------------------------------------------------------- 1 | % a general star 2 | edge(a,(b;c;d;e;f;g;h;i;j;k)). 3 | 4 | % Small independant biclique 5 | edge((b;c),(d;e)). 6 | 7 | % a star 8 | edge(f,(g;h;i)). 9 | 10 | % overlapping with a biclique 11 | edge((f;g;h),(i;j;k)). 12 | -------------------------------------------------------------------------------- /data/partition.lp: -------------------------------------------------------------------------------- 1 | edge((a;b;i),(e;f;g;h)). 2 | edge((g;h),(a;b;c;d)). 3 | -------------------------------------------------------------------------------- /data/perfectfit.lp: -------------------------------------------------------------------------------- 1 | 2 | % first biclique 3 | edge((a;b;c;d),(e;f;g;h;i)). 4 | 5 | % second biclique 6 | edge((l;j),(c;d;e;f;g)). 7 | -------------------------------------------------------------------------------- /data/pnode-to-clique.lp: -------------------------------------------------------------------------------- 1 | edge(a,c). 2 | edge(a,d). 3 | edge(a,e). 4 | edge(b,c). 5 | edge(b,d). 6 | edge(b,e). 7 | edge(f,c). 8 | edge(f,d). 9 | edge(f,e). 10 | 11 | edge(c,d). 12 | edge(c,e). 13 | edge(d,e). 14 | -------------------------------------------------------------------------------- /data/prio_deg.lp: -------------------------------------------------------------------------------- 1 | % this is a case where the prioritization by node degree show its effect. 2 | 3 | % biclique that is normally the first motif to be compressed: {a,b,c}×{d,e} 4 | edge((a;b;c),(d;e)). 5 | 6 | % star with central node as the node with the maximal degree, overlapping the biclique. 7 | % will be compressed first if prioritization by degree is used. 8 | edge(s,(a;f;g;h)). % a is linked to 5 over nodes. 9 | -------------------------------------------------------------------------------- /data/puceron-data-2018.lp: -------------------------------------------------------------------------------- 1 | /home/lbourneu/data/stephanie/A.pisum_data_lucas/lncRNA_classes.lp -------------------------------------------------------------------------------- /data/quasibiclique.lp: -------------------------------------------------------------------------------- 1 | % This networks is made of multiple 2-balanced biclique. 2 | 3 | 4 | edge(a,f). edge(a,i). edge(a,j). % minobj is not linked to everyone 5 | edge(b,f). edge(b,g). edge(b,h). edge(b,i). edge(b,j). 6 | edge(c,f). edge(c,g). edge(c,h). edge(c,i). edge(c,j). 7 | edge(d,f). edge(d,g). edge(d,h). edge(d,j). 8 | edge(e,f). edge(e,g). edge(e,h). edge(e,i). edge(e,j). 9 | 10 | 11 | edge(r,q). edge(r,x). edge(r,y). edge(r,z). edge(r,p). 12 | edge(s,q). edge(s,x). edge(s,y). edge(s,p). 13 | edge(t,q). edge(t,x). edge(t,z). edge(t,p). 14 | edge(u,q). edge(u,x). edge(u,p). 15 | edge(v,q). edge(v,x). edge(v,y). edge(v,z). edge(v,p). 16 | 17 | 18 | edge(1,l). edge(1,m). edge(1,n). edge(1,o). edge(1,w). 19 | edge(2,l). edge(2,m). edge(2,n). edge(2,o). edge(2,w). 20 | edge(3,l). edge(3,m). edge(3,n). edge(3,o). edge(3,w). 21 | edge(4,l). edge(4,m). edge(4,n). edge(4,o). edge(4,w). 22 | edge(5,l). edge(5,m). edge(5,n). edge(5,o). edge(5,w). 23 | -------------------------------------------------------------------------------- /data/quoting.lp: -------------------------------------------------------------------------------- 1 | % This use case is about the effect of quoting the litterals. 2 | % If quoting is correcly handled, it should be used on litterals 3 | % and therefore a 1×2 star should be found. 4 | 5 | edge(b,a). 6 | edge("b",c). 7 | -------------------------------------------------------------------------------- /data/recipe-option-test.lp: -------------------------------------------------------------------------------- 1 | % Testing file for the RECIPE_FILE option. 2 | % See recipe-option-test.txt for the recipe used. 3 | 4 | % One biclique 5 | edge((a;b;c),(d;e;f)). 6 | edge(c,(g;h;i;j;k;l;m;n)). 7 | edge(a,(h;g;j;k;l;m;n)). 8 | -------------------------------------------------------------------------------- /data/recipe-option-test.txt: -------------------------------------------------------------------------------- 1 | biclique c g h i 2 | biclique,open a b d e 3 | biclique,optional unexisting nodes are not compressible 4 | star,breakable a h g l m n 5 | biclique,last c j k 6 | -------------------------------------------------------------------------------- /data/recipe-test-inclusion.lp: -------------------------------------------------------------------------------- 1 | % A test of recipe behavior, where an existing powernode 2 | % must be reused inside a new one. 3 | 4 | edge((a;b),(c;d;e;f)). 5 | edge((e;f),(g;h)). 6 | 7 | % With a recipe forcing ef×gh to be compressed first, 8 | % we should get a ab×cd(ef) motif on second step. 9 | -------------------------------------------------------------------------------- /data/recipe-test.lp: -------------------------------------------------------------------------------- 1 | % Testing file for the RECIPE_FILE option. 2 | % See recipe-test.txt for the recipe used. 3 | 4 | % One biclique 5 | edge((a;b;c),(d;e;f)). 6 | edge(c,(g;h;i;j)). 7 | -------------------------------------------------------------------------------- /data/recipe-test.txt: -------------------------------------------------------------------------------- 1 | biclique c g h i 2 | biclique a b d e 3 | biclique a b f 4 | biclique c d e 5 | -------------------------------------------------------------------------------- /data/single-node.lp: -------------------------------------------------------------------------------- 1 | edge(a,a). 2 | -------------------------------------------------------------------------------- /data/star.lp: -------------------------------------------------------------------------------- 1 | 2 | 3 | edge((a;b;c;d),e). 4 | 5 | -------------------------------------------------------------------------------- /data/structural-binding-maincc.lp: -------------------------------------------------------------------------------- 1 | % The biggest connected component of the structural binding graph. 2 | % Graph comes from Royer et al, named "Interactions of SH3 Carrying Proteins". 3 | edge("YGR233C","YPL031C"). 4 | edge("YDL155W","YLR210W"). 5 | edge("YDL155W","YGR109C"). 6 | edge("YDL155W","YGR108W"). 7 | edge("YDL155W","YMR199W"). 8 | edge("YDL155W","YPR119W"). 9 | edge("YDL155W","YPR120C"). 10 | edge("YDL155W","YPL256C"). 11 | edge("YDL240W","YPR165W"). 12 | edge("YBL047C","YBR109C"). 13 | edge("YLR210W","YMR199W"). 14 | edge("YLR210W","YPR119W"). 15 | edge("YLR210W","YPR120C"). 16 | edge("YLR210W","YPL256C"). 17 | edge("YOR127W","YPR165W"). 18 | edge("YIL063C","YLR293C"). 19 | edge("YGR218W","YLR293C"). 20 | edge("YBR140C","YNL098C"). 21 | edge("YER009W","YOR185C"). 22 | edge("YER009W","YLR293C"). 23 | edge("YGR109C","YMR199W"). 24 | edge("YGR109C","YPR119W"). 25 | edge("YGR109C","YPR120C"). 26 | edge("YGR109C","YPL256C"). 27 | edge("YDR002W","YLR293C"). 28 | edge("YGR108W","YMR199W"). 29 | edge("YGR108W","YPR119W"). 30 | edge("YGR108W","YPR120C"). 31 | edge("YGR108W","YPL256C"). 32 | edge("YAL040C","YPR119W"). 33 | edge("YAL040C","YPR120C"). 34 | edge("YJL020C","YMR032W"). 35 | edge("YJL020C","YMR109W"). 36 | edge("YJL020C","YKL129C"). 37 | edge("YHR114W","YMR109W"). 38 | edge("YHR114W","YKL129C"). 39 | edge("YHR023W","YPR188C"). 40 | edge("YHR023W","YMR109W"). 41 | edge("YHR023W","YKL129C"). 42 | edge("YHR023W","YOR326W"). 43 | edge("YLR371W","YPR165W"). 44 | edge("YER155C","YLR310C"). 45 | edge("YDL056W","YLR182W"). 46 | edge("YHR061C","YNL298W"). 47 | edge("YGR250C","YIR001C"). 48 | edge("YNL189W","YOR185C"). 49 | edge("YGL238W","YOR185C"). 50 | edge("YGL238W","YLR293C"). 51 | edge("YBR109C","YML057W"). 52 | edge("YBR109C","YLR433C"). 53 | edge("YBR109C","YMR109W"). 54 | edge("YBR109C","YKL129C"). 55 | edge("YBR109C","YGL106W"). 56 | edge("YBR109C","YOR326W"). 57 | edge("YGL158W","YLR113W"). 58 | edge("YER110C","YMR308C"). 59 | edge("YER110C","YLR293C"). 60 | edge("YMR199W","YPR119W"). 61 | edge("YMR199W","YPL031C"). 62 | edge("YMR199W","YPR120C"). 63 | edge("YNL098C","YOL081W"). 64 | edge("YNL098C","YOR101W"). 65 | edge("YER133W","YIR006C"). 66 | edge("YER133W","YLR449W"). 67 | edge("YDR490C","YKL166C"). 68 | edge("YBL007C","YHR016C"). 69 | edge("YBL007C","YBR200W"). 70 | edge("YBL007C","YCR088W"). 71 | edge("YBL007C","YDR388W"). 72 | edge("YJL187C","YPR119W"). 73 | edge("YKL101W","YOR061W"). 74 | edge("YDL159W","YGR040W"). 75 | edge("YDL159W","YLR362W"). 76 | edge("YGR040W","YLR362W"). 77 | edge("YBR212W","YDL167C"). 78 | edge("YBL085W","YBR200W"). 79 | edge("YBL085W","YLR229C"). 80 | edge("YNL093W","YOR370C"). 81 | edge("YNL093W","YOR089C"). 82 | edge("YJL005W","YOR361C"). 83 | edge("YPR119W","YPR120C"). 84 | edge("YNL289W","YPL031C"). 85 | edge("YBL016W","YLR362W"). 86 | edge("YBR028C","YHR135C"). 87 | edge("YJL041W","YLR347C"). 88 | edge("YHR071W","YPL031C"). 89 | edge("YDR477W","YER129W"). 90 | edge("YDR477W","YMR104C"). 91 | edge("YJL128C","YLR362W"). 92 | edge("YJL128C","YLR113W"). 93 | edge("YHR086W","YIL061C"). 94 | edge("YDR429C","YOR361C"). 95 | edge("YNL090W","YOR089C"). 96 | edge("YFL029C","YPR161C"). 97 | edge("YLL016W","YLR310C"). 98 | edge("YBR119W","YIL061C"). 99 | edge("YBR119W","YMR268C"). 100 | edge("YIR001C","YNL016W"). 101 | edge("YBL004W","YJL109C"). 102 | edge("YBL004W","YGL195W"). 103 | edge("YJR065C","YMR109W"). 104 | edge("YER136W","YKR014C"). 105 | edge("YER136W","YLR262C"). 106 | edge("YER136W","YFL005W"). 107 | edge("YER136W","YFL038C"). 108 | edge("YGL019W","YOR039W"). 109 | edge("YGL019W","YOR061W"). 110 | edge("YGL019W","YIL035C"). 111 | edge("YOR039W","YOR061W"). 112 | edge("YKL190W","YLR433C"). 113 | edge("YHL007C","YPL256C"). 114 | edge("YJL095W","YOR231W"). 115 | edge("YHL002W","YMR109W"). 116 | edge("YLR113W","YLR248W"). 117 | edge("YBR200W","YER114C"). 118 | edge("YBR200W","YCR088W"). 119 | edge("YBR200W","YDR388W"). 120 | edge("YBR017C","YHL030W"). 121 | edge("YBR017C","YGL195W"). 122 | edge("YBR017C","YLR293C"). 123 | edge("YBR017C","YLR347C"). 124 | edge("YHR030C","YOR231W"). 125 | edge("YHR030C","YLR182W"). 126 | edge("YDR264C","YNL154C"). 127 | edge("YDR264C","YHR135C"). 128 | edge("YBR260C","YKR055W"). 129 | edge("YBR260C","YIL118W"). 130 | edge("YNL175C","YPL043W"). 131 | edge("YBL105C","YOR231W"). 132 | edge("YBL105C","YPR165W"). 133 | edge("YDR309C","YNL298W"). 134 | edge("YDR432W","YNL016W"). 135 | edge("YIL035C","YML074C"). 136 | edge("YMR109W","YOR326W"). 137 | edge("YLR262C","YMR235C"). 138 | edge("YKL129C","YOR326W"). 139 | edge("YER114C","YER118C"). 140 | edge("YER114C","YLR229C"). 141 | edge("YIL061C","YKL074C"). 142 | edge("YIL061C","YMR268C"). 143 | edge("YDL101C","YHR135C"). 144 | edge("YDL051W","YNL110C"). 145 | edge("YFL033C","YJL164C"). 146 | edge("YAL041W","YLR229C"). 147 | edge("YFL039C","YOR326W"). 148 | edge("YKL074C","YMR268C"). 149 | edge("YGL106W","YOR326W"). 150 | edge("YFL005W","YFL038C"). 151 | edge("YDL135C","YIL118W"). 152 | edge("YDL135C","YPR165W"). 153 | edge("YIL118W","YPR165W"). 154 | edge("YDR389W","YPR165W"). 155 | edge("YER031C","YFL038C"). 156 | edge("YCR088W","YDR388W"). 157 | edge("YLR449W","YML074C"). 158 | edge("YIL007C","YPR165W"). 159 | edge("YGL097W","YLR293C"). 160 | edge("YER123W","YHR135C"). 161 | edge("YLR293C","YLR347C"). 162 | edge("YNL298W","YPL115C"). 163 | edge("YAL040C","YDL155W"). 164 | edge("YDL029W","YOR122C"). 165 | edge("YFL039C","YOR122C"). 166 | edge("YFL039C","YJL081C"). 167 | edge("YGR109C","YLR210W"). 168 | edge("YGR108W","YLR210W"). 169 | edge("YAL040C","YLR210W"). 170 | edge("YLR229C","YOR127W"). 171 | edge("YHR030C","YLR096W"). 172 | edge("YBR109C","YPL242C"). 173 | edge("YBR109C","YOR257W"). 174 | edge("YGR108W","YGR109C"). 175 | edge("YAL040C","YGR109C"). 176 | edge("YAL040C","YGR108W"). 177 | edge("YFL039C","YOR141C"). 178 | edge("YKL166C","YPL203W"). 179 | edge("YJL164C","YPL203W"). 180 | edge("YHR135C","YPL203W"). 181 | edge("YBL007C","YHR114W"). 182 | edge("YFL039C","YHR023W"). 183 | edge("YGL106W","YHR023W"). 184 | edge("YAL029C","YHR023W"). 185 | edge("YIL061C","YIR009W"). 186 | edge("YGL195W","YGL241W"). 187 | edge("YER155C","YLR371W"). 188 | edge("YDL108W","YPR025C"). 189 | edge("YPL031C","YPR025C"). 190 | edge("YGL044C","YOL123W"). 191 | edge("YBL007C","YFR024C"). 192 | edge("YHR030C","YHR102W"). 193 | edge("YNL016W","YNL251C"). 194 | edge("YDR309C","YHR061C"). 195 | edge("YGL238W","YNL189W"). 196 | edge("YLR335W","YNL189W"). 197 | edge("YMR308C","YNL189W"). 198 | edge("YLR293C","YNL189W"). 199 | edge("YLR347C","YNL189W"). 200 | edge("YJL031C","YPR176C"). 201 | edge("YJL128C","YNR031C"). 202 | edge("YAL029C","YBR109C"). 203 | edge("YLR293C","YLR335W"). 204 | edge("YMR235C","YOR185C"). 205 | edge("YLR293C","YOR185C"). 206 | edge("YLR347C","YOR185C"). 207 | edge("YBL016W","YGL158W"). 208 | edge("YDR477W","YGL158W"). 209 | edge("YKR014C","YML064C"). 210 | edge("YBR017C","YER110C"). 211 | edge("YJL005W","YNL098C"). 212 | edge("YLR310C","YNL098C"). 213 | edge("YJL109C","YLR249W"). 214 | edge("YJL164C","YKL166C"). 215 | edge("YHR135C","YKL166C"). 216 | edge("YJL187C","YMR001C"). 217 | edge("YKL190W","YML057W"). 218 | edge("YLR433C","YML057W"). 219 | edge("YIL035C","YKL101W"). 220 | edge("YFL029C","YPR054W"). 221 | edge("YHR030C","YPR054W"). 222 | edge("YLR229C","YOL113W"). 223 | edge("YBL016W","YDL159W"). 224 | edge("YBL016W","YGR040W"). 225 | edge("YBR119W","YOR319W"). 226 | edge("YIL061C","YOR319W"). 227 | edge("YDL051W","YDL167C"). 228 | edge("YBL085W","YMR032W"). 229 | edge("YER118C","YMR032W"). 230 | edge("YER136W","YNL093W"). 231 | edge("YKR014C","YNL093W"). 232 | edge("YJL095W","YPL140C"). 233 | edge("YHR030C","YPL140C"). 234 | edge("YLR085C","YNL271C"). 235 | edge("YJR065C","YNL271C"). 236 | edge("YDL029W","YNL271C"). 237 | edge("YFL039C","YNL271C"). 238 | edge("YIL159W","YNL271C"). 239 | edge("YIR006C","YNL084C"). 240 | edge("YPL256C","YPR119W"). 241 | edge("YER136W","YGL210W"). 242 | edge("YBR017C","YJL041W"). 243 | edge("YNL025C","YPL042C"). 244 | edge("YDR477W","YPL042C"). 245 | edge("YGR092W","YPL042C"). 246 | edge("YNL016W","YPL190C"). 247 | edge("YNL025C","YPL031C"). 248 | edge("YDL127W","YPL031C"). 249 | edge("YFL033C","YPL031C"). 250 | edge("YDR477W","YNL025C"). 251 | edge("YHR135C","YNL025C"). 252 | edge("YJL031C","YOR370C"). 253 | edge("YOR089C","YOR370C"). 254 | edge("YBR264C","YOR370C"). 255 | edge("YFL038C","YOR370C"). 256 | edge("YAR019C","YGR092W"). 257 | edge("YCR073C","YJL128C"). 258 | edge("YLR113W","YLR362W"). 259 | edge("YER123W","YLR362W"). 260 | edge("YAL041W","YGR152C"). 261 | edge("YGR080W","YLL050C"). 262 | edge("YCR088W","YLL050C"). 263 | edge("YCR088W","YGR080W"). 264 | edge("YDR432W","YHR086W"). 265 | edge("YER136W","YML001W"). 266 | edge("YLR262C","YML001W"). 267 | edge("YER136W","YOR089C"). 268 | edge("YKR014C","YOR089C"). 269 | edge("YDR432W","YIR001C"). 270 | edge("YDL051W","YIR001C"). 271 | edge("YER165W","YIR001C"). 272 | edge("YDR122W","YPR120C"). 273 | edge("YPL256C","YPR120C"). 274 | edge("YLR310C","YOR101W"). 275 | edge("YBL004W","YMR308C"). 276 | edge("YLR293C","YMR308C"). 277 | edge("YLR347C","YMR308C"). 278 | edge("YDL029W","YJR065C"). 279 | edge("YNL154C","YPL204W"). 280 | edge("YOR061W","YPL204W"). 281 | edge("YLR182W","YPL204W"). 282 | edge("YML074C","YPL204W"). 283 | edge("YER123W","YPL204W"). 284 | edge("YHR135C","YPL204W"). 285 | edge("YGR159C","YKL193C"). 286 | edge("YBR264C","YER136W"). 287 | edge("YER031C","YER136W"). 288 | edge("YER031C","YKR014C"). 289 | edge("YHL034C","YMR302C"). 290 | edge("YGR159C","YMR302C"). 291 | edge("YDR432W","YMR302C"). 292 | edge("YGR159C","YHL034C"). 293 | edge("YDR432W","YHL034C"). 294 | edge("YCR088W","YHR016C"). 295 | edge("YDR388W","YHR016C"). 296 | edge("YIL035C","YOR039W"). 297 | edge("YHR082C","YJL095W"). 298 | edge("YHR030C","YJL095W"). 299 | edge("YHL002W","YNR006W"). 300 | edge("YER118C","YHL002W"). 301 | edge("YAL041W","YBR200W"). 302 | edge("YER111C","YHR030C"). 303 | edge("YER123W","YNL154C"). 304 | edge("YHR135C","YNL154C"). 305 | edge("YFL005W","YKR055W"). 306 | edge("YDL135C","YKR055W"). 307 | edge("YIL007C","YKR055W"). 308 | edge("YOR361C","YPL043W"). 309 | edge("YNL110C","YPL043W"). 310 | edge("YER114C","YNL298W"). 311 | edge("YLR229C","YNL298W"). 312 | edge("YDR432W","YGR159C"). 313 | edge("YIL035C","YOR061W"). 314 | edge("YKL129C","YMR109W"). 315 | edge("YDL029W","YMR109W"). 316 | edge("YER118C","YMR109W"). 317 | edge("YGL106W","YMR109W"). 318 | edge("YAL029C","YMR109W"). 319 | edge("YCR088W","YMR109W"). 320 | edge("YDR388W","YMR109W"). 321 | edge("YFL005W","YLR262C"). 322 | edge("YLR293C","YMR235C"). 323 | edge("YDL029W","YKL129C"). 324 | edge("YAL029C","YKL129C"). 325 | edge("YDR388W","YKL129C"). 326 | edge("YAL041W","YER114C"). 327 | edge("YDL101C","YPL153C"). 328 | edge("YER111C","YPL153C"). 329 | edge("YGL195W","YJL109C"). 330 | edge("YDL051W","YNL016W"). 331 | edge("YDL135C","YLR229C"). 332 | edge("YAL029C","YFL039C"). 333 | edge("YER165W","YGL044C"). 334 | edge("YAL029C","YGL106W"). 335 | edge("YAL029C","YOR326W"). 336 | edge("YER111C","YLR182W"). 337 | edge("YNL110C","YOR361C"). 338 | -------------------------------------------------------------------------------- /data/suboptimal.lp: -------------------------------------------------------------------------------- 1 | % Case proving that optimal compression can't always 2 | % be reached with standard heurisitic. 3 | 4 | edge((a;b),(c;d;i;e;f)). 5 | edge((c;d),(l;g;h)). 6 | edge((e;f),(j;g;h)). 7 | edge((g;h),(k;c;d)). 8 | 9 | 10 | rel(X,Y):- rel(Y,X). 11 | -------------------------------------------------------------------------------- /data/test.gml: -------------------------------------------------------------------------------- 1 | graph [ 2 | node [ 3 | id 0 4 | label "d" 5 | ] 6 | node [ 7 | id 1 8 | label "s" 9 | ] 10 | node [ 11 | id 2 12 | label "g" 13 | ] 14 | node [ 15 | id 3 16 | label "w" 17 | ] 18 | node [ 19 | id 4 20 | label "c" 21 | ] 22 | node [ 23 | id 5 24 | label "l" 25 | ] 26 | node [ 27 | id 6 28 | label "b" 29 | ] 30 | node [ 31 | id 7 32 | label "m" 33 | ] 34 | node [ 35 | id 8 36 | label "f" 37 | ] 38 | node [ 39 | id 9 40 | label "p" 41 | ] 42 | node [ 43 | id 10 44 | label "v" 45 | ] 46 | edge [ 47 | source 0 48 | target 6 49 | width 8.75 50 | ] 51 | edge [ 52 | source 0 53 | target 1 54 | width 8.25 55 | ] 56 | edge [ 57 | source 0 58 | target 3 59 | width 6.0 60 | ] 61 | edge [ 62 | source 0 63 | target 4 64 | width 10.0 65 | ] 66 | edge [ 67 | source 1 68 | target 6 69 | width 6.527777777777778 70 | ] 71 | edge [ 72 | source 1 73 | target 3 74 | width 5.4 75 | ] 76 | edge [ 77 | source 1 78 | target 4 79 | width 7.0 80 | ] 81 | edge [ 82 | source 2 83 | target 6 84 | width 5.292397660818714 85 | ] 86 | edge [ 87 | source 3 88 | target 6 89 | width 8.11111111111111 90 | ] 91 | edge [ 92 | source 3 93 | target 4 94 | width 6.0 95 | ] 96 | edge [ 97 | source 4 98 | target 6 99 | width 8.518518518518519 100 | ] 101 | edge [ 102 | source 4 103 | target 8 104 | width 5.0925925925925934 105 | ] 106 | edge [ 107 | source 5 108 | target 7 109 | width 6.923076923076923 110 | ] 111 | edge [ 112 | source 5 113 | target 9 114 | width 8.787878787878787 115 | ] 116 | edge [ 117 | source 5 118 | target 10 119 | width 6.190476190476191 120 | ] 121 | edge [ 122 | source 6 123 | target 7 124 | width 7.3076923076923075 125 | ] 126 | edge [ 127 | source 6 128 | target 8 129 | width 5.185185185185185 130 | ] 131 | edge [ 132 | source 6 133 | target 10 134 | width 5.456349206349206 135 | ] 136 | edge [ 137 | source 7 138 | target 10 139 | width 6.6208791208791204 140 | ] 141 | ] 142 | -------------------------------------------------------------------------------- /data/test.graphml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /data/testblocks.lp: -------------------------------------------------------------------------------- 1 | 2 | % external clique 3 | edge(a,b). 4 | edge(a,c). 5 | edge(a,d). 6 | edge(a,e). 7 | edge(b,c). 8 | edge(b,d). 9 | edge(b,e). 10 | edge(c,d). 11 | edge(c,e). 12 | edge(d,e). 13 | 14 | % external clique 2 15 | edge((f;g;h;i;j;m),(f;g;h;i;j;m)). 16 | 17 | % biclique of 4 elements of clique 1 and 2 18 | edge(f,(a;b;c;d)). 19 | 20 | % biclique of 4 elements of previous biclique and one external element 21 | edge(l,f). 22 | edge(l,g). 23 | edge(l,h). 24 | -------------------------------------------------------------------------------- /data/todel.lp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | % Case study 1 for lattice-based compression 5 | % edge(a,(b;c;d;x)). 6 | % edge(b,(a;c;d;y)). 7 | % edge(c,(a;b;z)). 8 | % edge(d,(a;b;w)). 9 | 10 | 11 | % Case study 2 for lattice-based compression: overlapping 3 and 4 cliques 12 | % edge((a;b;c;d),(a;b;c;d)). % first clique 13 | % edge((d;e;f),(d;e;f)). % small clique beside the first 14 | % edge(b,g). % noise 15 | 16 | 17 | % Case study 3 for lattice-based compression: overlapping 4 cliques 18 | % edge((a;b;d;e),(a;b;d;e)). % first clique 19 | % edge((b;c;e;f),(b;c;e;f)). % second clique 20 | % edge(b,g). % noise 21 | 22 | 23 | % Case study: suboptimal with some specifics removed 24 | % suboptimal cutted-3 with some specifics removed 25 | % edge((a;b),(c;d;g)). 26 | % edge((c;d),(e;f;h)). 27 | % edge((e;f),(a;b;i)). 28 | 29 | % suboptimal cutted-4 with some specifics removed 30 | % edge((a;b),(c;d;j)). 31 | % edge((c;d),(e;f;k)). 32 | % edge((e;f),(g;h;l)). 33 | % edge((g;h),(a;b;i)). 34 | 35 | % suboptimal cutted-5 with some specifics removed 36 | % edge((a;b),(c;d;l)). 37 | % edge((c;d),(e;f;m)). 38 | % edge((e;f),(g;h;n)). 39 | % edge((g;h),(i;j;o)). 40 | % edge((i;j),(a;b;k)). 41 | 42 | % suboptimal cutted-6 with some specifics removed 43 | % edge((a;b),(c;d;n)). 44 | % edge((c;d),(e;f)). 45 | % edge((e;f),(g;h)). 46 | % edge((g;h),(i;j;q)). 47 | % edge((i;j),(k;l)). 48 | % edge((k;l),(a;b)). 49 | -------------------------------------------------------------------------------- /data/triplets.lp: -------------------------------------------------------------------------------- 1 | % Example of triplet concepts 2 | 3 | 4 | edge((a;b;c),(d;e;f)). 5 | edge((a;b;c;d;e;f),(g;h;i)). 6 | edge((g;h;i),(g;h;i)). 7 | 8 | edge((b;c),(l;m;n;o;p;q)). 9 | edge((e;f),(l;m;n;o;p;q)). 10 | edge((l;m;n;o;p;q),(l;m;n;o;p;q)). 11 | -------------------------------------------------------------------------------- /data/typical-use-case.lp: -------------------------------------------------------------------------------- 1 | % The typical use case for the lattice-based search space formalization. 2 | 3 | edge((a;b;c),(e;d)). 4 | edge(g,e). 5 | edge((d;i;j;k),(e;f;g;h)). 6 | 7 | % motifs to compress (for ~/pocs/generalist_compression) 8 | motif(1,e,(a;b;c;d;g;i;j;k)). % concept 1 9 | motif(2,g,(d;i;j;k)). % concept 2 10 | motif(3,(d;i;j;k),(f;g;h)). % concept 3 11 | motif(4,d,(a;b;c)). % concept 7 12 | 13 | -------------------------------------------------------------------------------- /data/unclique.lp: -------------------------------------------------------------------------------- 1 | % non maximal clique 2 | edge((a;b;c;d),(a;b;c;d)). 3 | 4 | % maximal biclique 5 | edge((c;e;f;g),(h;i)). 6 | -------------------------------------------------------------------------------- /data/variable-name.gml: -------------------------------------------------------------------------------- 1 | graph [ 2 | node [ 3 | id 0 4 | label "B" 5 | ] 6 | node [ 7 | id 1 8 | label "C" 9 | ] 10 | node [ 11 | id 2 12 | label "D" 13 | ] 14 | node [ 15 | id 3 16 | label "E" 17 | ] 18 | node [ 19 | id 4 20 | label ""A"" 21 | ] 22 | edge [ 23 | source 0 24 | target 1 25 | ] 26 | edge [ 27 | source 0 28 | target 2 29 | ] 30 | edge [ 31 | source 0 32 | target 4 33 | ] 34 | edge [ 35 | source 3 36 | target 4 37 | ] 38 | ] 39 | -------------------------------------------------------------------------------- /data/wiki-tree-decomposition.lp: -------------------------------------------------------------------------------- 1 | % Graph from wikipedia's tree decomposition page. 2 | % https://en.wikipedia.org/wiki/Tree_decomposition 3 | 4 | edge(a,(b;c)). 5 | edge(d,(c;e)). 6 | edge(f,(b;g)). 7 | edge(h,(e;g)). 8 | 9 | edge(b,(c;e;g)). 10 | edge(e,(c;b;g)). 11 | -------------------------------------------------------------------------------- /data/zorro.lp: -------------------------------------------------------------------------------- 1 | 2 | % graph 3 | edge((a1;a2;a3;a4),(b1;b2;b3;b4;b5;b6)). 4 | edge((c1;c2;e3;e4),(b1;b2;d1;d2;d3)). 5 | edge((e1;e2;e3;e4),(f1;f2;f3;f4)). 6 | 7 | % motifs to compress (for ~/pocs/generalist_compression) 8 | motif(1,(a1;a2;a3;a4),(b1;b2;b3;b4;b5;b6)). 9 | motif(2,(c1;c2;e3;e4),(b1;b2;d1;d2;d3)). 10 | motif(3,(e1;e2;e3;e4),(f1;f2;f3;f4)). 11 | -------------------------------------------------------------------------------- /out/.gitignore: -------------------------------------------------------------------------------- 1 | stats.csv 2 | *.bbl 3 | -------------------------------------------------------------------------------- /out/thesis/concept-cycle-4.sif: -------------------------------------------------------------------------------- 1 | a Edge j 2 | b Edge j 3 | a Edge c 4 | a Edge d 5 | a Edge g 6 | a Edge h 7 | b Edge c 8 | b Edge d 9 | b Edge g 10 | b Edge h 11 | 12 | e Edge l 13 | f Edge l 14 | e Edge c 15 | e Edge d 16 | e Edge g 17 | e Edge h 18 | f Edge c 19 | f Edge d 20 | f Edge g 21 | f Edge h 22 | 23 | g Edge i 24 | h Edge i 25 | 26 | c Edge k 27 | d Edge k 28 | -------------------------------------------------------------------------------- /out/thesis/matrixdb_CORE27_example__a_0-_b_0-_c_3-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/matrixdb_CORE27_example__a_0-_b_0-_c_3-.png -------------------------------------------------------------------------------- /out/thesis/matrixdb_CORE27_example__a_0-_b_0-_c_3-zoom.png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/matrixdb_CORE27_example__a_0-_b_0-_c_3-zoom.png.png -------------------------------------------------------------------------------- /out/thesis/matrixdb_CORE27_example__a_0-_b_0-_c_3-zoom.png.png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/matrixdb_CORE27_example__a_0-_b_0-_c_3-zoom.png.png.png -------------------------------------------------------------------------------- /out/thesis/matrixdb_CORE27_example__a_3-_b_3-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/matrixdb_CORE27_example__a_3-_b_3-_c_0-.png -------------------------------------------------------------------------------- /out/thesis/miRNA_mRNA_diff-no3019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/miRNA_mRNA_diff-no3019.png -------------------------------------------------------------------------------- /out/thesis/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.bbl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.bbl.png -------------------------------------------------------------------------------- /out/thesis/thesis-network-triplet-zoom-a_0-_b_0-_c_0-.bbl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/thesis-network-triplet-zoom-a_0-_b_0-_c_0-.bbl.png -------------------------------------------------------------------------------- /out/thesis/triplet.sif: -------------------------------------------------------------------------------- 1 | node12 DirectedEdge node10 2 | node12 DirectedEdge node9 3 | node12 DirectedEdge node8 4 | node12 DirectedEdge node7 5 | node11 DirectedEdge node10 6 | node11 DirectedEdge node9 7 | node11 DirectedEdge node8 8 | node11 DirectedEdge node7 9 | node11 DirectedEdge node12 10 | node8 DirectedEdge node10 11 | node8 DirectedEdge node9 12 | node7 DirectedEdge node10 13 | node7 DirectedEdge node9 14 | -------------------------------------------------------------------------------- /out/thesis/zorro-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-annotated.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1-c2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1-c2.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1-c21-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1-c21-annotated.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1-c21-c31-c32-c22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1-c21-c31-c32-c22.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1-c22-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1-c22-annotated.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1-c3-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1-c3-annotated.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1-c3-c21-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1-c3-c21-annotated.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1-c3-c22-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1-c3-c22-annotated.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1-c3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1-c3.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1-c31-c21-c22-c32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1-c31-c21-c22-c32.png -------------------------------------------------------------------------------- /out/thesis/zorro-c1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-c1.png -------------------------------------------------------------------------------- /out/thesis/zorro-compression-middle-first.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-compression-middle-first.png -------------------------------------------------------------------------------- /out/thesis/zorro-compression-per-concept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-compression-per-concept.png -------------------------------------------------------------------------------- /out/thesis/zorro-compression-regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro-compression-regular.png -------------------------------------------------------------------------------- /out/thesis/zorro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/out/thesis/zorro.png -------------------------------------------------------------------------------- /out/thesis/zorro.sif: -------------------------------------------------------------------------------- 1 | a1 DirectedEdge b1 2 | a1 DirectedEdge b2 3 | a1 DirectedEdge b3 4 | a1 DirectedEdge b4 5 | a1 DirectedEdge b5 6 | a1 DirectedEdge b6 7 | a2 DirectedEdge b1 8 | a2 DirectedEdge b2 9 | a2 DirectedEdge b3 10 | a2 DirectedEdge b4 11 | a2 DirectedEdge b5 12 | a2 DirectedEdge b6 13 | a3 DirectedEdge b1 14 | a3 DirectedEdge b2 15 | a3 DirectedEdge b3 16 | a3 DirectedEdge b4 17 | a3 DirectedEdge b5 18 | a3 DirectedEdge b6 19 | a4 DirectedEdge b1 20 | a4 DirectedEdge b2 21 | a4 DirectedEdge b3 22 | a4 DirectedEdge b4 23 | a4 DirectedEdge b5 24 | a4 DirectedEdge b6 25 | 26 | 27 | c1 DirectedEdge b5 28 | c1 DirectedEdge b6 29 | c1 DirectedEdge d1 30 | c1 DirectedEdge d2 31 | c1 DirectedEdge d3 32 | c2 DirectedEdge b5 33 | c2 DirectedEdge b6 34 | c2 DirectedEdge d1 35 | c2 DirectedEdge d2 36 | c2 DirectedEdge d3 37 | 38 | e1 DirectedEdge b5 39 | e1 DirectedEdge b6 40 | e2 DirectedEdge b5 41 | e2 DirectedEdge b6 42 | 43 | e1 DirectedEdge d1 44 | e1 DirectedEdge d2 45 | e1 DirectedEdge d3 46 | e2 DirectedEdge d1 47 | e2 DirectedEdge d2 48 | e2 DirectedEdge d3 49 | 50 | 51 | e1 DirectedEdge f1 52 | e1 DirectedEdge f2 53 | e1 DirectedEdge f3 54 | e1 DirectedEdge f4 55 | e2 DirectedEdge f1 56 | e2 DirectedEdge f2 57 | e2 DirectedEdge f3 58 | e2 DirectedEdge f4 59 | e3 DirectedEdge f1 60 | e3 DirectedEdge f2 61 | e3 DirectedEdge f3 62 | e3 DirectedEdge f4 63 | e4 DirectedEdge f1 64 | e4 DirectedEdge f2 65 | e4 DirectedEdge f3 66 | e4 DirectedEdge f4 67 | -------------------------------------------------------------------------------- /powergrasp/__init__.py: -------------------------------------------------------------------------------- 1 | import pkg_resources 2 | ASP_FILES = { 3 | fname: pkg_resources.resource_filename(__name__, 'asp/' + fname + '.lp') 4 | for fname in ('search-triplet', 'search-fullbiclique', 'search-biclique', 'search-quasibiclique', 'search-star', 'search-clique', 'process-motif', 'block-constraint-cpu', 'block-constraint-memory', 'scoring_powergraph') 5 | } 6 | 7 | from .routines import compress_by_cc 8 | 9 | __version__ = '0.8.19.dev0' 10 | -------------------------------------------------------------------------------- /powergrasp/__main__.py: -------------------------------------------------------------------------------- 1 | """PowerGrASP package. 2 | 3 | """ 4 | 5 | from . import cli 6 | from .routines import compress_by_cc 7 | from .constants import print_config 8 | 9 | 10 | def run_cli(): 11 | args = cli.parse_args(__doc__) 12 | 13 | if args.show_config: 14 | print_config() 15 | exit() 16 | elif args.infile: 17 | with open(args.outfile, 'w') as fd: 18 | for line in compress_by_cc(args.infile, args.recipe): 19 | fd.write(line + '\n') 20 | else: 21 | print('Nothing to do.') 22 | 23 | 24 | if __name__ == "__main__": 25 | run_cli() 26 | -------------------------------------------------------------------------------- /powergrasp/asp.py: -------------------------------------------------------------------------------- 1 | """Search for motif using clyngor/clingo/ASP. 2 | 3 | Function solve_motif_search is defined according to global constants. 4 | 5 | """ 6 | 7 | import math 8 | import clyngor 9 | from powergrasp.constants import (COVERED_EDGES_FROM_ASP, SHOW_STORY, SHOW_DEBUG, 10 | MULTISHOT_MOTIF_SEARCH, CLINGO_MULTITHREADING) 11 | 12 | 13 | def _build_solver(step:int, lowerbound:int, upperbound:int, files:iter, graph:str, options:str) -> iter: 14 | """Return iterator over found models""" 15 | constants = {'k': step, 'lowerbound': lowerbound, 'upperbound': upperbound} 16 | if COVERED_EDGES_FROM_ASP: 17 | constants['covered_edges_from_asp'] = 1 18 | options += CLINGO_MULTITHREADING 19 | models = clyngor.solve(files=tuple(files), inline=str(graph), constants=constants, stats=False, options=options) 20 | if SHOW_STORY: 21 | print('SOLVE', models.command) 22 | return models.by_predicate.careful_parsing 23 | 24 | 25 | def oneshot_motif_search(step:int, lowerbound:int, upperbound:int, files:iter, graph:str, options:str='') -> iter: 26 | """Return iterable over the generator of the one best model 27 | containing atoms found in best model""" 28 | model = None 29 | for model in _build_solver(step, lowerbound, upperbound, files, graph, options): 30 | pass # get the last one 31 | if model: 32 | yield model 33 | 34 | 35 | def multishot_motif_search(step:int, lowerbound:int, upperbound:int, files:iter, graph:str, options:str='') -> iter: 36 | """Yield atoms found in bests models""" 37 | all_models = _build_solver(step, lowerbound, upperbound, files, graph, options='--opt-mode=optN ' + options) 38 | best_opt, models = math.inf, [] 39 | for model, opt in all_models.with_optimization: 40 | if SHOW_DEBUG: 41 | print('OPT, MODEL:', opt[0], model) 42 | if opt[0] < best_opt: # smaller is best 43 | best_opt, models = opt[0], [] # model will be given again as last model, so no need to include it twice 44 | else: 45 | models.append(model) 46 | yield from models 47 | 48 | 49 | # define the default behavior 50 | if MULTISHOT_MOTIF_SEARCH: 51 | solve_motif_search = multishot_motif_search 52 | else: 53 | solve_motif_search = oneshot_motif_search 54 | -------------------------------------------------------------------------------- /powergrasp/asp/block-constraint-cpu.lp: -------------------------------------------------------------------------------- 1 | % Implementation of the block overlap constraint, optimized for CPU. 2 | % If a powernode contains a node in a block and a node not in the block, 3 | % all nodes in block must be contained. 4 | includedblock(L,U,T,X):- newconcept(T,X) ; block(L,U,X) ; % X is in the block 5 | newconcept(T,Z) ; not block(L,U,Z). % Z is outside 6 | :- includedblock(L,U,T,X); not newconcept(T,Y) ; 7 | block(L,U,Y) ; X!=Y. % Y is not in the pnode 8 | 9 | % NB: this constraint may be written in many ways. 10 | % See debug/overlap-block-constraint for further investigations. 11 | -------------------------------------------------------------------------------- /powergrasp/asp/block-constraint-memory.lp: -------------------------------------------------------------------------------- 1 | % Implementation of the block overlap constraint, optimized for memory. 2 | % If a powernode contains a node in a block and a node not in the block, 3 | % all nodes in block must be contained. 4 | includedblock(L,U,T):- newconcept(T,X) ; block(L,U,X). % X is in the block 5 | strictlyincludedblock(L,U,T):- 6 | includedblock(L,U,T) ; newconcept(T,Z) ; not block(L,U,Z). % Z is outside 7 | :- strictlyincludedblock(L,U,T) ; not newconcept(T,Y) ; block(L,U,Y). % Y is not in the pnode 8 | 9 | % NB: this constraint may be written in many ways. 10 | % See debug/overlap-block-constraint for further investigations. 11 | -------------------------------------------------------------------------------- /powergrasp/asp/extract-ccs.lp: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Extraction of graph data from edge information. 3 | % 4 | % initial version: 09/12/2014 J. Nicolas 5 | % revised version: 29/04/2014 L. Bourneuf 6 | % 7 | % Extract the connected components of the graph 8 | % Input: 9 | % - edge(X,Y): there exists an edge between X and Y in the graph. 10 | % Output (one model per connected component): 11 | % - cc(CC): CC is the minimal element of a connected component. 12 | % - membercc(X,Y): there exists a path from X to Y, X P == B): done 73 | % else: (<=> P is included in B) 74 | % create include_block(k,B,P) 75 | % for each block C in B: 76 | % assert(C is included in P OR C inter P = {0}) 77 | % if C included in P: 78 | % don't create include_block(k,B,C) 79 | % create include_block(k,P,C) 80 | % else: (C inter P = {0}) 81 | % do nothing else 82 | % 83 | % in a more logical way: 84 | % - powernode P is included in its parent block B 85 | hierarchy_add(KP,TP,k,T):- parent_block(KP,TP,T) ; not star(T). 86 | % - all blocks included in B that are in P are included in P instead of B 87 | change_hierarchy(KP,TP,k,T,L,U):- 88 | parent_block(KP,TP,T) ; % the parent block… 89 | include_block(KP,TP,L,U) ; L=lowerbound ; clique ; edgecover(1,N1). 45 | score(N):- N<=upperbound; N>=lowerbound; star(T) ; edgecover(3-T,N) ; biclique ; not quasibiclique. 46 | score(N):- N=N1*N2; N<=upperbound; N>=lowerbound; biclique ; not star(1); not star(2); 47 | edgecover(1,N1) ; edgecover(2,N2). 48 | % score(N):- N={covered_edge(_,_)} ; quasibiclique; N<=upperbound; N>=lowerbound. 49 | 50 | % Minimize score 51 | #minimize{(upperbound-S)@1,S:score(S)}. 52 | 53 | % Discard cases when no score is generated 54 | :- not score(_). 55 | #show score/1. % Warning, Python will use this and consider that the edge cover is the score. 56 | -------------------------------------------------------------------------------- /powergrasp/asp/search-biclique.lp: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Find best biclique in input graph. 3 | % A biclique here can't be a star, so there is at least two elements in each set. 4 | % 5 | % initial version: 09/12/2014 J. Nicolas 6 | % revised version: 29/04/2015 L. Bourneuf 7 | % revised version: 08/07/2015 L. Bourneuf 8 | % revised version: 26/03/2018 J. Nicolas 9 | % 10 | % Constants: 11 | % - k: current step of treatment (first step is 1). 12 | % - lowerbound: the minimal cover to reach. 13 | % - upperbound: the maximal reachable cover. 14 | % - max_set_size: the maximal reachable size of a set. 15 | % Input: 16 | % - edge(X,Y): there exist a edge linking X and Y in cc (X=2. 31 | MS { newconcept(1,Y): inter(Hub,Y) } upperbound :- newconcept(2,Hub) ; min_size(MS). 32 | 33 | 34 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 | %%%%%% CONCEPT PROPERTIES %%%%%%%% 36 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 37 | % A star is a biclique with one powernode composed of only one node. 38 | star(2). 39 | 40 | biclique. 41 | -------------------------------------------------------------------------------- /powergrasp/asp/search-triplet.lp: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Find best triplet concept in input graph. 3 | % 4 | % Constants: 5 | % - k: current step of treatment (first step is 1). 6 | % - lowerbound: the minimal cover to reach. 7 | % - upperbound: the maximal reachable cover. 8 | % - max_set_size: the maximal reachable size of a set. 9 | % Input: 10 | % - edge(X,Y): there exist a edge linking X and Y in cc (X dict: 10 | return cli_parser(description).parse_args(args) 11 | 12 | def existant_file(filepath:str) -> str: 13 | """Argparse type, raising an error if given file does not exists""" 14 | if filepath is None: return None 15 | if not os.path.exists(filepath): 16 | raise argparse.ArgumentTypeError("file {} doesn't exists".format(filepath)) 17 | return filepath 18 | 19 | def writable_file(filepath:str) -> str: 20 | """Argparse type, raising an error if given file is not writable. 21 | Will delete the file ! 22 | 23 | """ 24 | try: 25 | with open(filepath, 'a') as fd: 26 | pass 27 | os.remove(filepath) 28 | return filepath 29 | except (PermissionError, IOError): 30 | raise argparse.ArgumentTypeError("file {} is not writable.".format(filepath)) 31 | 32 | 33 | def cli_parser(description:str) -> argparse.ArgumentParser: 34 | # main parser 35 | parser = argparse.ArgumentParser(description=description.strip()) 36 | 37 | 38 | parser.add_argument('infile', type=existant_file, nargs='?', 39 | help="Name of the input file to compress") 40 | parser.add_argument('outfile', nargs='?', 41 | type=writable_file, default='out.bbl', 42 | help="Name of the bubble file to produce") 43 | parser.add_argument('--config', '-c', action='store_true', dest='show_config', 44 | help="Print detected configuration, then quit") 45 | parser.add_argument('--recipe', '-r', default=None, type=str, 46 | help="Use content of given filename as a recipe") 47 | 48 | return parser 49 | -------------------------------------------------------------------------------- /powergrasp/constants.py: -------------------------------------------------------------------------------- 1 | """Some constants to tune the compression behavior. 2 | 3 | Final user may want to override it by writing in 'powergrasp.cfg' file in 4 | either JSON or INI format. 5 | 6 | """ 7 | import os 8 | import ast 9 | import json 10 | import itertools 11 | import configparser 12 | import multiprocessing 13 | from collections import ChainMap 14 | from . import utils 15 | 16 | # Default values 17 | constants = { 18 | # Run some integrity tests at some points. May slow the compression a lot. 19 | 'TEST_INTEGRITY': True, 20 | 21 | # Show main steps of the compression. 22 | 'SHOW_STORY': True, 23 | 24 | # Show motifs transformation into powergraph. 25 | 'SHOW_MOTIF_HANDLING': False, 26 | 27 | # Timers. 28 | 'TIMERS': True, 29 | 30 | # Statistics file to write during compression. 31 | 'STATISTIC_FILE': None, 32 | 33 | # Connected components statistics file to write at the end of each cc. 34 | 'CC_STATISTIC_FILE': None, 35 | 36 | # Compute statistics/metrics over all connected components. 37 | 'GLOBAL_STATISTICS': True, 38 | 39 | # Include some statistics in output bubble. 40 | 'BUBBLE_WITH_STATISTICS': True, 41 | 42 | # Generate and save a bubble representation of the graph at each step. 43 | 'BUBBLE_FOR_EACH_STEP': False, 44 | 45 | # Keep simple edges in output. 46 | 'BUBBLE_WITH_SIMPLE_EDGES': True, 47 | 48 | # Prefix to add to all (power)nodes names in output. 49 | 'OUTPUT_NODE_PREFIX': '', 50 | 51 | # Show full trace of the compression. Useful for debugging. 52 | 'SHOW_DEBUG': False, 53 | 54 | # Recover covered edges from ASP. If falsy, will ask motif searcher to compute the edges, which may be quicker. 55 | 'COVERED_EDGES_FROM_ASP': False, 56 | 57 | # Nodes and sets are optional in the output bubble. 58 | 'BUBBLE_WITH_NODES': True, 59 | 'BUBBLE_WITH_SETS': True, 60 | 61 | # Put each connected component in a dedicated powernode. 62 | 'BUBBLE_EMBEDS_CC': False, 63 | 64 | # Edges in bubble are associated to a factor 65 | 'BUBBLE_POWEREDGE_FACTOR': '1.0', 66 | 'BUBBLE_EDGE_FACTOR': '1.0', 67 | 68 | # When possible, delete the quotes around identifiers in the bubble. May lead to node name collision. 69 | 'BUBBLE_SIMPLIFY_QUOTES': True, 70 | 71 | # Change them according to config file 72 | 'CONFIG_FILE': 'powergrasp.cfg', 73 | 74 | # Search for multiple motif in a single search. Accelerate the solving for graph with lots of equivalent motifs. 75 | 'MULTISHOT_MOTIF_SEARCH': True, 76 | 77 | # Optimization on biclique lowerbound computation. Can be costly. Deactivate with 2. With value at n, up to n neighbors are considered. 78 | 'BICLIQUE_LOWERBOUND_MAXNEI': 2, 79 | 80 | # Arbitrary parameters to give to clingo (note that some, like multithreading or optmode, may already be set by other options). 81 | 'CLINGO_OPTIONS': {}, 82 | 83 | # Number of CPU available to clingo (or a string like '2,join' or '48,compete'), or 0 for autodetect number of CPU. 84 | 'CLINGO_MULTITHREADING': 1, 85 | 86 | # Do not search for cliques 87 | 'ONLY_BICLIQUES': False, 88 | 89 | # Two different motifs for stars and bicliques, so the work of biclique is lighter. 90 | 'USE_STAR_MOTIF': True, 91 | 92 | # Use quasibicliques instead of cliques. 93 | 'QUASIBICLIQUES': False, 94 | 95 | # Search for triplets. 96 | 'TRIPLETS': False, 97 | 98 | # Use only triplet motifs. 99 | 'ONLY_TRIPLETS': False, 100 | 101 | # Mu is the value for constraints for quasibicliques. 102 | 'QUASIBICLIQUE_MU': 2, 103 | 104 | # When a choice is given, prefer memory over CPU. 105 | 'OPTIMIZE_FOR_MEMORY': False, 106 | 107 | # If set, will keep nodes connected to nothing. Else, will discard them. 108 | 'KEEP_SINGLE_NODES': True, 109 | 110 | # Ignore edges dynamically determined as impossible to compress. 111 | 'GRAPH_FILTERING': True, 112 | 113 | # Perform the search for motifs in different process instead of sequentially. 114 | 'PARALLEL_MOTIF_SEARCH': False, 115 | 116 | # Number of processes to work on connected components. Zero to get one per cc. One to deactivate. 117 | 'PARALLEL_CC_COMPRESSION': 1, 118 | 119 | # Define in which order the motifs are tested. 120 | 'MOTIF_TYPE_ORDER': 'star,clique,non-star-biclique,quasi-biclique,biclique,triplet', 121 | 122 | # TODO Detect and postpone compression of terminal tree subgraphs 123 | # 'TERMINAL_TREES_POSTPONING': True, 124 | # TODO Detect, delete and restore bridges 125 | # 'BRIDGES_CUT': True, 126 | # TODO Detect and if available run specialized compression routine for: trees, triangle-free graphs, cactii. 127 | # Will not do anything on a graph that does not belong to those classes. 128 | # 'SPECIAL_CASES_DETECTION': True, 129 | } 130 | 131 | _derived_constants = { 132 | 'KEEP_NX_GRAPH': lambda c: c['GRAPH_FILTERING'], 133 | } 134 | 135 | 136 | def make_key(key:str) -> str: 137 | """Return the well formed key for constants dictionary""" 138 | return key.upper().replace(' ', '_') 139 | 140 | def make_value_from_ini(found_key:str, real_key:str, section, 141 | config:configparser.ConfigParser): 142 | """Return the int, str, dict, float or tuple equivalent to value 143 | found for given section and key. 144 | 145 | """ 146 | assert real_key in constants, f"{real_key} key found in config file is unexpected" 147 | assert section in config 148 | assert found_key in config[section], (config[section], found_key) 149 | default = constants[real_key] 150 | if isinstance(default, bool): 151 | return config.getboolean(section, found_key) 152 | elif isinstance(default, type(None)): 153 | try: 154 | return ast.literal_eval(config[section][found_key]) 155 | except ValueError as err: # it's not a python literal, so it's a string 156 | return config[section][found_key] 157 | elif isinstance(default, (int, float, tuple, list, dict, set, frozenset)): 158 | value = config[section][found_key] or '""' # cast empty value to empty string 159 | try: 160 | return type(default)(ast.literal_eval(value)) 161 | except ValueError as err: # it's not a python literal, so it's a string 162 | return config[section][found_key] 163 | elif isinstance(default, str): 164 | return config[section][found_key] 165 | else: 166 | raise ValueError("Non-handled option type {} for field {}" 167 | "".format(type(default), real_key)) 168 | 169 | def open_config_file(fname:str) -> dict: 170 | """Try reading file in INI, and if it do not works, try JSON""" 171 | try: 172 | # read file, take all available sections 173 | config = configparser.ConfigParser() 174 | config.read(fname) 175 | if config.sections(): 176 | return { 177 | key: make_value_from_ini(found_key, key, section, config) 178 | for section in config.sections() 179 | for found_key, key in map(lambda k:(k, make_key(k)), config[section]) 180 | } 181 | else: 182 | print('ERROR input config do not have any section.') 183 | except configparser.MissingSectionHeaderError as err: 184 | ini_err = err.args[0] 185 | try: 186 | with open(fname) as fd: 187 | return {make_key(k): v for k, v in json.load(fd).items()} 188 | except json.decoder.JSONDecodeError as err: 189 | json_err = err.args[0] 190 | print("ERROR input config file is not a valid json, nor a valid ini." 191 | "\nINI error: {}\nJSON error: {}".format(ini_err, json_err)) 192 | 193 | 194 | try: 195 | cfg = open_config_file(constants['CONFIG_FILE']) 196 | except FileNotFoundError: 197 | cfg = None 198 | if cfg: 199 | for field, value in cfg.items(): 200 | if field in constants: 201 | constants[field] = value 202 | elif constants['SHOW_STORY'] or constants['SHOW_DEBUG']: 203 | raise ValueError("field '{}' is not a valid field for configuration." 204 | "".format(field)) 205 | if constants['SHOW_STORY'] or constants['SHOW_DEBUG']: 206 | print('INFO: config file {} loaded.'.format(constants['CONFIG_FILE'])) 207 | elif constants['SHOW_STORY'] or constants['SHOW_DEBUG']: 208 | print("INFO no config file") 209 | 210 | 211 | def _convert_parallel_mode_option(value:str or int) -> str: 212 | """Return the option to give to clingo to handle given number of CPU. 213 | 214 | >>> _convert_parallel_mode_option(0) 215 | ' --parallel-mode=4' 216 | >>> _convert_parallel_mode_option(1) 217 | '' 218 | >>> _convert_parallel_mode_option('2') 219 | ' --parallel-mode=2' 220 | >>> _convert_parallel_mode_option(' 2') 221 | ' --parallel-mode=2' 222 | >>> _convert_parallel_mode_option('0,split') 223 | ' --parallel-mode=4,split' 224 | >>> _convert_parallel_mode_option("'0,split'") 225 | ' --parallel-mode=4,split' 226 | >>> _convert_parallel_mode_option('"0,split"') 227 | ' --parallel-mode=4,split' 228 | 229 | """ 230 | if isinstance(value, str): 231 | value = value.strip(' "\'\t\n') 232 | if value.isnumeric(): 233 | return str(_convert_parallel_mode_option(int(value))) 234 | elif value and value.startswith('0'): 235 | if value[1:] not in {',compete', ',split'}: 236 | raise ValueError("Multithreading option value is not valid: {}" 237 | "".format(value)) 238 | nb_cpu = str(multiprocessing.cpu_count()) 239 | return _convert_parallel_mode_option(nb_cpu + value.lstrip('0')) 240 | elif value: 241 | return ' --parallel-mode=' + value 242 | elif value == 0: 243 | return _convert_parallel_mode_option(multiprocessing.cpu_count()) 244 | elif value > 1: 245 | return ' --parallel-mode=' + str(value) 246 | return '' 247 | 248 | 249 | def _convert_clingo_options(value:dict or str) -> dict: 250 | """Return a map from motif name to clingo options.""" 251 | # NB: can't access MotifSearchers subclass at this point, since constants 252 | # are computed at import time. We therefore can't verify the keys of the dict. 253 | # convert string to dict 254 | if isinstance(value, str): 255 | value = {None: value} 256 | # validate and return the dict 257 | value = {None if motif is None else motif.lower().replace(' ', '-').replace('_', '-'): options 258 | for motif, options in value.items()} 259 | value.setdefault(None, '') 260 | return value 261 | 262 | 263 | def _convert_motif_type_order(value:str) -> callable: 264 | """Return a function returning sorted searchers according to the given value. 265 | 266 | For instance, if input is 'worst-upperbound-first', the function returned 267 | will sort input searchers according to their upperbound, smallest first. 268 | 269 | """ 270 | error = lambda m: ValueError("Invalid value for option MOTIF TYPE ORDER: {} ({})".format(value, m)) 271 | value = value.lower().replace(' ', '-').replace('_', '-') 272 | if ',' in value: 273 | values = (val for val in map(str.strip, value.split(',')) if val) 274 | order = {name: idx for idx, name in enumerate(values)} 275 | def ordered(searchers, *, order=order) -> iter: 276 | """Yield given searchers according to their priority""" 277 | return sorted(searchers, key=lambda s: order[s.name]) 278 | elif '-' in value: 279 | which, bound, where = value = value.split('-') 280 | greatests = {'greatest', 'biggest'} 281 | smallests = {'worst', 'smallest'} 282 | if len(value) != 3: 283 | raise error("{} groups instead of 3, like 'greatest-lowerbound-first'".format(len(value))) 284 | if which not in greatests | smallests: 285 | raise error("the which value must be something like worst or greatest".format(len(value))) 286 | reverse = (where == 'first') != (which in smallests) 287 | if bound == 'lowerbound': 288 | key = lambda s: s.lowerbound 289 | elif bound == 'upperbound': 290 | key = lambda s: s.upperbound 291 | else: 292 | raise error("the bound value must be upperbound or lowerbound".format(len(value))) 293 | def ordered(searchers, *, reverse=reverse, key=key) -> iter: 294 | return sorted(searchers, reverse=reverse, key=key) 295 | elif value == 'random': # funny, but not really useful 296 | def ordered(searchers) -> iter: 297 | import random 298 | searchers = list(searchers) 299 | random.shuffle(searchers) 300 | return searchers 301 | else: 302 | raise error("not a list of elements or groups, like 'star,clique,non-star-biclique,biclique' or 'greatest-lowerbound-first'") 303 | return ordered 304 | 305 | def _convert_erased_file(fname:str) -> str: 306 | """A type to give to convertion, where value is a file to erase.""" 307 | if fname is not None: 308 | with open(fname, 'w') as fd: 309 | pass # just erase it 310 | return fname # conserve it untouched 311 | 312 | 313 | # Apply the value convertion, if any. 314 | _CONVERTIONS = { 315 | 'CLINGO_MULTITHREADING': _convert_parallel_mode_option, 316 | 'BICLIQUE_LOWERBOUND_MAXNEI': int, 317 | 'CLINGO_OPTIONS': _convert_clingo_options, 318 | 'MOTIF_TYPE_ORDER': _convert_motif_type_order, 319 | 'CC_STATISTIC_FILE': _convert_erased_file, 320 | 'COMPRESSION_STATISTIC_FILE': _convert_erased_file, 321 | 'STATISTIC_FILE': _convert_erased_file, 322 | } 323 | constants = {f: _CONVERTIONS.get(f, lambda x:x)(v) for f, v in constants.items()} 324 | # add the derived ones 325 | constants.update({ 326 | field: make_value(constants) 327 | for field, make_value in _derived_constants.items() 328 | }) 329 | 330 | # verifications about clingo options 331 | if constants['CLINGO_MULTITHREADING']: 332 | for motif, options in constants['CLINGO_OPTIONS'].items(): 333 | if '--parallel-mode=' in options: 334 | raise ValueError("Invalid option value: --parallel-mode given by both" 335 | " CLINGO_OPTIONS ({}) and CLINGO_MULTITHREADING ({})." 336 | "".format(options, constants['CLINGO_MULTITHREADING'])) 337 | 338 | 339 | # Put them in global access 340 | globals().update(constants) 341 | 342 | 343 | def print_config(): 344 | """Print configuration in stdout""" 345 | # name_width = max(len(name) for name, _ in uplets) 346 | # value_width = max(len(repr(value)) for _, value in uplets) 347 | uplets = sorted(tuple(OPTIONS_CATEGORIES.items())) 348 | name_width = max(len(name) for _, names in uplets for name in names) 349 | for category, options in uplets: 350 | print('[{}]'.format(category)) 351 | for option in options: 352 | value = repr(constants[option]).strip('"\'') 353 | option = option.lower().replace('_', ' ').ljust(name_width) 354 | print('{} = {}'.format(option, value)) 355 | print() 356 | 357 | 358 | 359 | OPTIONS_CATEGORIES = utils.reverse_dict({ 360 | 'TEST_INTEGRITY': 'debug', 361 | 'SHOW_STORY': 'debug', 362 | 'SHOW_MOTIF_HANDLING': 'debug', 363 | 'TIMERS': 'statistics', 364 | 'STATISTIC_FILE': 'statistics', 365 | 'CC_STATISTIC_FILE': 'statistics', 366 | 'GLOBAL_STATISTICS': 'statistics', 367 | 'BUBBLE_WITH_STATISTICS': 'statistics', 368 | 'BUBBLE_FOR_EACH_STEP': 'debug', 369 | 'BUBBLE_WITH_SIMPLE_EDGES': 'output', 370 | 'OUTPUT_NODE_PREFIX': 'output', 371 | 'SHOW_DEBUG': 'debug', 372 | 'COVERED_EDGES_FROM_ASP': 'optimization', 373 | 'BUBBLE_WITH_NODES': 'output', 374 | 'BUBBLE_WITH_SETS': 'output', 375 | 'BUBBLE_POWEREDGE_FACTOR': 'output', 376 | 'BUBBLE_EDGE_FACTOR': 'output', 377 | 'BUBBLE_EMBEDS_CC': 'output', 378 | 'BUBBLE_SIMPLIFY_QUOTES': 'input', 379 | 'CONFIG_FILE': 'input', 380 | 'MULTISHOT_MOTIF_SEARCH': 'optimization', 381 | 'BICLIQUE_LOWERBOUND_MAXNEI': 'optimization', 382 | 'CLINGO_OPTIONS': 'clingo', 383 | 'CLINGO_MULTITHREADING': 'clingo', 384 | 'USE_STAR_MOTIF': 'optimization', 385 | 'ONLY_BICLIQUES': 'output', 386 | 'QUASIBICLIQUES': 'output', 387 | 'QUASIBICLIQUE_MU': 'output', 388 | 'TRIPLETS': 'output', 389 | 'ONLY_TRIPLETS': 'output', 390 | 'OPTIMIZE_FOR_MEMORY': 'optimization', 391 | 'KEEP_SINGLE_NODES': 'output', 392 | 'KEEP_NX_GRAPH': 'optimization', 393 | 'GRAPH_FILTERING': 'optimization', 394 | 'PARALLEL_MOTIF_SEARCH': 'optimization', 395 | 'PARALLEL_CC_COMPRESSION': 'optimization', 396 | 'MOTIF_TYPE_ORDER': 'optimization', 397 | 398 | # 'TERMINAL_TREES_POSTPONING': 'optimization', 399 | # 'BRIDGES_CUT': 'optimization', 400 | # 'SPECIAL_CASES_DETECTION': 'optimization', 401 | }) 402 | categorized_options = frozenset(itertools.chain.from_iterable(OPTIONS_CATEGORIES.values())) 403 | assert all(option in constants for option in categorized_options) 404 | for constant in constants: 405 | if constant not in categorized_options: 406 | raise ValueError("Option {} has no category".format(constant)) 407 | -------------------------------------------------------------------------------- /powergrasp/edge_filtering.py: -------------------------------------------------------------------------------- 1 | """Routines implementing edge filtering on input graphs, 2 | knowing the bounds on the size of the motif to search in it. 3 | 4 | All routines follow the following interface: 5 | - arguments are the graph and the bounds 6 | - yield valid edges as pairs of nodes 7 | 8 | """ 9 | 10 | import networkx as nx 11 | 12 | 13 | def for_biclique(graph:nx.Graph, lowerbound:int, upperbound:int) -> [(str, str)]: 14 | """ 15 | Remove any edge that the product of its nodes degrees is inferior to lowerbound. 16 | """ 17 | def ok_to_go(edge:tuple) -> bool: 18 | one, two = edge 19 | degone, degtwo = map(graph.degree, edge) 20 | return degone * degtwo >= lowerbound 21 | for edge in graph.edges: 22 | if ok_to_go(edge): 23 | yield edge 24 | 25 | 26 | def for_star(graph:nx.Graph, lowerbound:int, upperbound:int) -> [(str, str)]: 27 | """ 28 | """ 29 | def ok_to_go(edge:tuple) -> bool: 30 | one, two = edge 31 | degone, degtwo = map(graph.degree, edge) 32 | return not all(( 33 | degone < lowerbound, 34 | degtwo < lowerbound, 35 | )) 36 | for edge in graph.edges: 37 | if ok_to_go(edge): 38 | yield edge 39 | 40 | 41 | def for_clique(graph:nx.Graph, lowerbound:int, upperbound:int) -> [(str, str)]: 42 | """ 43 | Remove an edge when one participating node has a clustering coefficient equal to 0. 44 | """ 45 | clusterings = {} # node -> clustering coefficient 46 | def clustering_of(node:str) -> float: 47 | if node in clusterings: 48 | return clusterings[node] 49 | else: 50 | return clusterings.setdefault(node, nx.clustering(graph, node)) 51 | for edge in graph.edges: 52 | if any(clustering_of(node) > 0. for node in edge): 53 | yield edge 54 | -------------------------------------------------------------------------------- /powergrasp/metrics.py: -------------------------------------------------------------------------------- 1 | def conversion_rate(initial_edge, final_edge, poweredge, powernode): 2 | """Compute conversion rate""" 3 | try: 4 | edge = initial_edge 5 | poweredge = final_edge + poweredge 6 | return (edge - poweredge) / powernode 7 | except ZeroDivisionError: 8 | return 1. 9 | 10 | def edge_reduction(initial_edge, final_edge, poweredge, _): 11 | """Compute edge reduction (percentage)""" 12 | try: 13 | edge = initial_edge 14 | poweredge = final_edge + poweredge 15 | return ((edge - poweredge) / edge) * 100 16 | except ZeroDivisionError: 17 | return 100. 18 | 19 | def compression_ratio(initial_edge, final_edge, poweredge, _): 20 | """Compute data compression ratio""" 21 | try: 22 | return initial_edge / (final_edge + poweredge) 23 | except ZeroDivisionError: 24 | return 1. 25 | 26 | 27 | def compression_metrics(initial_edge, final_edge, poweredge, powernode) -> [(str, float)]: 28 | """Yield pairs (name, value) describing measures and their value. 29 | 30 | initial_edge -- number of edge in initial graph 31 | final_edge -- number of (non power) edge in final graph 32 | poweredge -- number of poweredge in final graph 33 | powernode -- number of powernode in final graph 34 | 35 | """ 36 | payload = initial_edge, final_edge, poweredge, powernode 37 | for func in (conversion_rate, edge_reduction, compression_ratio): 38 | yield func.__name__.replace('_', ' '), func(*payload) 39 | -------------------------------------------------------------------------------- /powergrasp/motif.py: -------------------------------------------------------------------------------- 1 | 2 | from powergrasp.constants import TEST_INTEGRITY, SHOW_DEBUG, COVERED_EDGES_FROM_ASP 3 | 4 | 5 | class Motif: 6 | """A motif found by a motif searcher. 7 | 8 | The motif is a proxy to the ASP model, with a large set of properties 9 | that Graph and Searchers will use to determine the Motif effect 10 | on the Graph. 11 | 12 | """ 13 | def __init__(self, typename:str, atoms:dict, maximal:bool, step:int, searcher:object): 14 | self.typename, self.atoms, self.ismaximal, self.step = str(typename), dict(atoms), bool(maximal), int(step) 15 | self.step_modifier = 0 16 | self._searcher = searcher 17 | if SHOW_DEBUG: 18 | from pprint import pprint 19 | print('ATOMS FOR MOTIF {}:'.format(typename)) 20 | pprint(self.atoms) 21 | self._score = None 22 | 23 | 24 | @property 25 | def name(self) -> str: return self.typename 26 | @property 27 | def uid(self) -> int: return self.step + self.step_modifier 28 | @property 29 | def type(self): return self._searcher 30 | 31 | 32 | @property 33 | def score(self) -> int: 34 | if self._score is None: 35 | self._score = self._compute_score() 36 | return self._score 37 | @property 38 | def edge_cover(self) -> int: 39 | return self.score 40 | 41 | def _compute_score(self) -> int: 42 | """Compute and return the score of this motif""" 43 | score_atoms = tuple(self.atoms.get('score', ())) 44 | if not score_atoms: 45 | raise ASPModelError("No atom `score` found") 46 | if len(score_atoms) > 1: 47 | raise ASPModelError("Multiple atom `score` found: {}".format(len(score_atoms))) 48 | score_atom_args = score_atoms[0] 49 | if len(score_atom_args) != 1: 50 | raise ASPModelError("Atom `score` got a non-valid number of arguments: {}".format(score_atom_args)) 51 | score = score_atom_args[0] 52 | if not isinstance(score, int): 53 | raise ASPModelError("Atom `score` got a non-int argument of type {}: {}".format(type(score), score)) 54 | assert isinstance(score, int) 55 | return score 56 | 57 | def increase_step(self, step_diff:int): 58 | """Increase internally the step of self""" 59 | self.step_modifier += int(step_diff) 60 | 61 | @property 62 | def new_nodes(self) -> iter: 63 | yield from (node for numset, node in self.atoms.get('new_powernode', ())) 64 | yield from self.stars 65 | @property 66 | def new_powernodes(self) -> iter: 67 | yield from self.atoms.get('new_powernode', ()) 68 | @property 69 | def powernodes(self) -> iter: 70 | _ = lambda s: s + (self.step_modifier if s == self.step else 0) 71 | yield from ( 72 | (_(step), numset) for step, numset in self.atoms.get('powernode', ()) 73 | ) 74 | @property 75 | def stars(self) -> iter: 76 | yield from (args[0] for args in self.atoms.get('star', ())) 77 | @property 78 | def new_poweredge(self) -> iter: 79 | _ = lambda s: s + (self.step_modifier if s == self.step else 0) 80 | for args in self.atoms.get('poweredge', ()): 81 | if len(args) == 4: 82 | step_a, set_a, step_b, set_b = args 83 | yield (_(step_a), set_a), (_(step_b), set_b) 84 | elif len(args) == 3: 85 | step_a, set_a, node = args 86 | yield (_(step_a), set_a), node 87 | @property 88 | def hierachy_added(self) -> iter: 89 | _ = lambda s: s + (self.step_modifier if s == self.step else 0) 90 | yield from ( 91 | (_(step1), numset, _(step2), numset2) 92 | for step1, numset, step2, numset2 93 | in self.atoms.get('hierarchy_add', ())) 94 | @property 95 | def hierachy_removed(self) -> iter: 96 | _ = lambda s: s + (self.step_modifier if s == self.step else 0) 97 | yield from ( 98 | (_(step1), numset, _(step2), numset2) 99 | for step1, numset, step2, numset2 100 | in self.atoms.get('hierarchy_remove', ())) 101 | 102 | 103 | def edges_covered(self, sets:[frozenset]=None) -> iter: 104 | """If sets are given, the computation of edges covered by the motif 105 | is delegated to the searcher object. 106 | 107 | This allow to avoid a costly output from ASP. 108 | 109 | """ 110 | if sets: # give that to the searcher 111 | yield from frozenset(self.type.covered_edges(tuple(sets))) 112 | else: # ASP provide us with the data 113 | yield from map(frozenset, self.atoms.get('covered_edge', ())) 114 | -------------------------------------------------------------------------------- /powergrasp/motif_batch.py: -------------------------------------------------------------------------------- 1 | """Batch of concurrent motif on a graph. 2 | 3 | Offers an API useful for compression routine (access to score), 4 | internal integrity test (equivalency of all contained motifs), 5 | and non-overlapping subset selection. 6 | 7 | """ 8 | 9 | from itertools import islice 10 | from powergrasp.motif import Motif 11 | from powergrasp.constants import TEST_INTEGRITY 12 | 13 | 14 | class MotifBatch: 15 | """Container of Motif""" 16 | 17 | def __init__(self, motifs:iter): 18 | self.motifs = tuple(motifs) 19 | self.score = self.motifs[0].score if self.motifs else None 20 | if TEST_INTEGRITY and self.score: 21 | scores = set(m.score for m in self.motifs) 22 | assert len(scores) == 1, "Multiple different scores in motifs: " + str(scores) 23 | 24 | def __bool__(self) -> bool: 25 | return bool(self.motifs) 26 | 27 | @property 28 | def empty(self) -> bool: 29 | return not self 30 | @property 31 | def name(self) -> str: return self.motifs[0].typename 32 | @property 33 | def ismaximal(self) -> bool: return self.motifs[0].ismaximal 34 | @property 35 | def count(self) -> int: return len(self.motifs) 36 | 37 | 38 | def non_overlapping_subset(self) -> iter: 39 | """Yield motifs contained in self that are non overlapping between them. 40 | 41 | These motifs can all be compressed at the same time because they 42 | do not share any node. 43 | 44 | """ 45 | if self.empty: return # nothing to yield 46 | motifs = iter(self.motifs) 47 | first = next(motifs) 48 | nodes = frozenset(first.new_nodes) 49 | yield first 50 | for motif in motifs: 51 | motif_nodes = frozenset(motif.new_nodes) 52 | if motif_nodes.isdisjoint(nodes): 53 | nodes |= motif_nodes 54 | yield motif 55 | -------------------------------------------------------------------------------- /powergrasp/recipe.py: -------------------------------------------------------------------------------- 1 | """Definition of a Recipe. 2 | 3 | """ 4 | 5 | import itertools 6 | 7 | 8 | class RecipeError(ValueError): 9 | pass 10 | 11 | 12 | class Recipe: 13 | RecipeError = RecipeError 14 | 15 | """Basically, a list of RecipeEntry""" 16 | 17 | def __init__(self, lines:iter): 18 | self._lines = tuple(RecipeEntry(*line) for line in lines) 19 | 20 | def __iter__(self): 21 | yield from self._lines 22 | 23 | def __len__(self): 24 | return len(self._lines) 25 | 26 | def __getitem__(self, idx): 27 | return self._lines[idx] 28 | 29 | def __str__(self): 30 | nb_entry = len(self._lines) 31 | return f" 1 else ''}>" 32 | 33 | def works_on(self, graph) -> bool: 34 | "True if the graph has a node referenced in self." 35 | for entry in self: 36 | if f'"{entry.one_node}"' in graph.nodes: 37 | return True 38 | return False 39 | 40 | 41 | @staticmethod 42 | def from_(obj:object) -> object: 43 | "Build a Recipe instance from a filename, its raw data, or an iterable of lines" 44 | if isinstance(obj, Recipe): 45 | return obj 46 | if isinstance(obj, str): 47 | if '\t' in obj: 48 | return Recipe.from_string(obj) 49 | # must be a file 50 | return Recipe.from_file(obj) 51 | return Recipe.from_lines(obj) 52 | 53 | @staticmethod 54 | def from_string(string:str) -> object: 55 | return Recipe.from_lines(string.splitlines(False)) 56 | 57 | @staticmethod 58 | def from_lines(lines:[str]) -> object: 59 | """Build a Recipe instance from given file""" 60 | def motif_from_line(line:str) -> (str, [str], [str]) or None: 61 | if not line or line.count('\t') != 2: 62 | return None # not a Motif ; it needs to be looked by itself 63 | typemotif, seta, setb = line.split('\t') 64 | return set(typemotif.split(',')), set(seta.split(' ')), set(setb.split(' ')) 65 | 66 | motifs = tuple(motif for motif in 67 | map(motif_from_line, map(str.strip, lines)) if motif) 68 | return Recipe( 69 | (typemotifs, seta, setb) for typemotifs, seta, setb in motifs 70 | ) 71 | 72 | @staticmethod 73 | def from_file(fname:str) -> object: 74 | """Build a Recipe instance from given file""" 75 | if fname is None: return Recipe(()) 76 | with open(fname) as fd: 77 | return Recipe.from_lines(fd) 78 | 79 | 80 | class RecipeEntry: 81 | RecipeError = RecipeError 82 | def __init__(self, typenames:set, seta:set, setb:set): 83 | self.typenames = frozenset(typenames) 84 | self.seta = frozenset(seta) 85 | self.setb = frozenset(setb) 86 | if self.isextendable and self.isbreakable: 87 | raise NotImplementedError("Recipe is both extendable (open/primer option)" 88 | " and breakable.") 89 | 90 | @property 91 | def isextendable(self) -> bool: 92 | return bool({'open', 'primer'} & self.typenames) 93 | @property 94 | def isbreakable(self) -> bool: 95 | return 'breakable' in self.typenames 96 | @property 97 | def islast(self) -> bool: 98 | return 'last' in self.typenames 99 | @property 100 | def isrequired(self) -> bool: 101 | return 'optional' not in self.typenames 102 | @property 103 | def one_node(self) -> str: 104 | """Return one node found in sets""" 105 | return next(iter(self.seta), None) or next(iter(self.setb)) 106 | @property 107 | def is_clique(self) -> str: 108 | """True if describes a clique""" 109 | return 'clique' in self.typenames 110 | @property 111 | def is_star(self) -> bool: 112 | """True if describes a star""" 113 | return 'star' in self.typenames or ('biclique' in self.typenames and any(len(s) == 1 for s in self.sets)) 114 | 115 | @property 116 | def covered_edges(self) -> {frozenset((str, str))}: 117 | "Return edges covered by the recipe" 118 | quoted = lambda a: '"' + a + '"' 119 | return frozenset(map(frozenset, itertools.product(map(quoted, self.seta), map(quoted, self.setb)))) 120 | 121 | def __iter__(self): 122 | return iter((self.typenames, self.seta, self.setb)) 123 | 124 | def __str__(self): 125 | return f"" 126 | 127 | def as_asp(self, is_star:bool): 128 | """Return ASP atoms translating the given recipe line""" 129 | typenames, seta, setb = self 130 | if min(setb) < min(seta): # minimal element must be in seta 131 | setb, seta = seta, setb 132 | if is_star and len(seta) == 1: # if it's a star, then single element must be in setb 133 | setb, seta = seta, setb 134 | return '\n'.join(( 135 | ' '.join(f'newconcept(1,"{element}").' for element in seta), 136 | '' if self.is_clique else ' '.join(f'newconcept(2,"{element}").' for element in setb), 137 | # '|'.join(typenames) + '.' 138 | )) 139 | 140 | @property 141 | def sets(self) -> [set]: 142 | """Return the sets composing the motif described by the entry""" 143 | return frozenset([self.seta]) if self.is_clique else frozenset([self.seta, self.setb]) 144 | 145 | def accept(self, searcher): 146 | if searcher.name == 'star': 147 | return self.is_star 148 | return searcher.motif_name in self.typenames 149 | -------------------------------------------------------------------------------- /powergrasp/routines.py: -------------------------------------------------------------------------------- 1 | """Definition of high level functions operating the compression. 2 | 3 | """ 4 | 5 | import csv 6 | from .searchers import CliqueSearcher, BicliqueSearcher, StarSearcher, NonStarBicliqueSearcher, QuasiBicliqueSearcher, TripletSearcher 7 | from .utils import get_time 8 | from .graph import Graph 9 | from .recipe import Recipe 10 | from . import constants as const 11 | from .constants import MULTISHOT_MOTIF_SEARCH, BUBBLE_FOR_EACH_STEP, TIMERS, SHOW_STORY, SHOW_DEBUG, STATISTIC_FILE, USE_STAR_MOTIF, ONLY_BICLIQUES, QUASIBICLIQUES, TRIPLETS, ONLY_TRIPLETS 12 | from .motif_batch import MotifBatch 13 | from multiprocessing.dummy import Pool as ThreadPool # dummy here to use the threading backend, not process 14 | from multiprocessing import Pool as ProcessPool 15 | 16 | 17 | if TIMERS and STATISTIC_FILE: 18 | # function to fill the file during compression 19 | def save_stats(*args): 20 | """Fill statistic file with given data""" 21 | with open(STATISTIC_FILE, 'a') as fd: 22 | fd.write(','.join(map(str, args)) + '\n') 23 | 24 | 25 | def search_best_motifs_sequentially(searchers, step, recipe) -> MotifBatch: 26 | """Return a MotifBatch instance containing the best motifs 27 | found by given searchers.""" 28 | score_to_beat = 0 29 | best_motifs, best_motifs_score = None, 0 30 | ordered_searchers = const.MOTIF_TYPE_ORDER(searchers) 31 | for searcher in ordered_searchers: 32 | if recipe and not recipe.accept(searcher): 33 | print(f'Recipe {recipe} cannot be fulfilled with searcher {searcher.name}') 34 | continue 35 | motifs = MotifBatch(searcher.search(step, score_to_beat, recipe=recipe)) 36 | if motifs: 37 | searcher.on_new_found_motif(motifs) 38 | if motifs.score > best_motifs_score: 39 | best_motifs, best_motifs_score = motifs, motifs.score 40 | score_to_beat = best_motifs_score 41 | return best_motifs 42 | 43 | def search_best_motifs_in_parallel(searchers, step, recipe) -> MotifBatch: 44 | """Return a MotifBatch instance containing the best motifs 45 | found by given searchers.""" 46 | with ThreadPool(len(searchers)) as pool: 47 | founds = pool.starmap(search_best_motifs_sequentially, (([s], step, recipe) for s in searchers)) 48 | return max(founds, key=lambda f: 0 if f is None else f.score) 49 | 50 | if const.PARALLEL_MOTIF_SEARCH: 51 | search_best_motifs = search_best_motifs_in_parallel 52 | else: 53 | search_best_motifs = search_best_motifs_sequentially 54 | 55 | 56 | def create_searchers(graph): 57 | """Return a list of searchers on given graph, depending on the global parameters""" 58 | if ONLY_TRIPLETS: 59 | return [TripletSearcher(graph)] 60 | searchers = [] if ONLY_BICLIQUES else [CliqueSearcher(graph)] 61 | if USE_STAR_MOTIF and QUASIBICLIQUES: 62 | # searchers.extend([QuasiBicliqueSearcher(graph), BicliqueSearcher(graph), StarSearcher(graph)]) 63 | searchers.extend([QuasiBicliqueSearcher(graph), StarSearcher(graph)]) 64 | elif USE_STAR_MOTIF: 65 | searchers.extend([NonStarBicliqueSearcher(graph), StarSearcher(graph)]) 66 | elif QUASIBICLIQUES: 67 | searchers.extend([QuasiBicliqueSearcher(graph), BicliqueSearcher(graph)]) 68 | else: 69 | searchers.append(BicliqueSearcher(graph)) 70 | if TRIPLETS: 71 | searchers.append(TripletSearcher(graph)) 72 | return searchers 73 | 74 | 75 | def compress(graph:Graph, *, cc_idx=None, recipe:[Recipe]=None) -> [str]: 76 | """Yield bubble lines found in graph""" 77 | if TIMERS: 78 | timer_start = get_time() 79 | timer_last = timer_start 80 | searchers = create_searchers(graph) 81 | if SHOW_STORY: 82 | print('INFO searchers: ' + ', '.join(s.name for s in searchers)) 83 | print(f"INFO recipe: {recipe}") 84 | recipe_lines, recipe_line, recipe_completed = iter(recipe or ()), None, False 85 | step = 0 86 | complete_compression = False 87 | while True: 88 | if recipe_line and recipe_line.isbreakable and not recipe_completed: 89 | pass # reuse the same recipe line 90 | else: # everything normal 91 | recipe_line = next(recipe_lines, None) 92 | recipe_completed = False 93 | if (SHOW_STORY and recipe_line) or SHOW_DEBUG: print('INFO recipe:', recipe_line) 94 | step += 1 95 | try: 96 | best_motifs = search_best_motifs(searchers, step, recipe=recipe_line) 97 | except KeyboardInterrupt: 98 | print('WARNING interrupted search. Graph compression aborted. Output will be written.') 99 | best_motifs = None 100 | break 101 | if best_motifs: # let's compress it 102 | step += graph.compress_all(best_motifs.non_overlapping_subset()) 103 | for searcher in searchers: 104 | searcher.on_new_compressed_motif(best_motifs) 105 | if BUBBLE_FOR_EACH_STEP: 106 | graph.output('out/out_k{}_s{}.bbl'.format(step, best_motif.score)) 107 | if SHOW_STORY: 108 | print('INFO {} {} motif of score {} compressed'.format(best_motifs.count, best_motifs.name, best_motifs.score)) 109 | if TIMERS: 110 | now = get_time() 111 | timers = round(now - timer_start, 2), round(now - timer_last, 2) 112 | if SHOW_STORY: 113 | print("TIMER since start: {}s\t\tsince last motif: {}s" 114 | "".format(*timers)) 115 | timer_last = now 116 | for searcher in searchers: # timer per motif search 117 | timers = timers + ('{}:{}'.format(searcher.name, round(searcher.last_search_time, 2)) if searcher.last_search_time is not None else 'none',) 118 | if STATISTIC_FILE: 119 | bounds = [ 120 | '{}:[{};{}]'.format(searcher.name, searcher.lowerbound, searcher.upperbound) 121 | for searcher in searchers 122 | ] 123 | if not TIMERS: 124 | timers = 'none', 'none' 125 | save_stats(cc_idx, *timers, best_motifs.name, best_motifs.score, *bounds) 126 | else: 127 | if recipe_line: # the recipe failed, or is optional 128 | recipe_completed = True 129 | if recipe_line.isbreakable: 130 | if SHOW_DEBUG: 131 | print(f"DEBUG breakable recipe {recipe_line} exhausted.") 132 | elif recipe_line.isrequired: 133 | raise recipe_line.RecipeError(f"Recipe {recipe_line} failed, but was necessary.") 134 | else: # it is optional 135 | if SHOW_STORY: 136 | print(f"INFO optional recipe {recipe_line} failed.") 137 | else: # no recipe, so it's a normal ending of compression 138 | complete_compression = True 139 | break # nothing to compress 140 | # finish compression if the recipe asks so (and is not an uncompleted breakable). 141 | if recipe_line and recipe_line.islast and not (recipe_line.isbreakable and not recipe_completed): 142 | break 143 | if TIMERS: 144 | timer_output = get_time() 145 | 146 | # write the bubble 147 | head_comment = '' 148 | if not complete_compression: 149 | head_comment = 'Warning: incomplete compression (stopped at step {})'.format(step) 150 | yield from graph.bubble_repr(head_comment=head_comment, given_uid=cc_idx) 151 | 152 | # timers 153 | if TIMERS: 154 | now = get_time() 155 | timers = round(now - timer_start, 2), round(now - timer_output, 2) 156 | if SHOW_STORY: 157 | print("TIMER since start: {}s\t\toutput generation: {}s" 158 | "".format(*timers)) 159 | 160 | # compute the statistics 161 | compression_statistics = tuple(graph.compression_metrics()) 162 | if cc_idx: 163 | compression_statistics = (('connected component', cc_idx), *compression_statistics) 164 | if TIMERS: 165 | compression_statistics = (*compression_statistics, ('time since start', timers[0])) 166 | # write the statistics where available 167 | if const.CC_STATISTIC_FILE and cc_idx: 168 | with open(const.CC_STATISTIC_FILE, 'a') as fd: 169 | csv.writer(fd).writerow(v for _, v in compression_statistics) 170 | if const.BUBBLE_WITH_STATISTICS: 171 | yield from _gen_metrics(compression_statistics) 172 | 173 | 174 | def compress_by_cc(fname:str, recipe_files:[str]=None) -> [str]: 175 | """Yield bubble lines from compression of each cc found in given filename 176 | 177 | recipe_files -- iterable of filenames or raw recipe, or Recipe objects 178 | 179 | """ 180 | if TIMERS and const.BUBBLE_WITH_STATISTICS: 181 | timer = get_time() 182 | if recipe_files: 183 | if SHOW_STORY: 184 | print('INFO recipe files:', recipe_files) 185 | recipe_files = tuple([recipe_files] if isinstance(recipe_files, str) else recipe_files) 186 | recipes = tuple(map(Recipe.from_, recipe_files)) 187 | def recipe_for(graph:Graph, recipes=recipes) -> Recipe: 188 | "Return the first recipe using a node found in given graph" 189 | for recipe in recipes: 190 | if recipe.works_on(graph): 191 | return recipe 192 | else: 193 | def recipe_for(*_, **__): return None # no recipe available 194 | 195 | graphs = enumerate(Graph.ccs_from_file(fname), start=1) 196 | stats = None 197 | if const.PARALLEL_CC_COMPRESSION == 1: # simple case, allowing for global stats 198 | for idx, graph in graphs: 199 | if idx > 1: yield '' 200 | yield '# CONNECTED COMPONENT {}'.format(idx) 201 | yield from compress(graph, cc_idx=idx, recipe=recipe_for(graph)) 202 | if const.GLOBAL_STATISTICS: 203 | stats = _build_global_stats(stats, graph.compression_metrics_data()) 204 | else: # many processes imply a more complex system 205 | nb_process = const.PARALLEL_CC_COMPRESSION 206 | if nb_process == 0: 207 | graphs = ((idx, gr, recipe_for(gr)) for idx, gr in graphs) 208 | graphs = tuple(graphs) # RIP memory 209 | nb_process = len(graphs) or 1 210 | with ProcessPool(nb_process) as pool: 211 | for lines, stats_data in pool.starmap(_func_on_graph, graphs): 212 | yield from lines 213 | if const.GLOBAL_STATISTICS: 214 | stats = _build_global_stats(stats, stats_data) 215 | 216 | # show global stats 217 | if stats is not None and const.BUBBLE_WITH_STATISTICS: 218 | yield '# TOTAL GRAPH METRICS' 219 | yield from _gen_metrics(Graph.compression_metrics_from_data(stats)) 220 | if TIMERS and const.BUBBLE_WITH_STATISTICS: 221 | yield '# total compression time: {}'.format(round(get_time() - timer, 2)) 222 | 223 | 224 | def _func_on_graph(idx, graph, recipe): 225 | """Function used by multiprocessing compression of cc. Needs to be global 226 | to be pickled.""" 227 | lines = ( 228 | '# CONNECTED COMPONENT {}'.format(idx), 229 | *compress(graph, cc_idx=idx, recipe=recipe) 230 | ) 231 | return lines, graph.compression_metrics_data() 232 | 233 | 234 | def _build_global_stats(prev:tuple, current:tuple): 235 | """Return the addition of previous and current statistics values""" 236 | if prev is None: 237 | return current 238 | return tuple(one + two for one, two in zip(prev, current)) 239 | 240 | 241 | def _gen_metrics(metrics:[(str, float)]) -> str: 242 | """Yield lines describing given iterable of metric and their value.""" 243 | metrics = tuple(metrics) 244 | metric_name_size = max((len(m) for m, _ in metrics)) 245 | for metric, value in metrics: 246 | if isinstance(value, float): value = round(value, 2) 247 | yield '# {}: {}'.format(metric.ljust(metric_name_size), value) 248 | -------------------------------------------------------------------------------- /powergrasp/utils.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | import math 4 | import time 5 | import phasme 6 | 7 | 8 | def get_time() -> float: return time.time() 9 | 10 | 11 | 12 | def maximal_clique_size(nb_edge:int) -> int: 13 | """Maximal number of nodes implied in a clique when there is given 14 | number of edges between neighbors of a node. 15 | 16 | nb_edge -- number of edges between neighbors of a node n 17 | return -- maximal number of node implied in a clique implying node n 18 | 19 | The number of edges covered by a clique of n nodes is given by function k: 20 | k(n) = n(n-1) / 2 21 | 22 | The contraposition of k, giving the number of nodes n in a clique of k(n) edges is: 23 | n = (1 + √(1+8*k(n))) / 2 24 | 25 | Proof: function k may be expressed as: 26 | n^2 - n - 2k(n) = 0 27 | The discriminant Δ = (-1)^2 - 4 * 1 * (-2k(n)) = 1 + 8k(n) 28 | Roots are (1±√Δ)/2, only the positive one is relevant (unless antimatter is involved), 29 | therefore root of k is (1 + √(1+8*k(n))) / 2 □ 30 | 31 | For any node n, the maximal clique MC implying node n is constitued of n 32 | and its neighbors having a link between them. 33 | An upperbound of that number of node is given by 34 | considering that neighbors link are optimally placed to create a clique. 35 | 36 | There is therefore, in the best case, NMC(n) nodes in the maximal 37 | clique implying n: 38 | NMC(n) = 1 + ⌊ (1 + √(1+8*v(n))) / 2 ⌋ 39 | 40 | With v(n) the number of edges between the neighbors of n. 41 | 42 | NMC(n) may then be used to compute the upperbound of clique search, 43 | by taking the maximal NMC(n) for all n of the graph in which a clique 44 | is searched. 45 | 46 | >>> maximal_clique_size(0) # when no edge between neighbors: the node and one neighbor make the clique 47 | 2 48 | >>> maximal_clique_size(1) # when 1 edge between neighbors of n, the maximal clique imply two neighbors and n 49 | 3 50 | >>> maximal_clique_size(2) # when 2 edges between neighbors of n, the maximal clique imply two neighbors and n 51 | 3 52 | >>> maximal_clique_size(3) 53 | 4 54 | >>> maximal_clique_size(4) 55 | 4 56 | >>> maximal_clique_size(5) 57 | 4 58 | >>> maximal_clique_size(6) 59 | 5 60 | 61 | """ 62 | return 1 + int((1 + math.sqrt(1 + 8 * nb_edge)) / 2) 63 | 64 | 65 | def quoted(string:str) -> str: 66 | """Return the given string, quoted, and with internal quotes escaped. 67 | 68 | Existing quotes will be escaped. 69 | 70 | >>> quoted('a') 71 | '"a"' 72 | >>> quoted('"a"') 73 | '"\\\\"a\\\\""' 74 | >>> quoted('"a') 75 | '"\\\\"a"' 76 | 77 | """ 78 | # space is here to allow the regex to match for the first char 79 | return '"' + re.sub(r'([^\\])"', r'\1\\"', ' ' + string)[1:] + '"' 80 | 81 | 82 | def unquoted(string:str) -> str: 83 | """Return the given string, unquoted. 84 | 85 | >>> unquoted('a') 86 | 'a' 87 | >>> unquoted('"a"') 88 | 'a' 89 | >>> unquoted('"a') 90 | '"a' 91 | 92 | """ 93 | if string[0] == '"' and string[-1] == '"': 94 | return string[1:-1] 95 | return string 96 | 97 | 98 | def normalized_name(string:str) -> str: 99 | """Return the normalized string, that consist of a quoted string 100 | with special characters replaced by their ord number. 101 | 102 | >>> normalized_name('a') 103 | '"a"' 104 | >>> normalized_name('A') 105 | '"A"' 106 | >>> normalized_name('"a"') 107 | '"a"' 108 | >>> normalized_name('"a') 109 | '"_c34_a"' 110 | 111 | """ 112 | return quoted(phasme.commons.fixed_name(unquoted(string))) 113 | 114 | 115 | def reverse_dict(indict:dict) -> dict: 116 | """Return a dict containing values of input dict as keys, 117 | and a set of associated keys as values. 118 | 119 | >>> reverse_dict({1: 2, 3: 2}) 120 | {2: {1, 3}} 121 | >>> reverse_dict({1: 2, 3: 4}) 122 | {2: {1}, 4: {3}} 123 | 124 | """ 125 | ret = {} 126 | for key, val in indict.items(): 127 | ret.setdefault(val, set()).add(key) 128 | return ret 129 | -------------------------------------------------------------------------------- /recipe: -------------------------------------------------------------------------------- 1 | biclique a1 a2 a3 a4 b1 b2 b3 b4 b5 b6 2 | biclique,breakable e3 e4 d1 d2 d3 b1 b2 f1 f2 f3 f4 3 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = powergrasp 3 | version = attr: powergrasp.__version__ 4 | description = compress graphs with answer-set-programming 5 | long_description = file: README.mkd 6 | author = Lucas Bourneuf 7 | author_email = lucas.bourneuf@inria.fr 8 | url = https://github.com/aluriak/powergrasp 9 | license = GPL 10 | keywords = graph, Answer Set Programming 11 | classifiers = 12 | Development Status :: 2 - Pre-Alpha 13 | Intended Audience :: Science/Research 14 | License :: OSI Approved :: GNU General Public License (GPL) 15 | Natural Language :: English 16 | Programming Language :: Python :: 3 17 | Programming Language :: Python :: 3.5 18 | Programming Language :: ASP 19 | Topic :: Software Development :: Libraries :: Python Modules 20 | 21 | [options] 22 | zip_safe = False 23 | include_package_data = True 24 | packages = find: 25 | install_requires = 26 | bubbletools>=0.6.1 27 | clyngor>=0.3.12 28 | networkx>=2.1 29 | phasme>=0.0.16 30 | pytest>=3.5.0 31 | 32 | [zest.releaser] 33 | create-wheel = yes 34 | python-file-with-version = powergrasp/__init__.py 35 | 36 | 37 | [options.packages.find] 38 | exclude = 39 | test 40 | 41 | [options.entry_points] 42 | console_scripts= 43 | powergrasp = powergrasp.__main__:run_cli 44 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup() 4 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/test/__init__.py -------------------------------------------------------------------------------- /test/ambiguous_test_cases.py: -------------------------------------------------------------------------------- 1 | """List of compression cases. 2 | 3 | """ 4 | 5 | 6 | cases = {} # filename: {expected bubble} 7 | 8 | # Expected results of tested cases 9 | cases['multiple-optimals.lp'] = { 10 | 'common': """ 11 | NODE\ta 12 | NODE\ta1 13 | NODE\ta2 14 | NODE\ta3 15 | NODE\tb 16 | NODE\tb1 17 | NODE\tb2 18 | NODE\tb3 19 | NODE\tc1 20 | NODE\tc2 21 | NODE\tc3 22 | NODE\td1 23 | NODE\td2 24 | NODE\td3 25 | NODE\te1 26 | NODE\te2 27 | NODE\te3 28 | NODE\tf1 29 | NODE\tf2 30 | SET\tPWRN-a-1-1\t1.0 31 | SET\tPWRN-a-1-2\t1.0 32 | SET\tPWRN-a-2-1\t1.0 33 | SET\tPWRN-a-2-2\t1.0 34 | SET\tPWRN-a-3-1\t1.0 35 | SET\tPWRN-a-3-2\t1.0 36 | SET\tPWRN-a-4-1\t1.0 37 | SET\tPWRN-a-4-2\t1.0 38 | IN\tf1\tPWRN-a-4-2 39 | IN\tf2\tPWRN-a-4-2 40 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 41 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 42 | EDGE\tPWRN-a-3-1\tPWRN-a-3-2\t1.0 43 | EDGE\tPWRN-a-4-1\tPWRN-a-4-2\t1.0 44 | EDGE\ta\ta1\t1.0 45 | EDGE\ta\ta2\t1.0 46 | EDGE\ta\ta3\t1.0 47 | """, 48 | 'values': (1, 2, 3), 49 | 'variant': """ 50 | IN\ta1\tPWRN-a-{a}-1 51 | IN\ta2\tPWRN-a-{b}-1 52 | IN\ta3\tPWRN-a-{c}-1 53 | IN\ta\tPWRN-a-4-1 54 | IN\tb1\tPWRN-a-{a}-1 55 | IN\tb2\tPWRN-a-{b}-1 56 | IN\tb3\tPWRN-a-{c}-1 57 | IN\tb\tPWRN-a-4-1 58 | IN\tc1\tPWRN-a-{a}-2 59 | IN\tc2\tPWRN-a-{b}-2 60 | IN\tc3\tPWRN-a-{c}-2 61 | IN\td1\tPWRN-a-{a}-2 62 | IN\td2\tPWRN-a-{b}-2 63 | IN\td3\tPWRN-a-{c}-2 64 | IN\te1\tPWRN-a-{a}-2 65 | IN\te2\tPWRN-a-{b}-2 66 | IN\te3\tPWRN-a-{c}-2 67 | IN\tf1\tPWRN-a-4-2 68 | IN\tf2\tPWRN-a-4-2 69 | """, 70 | } 71 | 72 | cases['test.gml'] = { 73 | 'common': """ 74 | NODE\tb 75 | NODE\tc 76 | NODE\td 77 | NODE\tf 78 | NODE\tg 79 | NODE\tl 80 | NODE\tm 81 | NODE\tp 82 | NODE\ts 83 | NODE\tv 84 | NODE\tw 85 | """, 86 | 'values': (1, 2), 87 | 'variant': """ 88 | IN\tc\tPWRN-b-1-1 89 | IN\tb\tPWRN-b-1-1 90 | IN\tw\tPWRN-b-1-1 91 | IN\td\tPWRN-b-1-1 92 | IN\ts\tPWRN-b-1-1 93 | IN\tg\tPWRN-b-2-{a} 94 | IN\tf\tPWRN-b-2-{a} 95 | IN\tPWRN-b-3-{a}\tPWRN-b-2-{a} 96 | IN\tv\tPWRN-b-3-{a} 97 | IN\tm\tPWRN-b-3-{a} 98 | SET\tPWRN-b-1-1\t1.0 99 | SET\tPWRN-b-2-{a}\t1.0 100 | SET\tPWRN-b-3-{a}\t1.0 101 | EDGE\tPWRN-b-2-{a}\tb\t1.0 102 | EDGE\tc\tf\t1.0 103 | EDGE\tPWRN-b-1-1\tPWRN-b-1-1\t1.0 104 | EDGE\tm\tv\t1.0 105 | EDGE\tl\tp\t1.0 106 | EDGE\tPWRN-b-3-{a}\tl\t1.0 107 | """, 108 | } 109 | -------------------------------------------------------------------------------- /test/definitions.py: -------------------------------------------------------------------------------- 1 | """Various definitions needed by testing routines. 2 | 3 | """ 4 | 5 | import os 6 | from powergrasp import constants 7 | 8 | 9 | def unified_bubble(bubble_lines): 10 | """Return the set of comparable lines found in given bubble lines""" 11 | filtered = ['#'] 12 | if not constants.BUBBLE_WITH_NODES: 13 | filtered.append('NODE') 14 | if not constants.BUBBLE_WITH_SETS: 15 | filtered.append('SET') 16 | filtered = tuple(filtered) 17 | 18 | # filter out comments and blank lines 19 | bubble_lines = (line.strip() for line in bubble_lines) 20 | return set(line for line in bubble_lines 21 | if not line.startswith(filtered) and len(line) > 0) 22 | 23 | 24 | def gen_test_functions(cases:dict, template_test_function:callable): 25 | for fname, bubble in cases.items(): 26 | func = template_test_function('data/' + fname, bubble) 27 | yield 'test_' + os.path.basename(fname).replace('-', '_'), func 28 | -------------------------------------------------------------------------------- /test/powergrasp.default.cfg: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /test/powergrasp.manyoptions.cfg: -------------------------------------------------------------------------------- 1 | [many options] 2 | COVERED_EDGES_FROM_ASP = yes 3 | BICLIQUE_LOWERBOUND_MAXNEI = 5 4 | CLINGO_MULTITHREADING = 0,split 5 | CLINGO_OPTIONS = {'non-star-biclique': '--configuration=handy', 'clique': '--configuration=frumpy'} 6 | STATISTIC_FILE = out/stats.csv 7 | CC_STATISTIC_FILE = out/stats-cc.csv 8 | GLOBAL_STATISTICS = no 9 | BUBBLE_WITH_STATISTICS = no 10 | SHOW_DEBUG = yes 11 | TEST_INTEGRITY = no 12 | SHOW_STORY = no 13 | SHOW_MOTIF_HANDLING = yes 14 | OPTIMIZE_FOR_MEMORY = yes 15 | GRAPH_FILTERING = no 16 | KEEP_SINGLE_NODES = no 17 | MOTIF_TYPE_ORDER = worst-lowerbound-last 18 | PARALLEL_CC_COMPRESSION = 0 19 | -------------------------------------------------------------------------------- /test/powergrasp.nostarsearch.cfg: -------------------------------------------------------------------------------- 1 | { 2 | "use star motif": false, 3 | "biclique lowerbound maxnei": 5 4 | } 5 | -------------------------------------------------------------------------------- /test/powergrasp.oneshot.cfg: -------------------------------------------------------------------------------- 1 | { 2 | "multishot motif search": false 3 | } 4 | -------------------------------------------------------------------------------- /test/test_cases.py: -------------------------------------------------------------------------------- 1 | """List of compression cases. 2 | 3 | """ 4 | 5 | from powergrasp import constants 6 | 7 | cases = {} # filename: expected bubble 8 | 9 | # Expected results of tested cases 10 | cases['diacli.lp'] = """ 11 | NODE\tn 12 | NODE\tr 13 | NODE\tp 14 | NODE\tq 15 | NODE\te 16 | NODE\tb 17 | NODE\tm 18 | NODE\ta 19 | NODE\to 20 | NODE\tc 21 | NODE\tj 22 | NODE\td 23 | NODE\tg 24 | NODE\tl 25 | NODE\ts 26 | NODE\tf 27 | IN\tPWRN-a-3-1\tPWRN-a-1-1 28 | IN\tPWRN-a-4-2\tPWRN-a-2-2 29 | IN\ta\tPWRN-a-2-1 30 | IN\tb\tPWRN-a-2-2 31 | IN\tc\tPWRN-a-2-2 32 | IN\td\tPWRN-a-2-1 33 | IN\te\tPWRN-a-2-2 34 | IN\tf\tPWRN-a-1-1 35 | IN\tg\tPWRN-a-1-1 36 | IN\tj\tPWRN-a-1-1 37 | IN\tl\tPWRN-a-3-1 38 | IN\tm\tPWRN-a-3-2 39 | IN\tn\tPWRN-a-3-2 40 | IN\to\tPWRN-a-4-2 41 | IN\tp\tPWRN-a-3-1 42 | IN\tq\tPWRN-a-4-2 43 | IN\tr\tPWRN-a-1-1 44 | IN\ts\tPWRN-a-3-1 45 | SET\tPWRN-a-1-1\t1.0 46 | SET\tPWRN-a-2-1\t1.0 47 | SET\tPWRN-a-2-2\t1.0 48 | SET\tPWRN-a-3-1\t1.0 49 | SET\tPWRN-a-3-2\t1.0 50 | SET\tPWRN-a-3-2\t1.0 51 | SET\tPWRN-a-4-2\t1.0 52 | EDGE\tPWRN-a-3-1\tPWRN-a-3-2\t1.0 53 | EDGE\tPWRN-a-1-1\tPWRN-a-1-1\t1.0 54 | EDGE\tPWRN-a-3-2\tPWRN-a-4-2\t1.0 55 | EDGE\tb\tc\t1.0 56 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 57 | EDGE\tm\tn\t1.0 58 | """ 59 | 60 | cases['partition.lp'] = """ 61 | NODE\ta 62 | NODE\tb 63 | NODE\tc 64 | NODE\td 65 | NODE\te 66 | NODE\tf 67 | NODE\tg 68 | NODE\th 69 | NODE\ti 70 | IN\tc\tPWRN-a-2-1 71 | IN\td\tPWRN-a-2-1 72 | IN\tg\tPWRN-a-2-2 73 | IN\th\tPWRN-a-2-2 74 | IN\ta\tPWRN-a-1-1 75 | IN\tb\tPWRN-a-1-1 76 | IN\ti\tPWRN-a-1-1 77 | IN\te\tPWRN-a-1-2 78 | IN\tPWRN-a-2-2\tPWRN-a-1-2 79 | IN\tf\tPWRN-a-1-2 80 | SET\tPWRN-a-1-1\t1.0 81 | SET\tPWRN-a-1-2\t1.0 82 | SET\tPWRN-a-2-1\t1.0 83 | SET\tPWRN-a-2-2\t1.0 84 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 85 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 86 | """ 87 | 88 | cases['double_biclique_unambiguous.lp'] = """ 89 | NODE\ta 90 | NODE\tb1 91 | NODE\tb2 92 | NODE\tc 93 | NODE\td 94 | NODE\td2 95 | NODE\te 96 | NODE\tf1 97 | NODE\tf2 98 | NODE\tg 99 | NODE\th 100 | NODE\ti 101 | NODE\tj 102 | NODE\tl 103 | NODE\tm 104 | NODE\tm2 105 | NODE\tn 106 | NODE\to 107 | NODE\tp 108 | NODE\tq 109 | IN\tPWRN-a-3-1\tPWRN-a-2-1 110 | IN\tPWRN-a-5-1\tPWRN-a-3-2 111 | IN\ta\tPWRN-a-1-1 112 | IN\tb1\tPWRN-a-1-2 113 | IN\tb2\tPWRN-a-1-2 114 | IN\tc\tPWRN-a-1-2 115 | IN\td2\tPWRN-a-1-1 116 | IN\td\tPWRN-a-1-1 117 | IN\te\tPWRN-a-1-2 118 | IN\tf1\tPWRN-a-2-1 119 | IN\tf2\tPWRN-a-2-1 120 | IN\tg\tPWRN-a-2-1 121 | IN\th\tPWRN-a-2-2 122 | IN\ti\tPWRN-a-2-2 123 | IN\tj\tPWRN-a-2-1 124 | IN\tl\tPWRN-a-3-1 125 | IN\tm2\tPWRN-a-5-1 126 | IN\tm\tPWRN-a-5-1 127 | IN\tn\tPWRN-a-3-2 128 | IN\to\tPWRN-a-1-2 129 | IN\tp\tPWRN-a-3-1 130 | IN\tq\tPWRN-a-1-2 131 | SET\tPWRN-a-1-1\t1.0 132 | SET\tPWRN-a-1-2\t1.0 133 | SET\tPWRN-a-2-1\t1.0 134 | SET\tPWRN-a-2-2\t1.0 135 | SET\tPWRN-a-3-1\t1.0 136 | SET\tPWRN-a-3-2\t1.0 137 | SET\tPWRN-a-5-1\t1.0 138 | EDGE\tPWRN-a-5-1\tn\t1.0 139 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 140 | EDGE\tf1\tg\t1.0 141 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 142 | EDGE\tPWRN-a-3-1\tPWRN-a-3-2\t1.0 143 | EDGE\tPWRN-a-3-2\tq\t1.0 144 | EDGE\tb1\tc\t1.0 145 | """ 146 | 147 | 148 | cases['testblocks.lp'] = """ 149 | NODE\ta 150 | NODE\tb 151 | NODE\tc 152 | NODE\td 153 | NODE\te 154 | NODE\tf 155 | NODE\tg 156 | NODE\th 157 | NODE\ti 158 | NODE\tj 159 | NODE\tl 160 | NODE\tm 161 | IN\te\tPWRN-a-2-1 162 | IN\tPWRN-a-3-1\tPWRN-a-2-1 163 | IN\ta\tPWRN-a-3-1 164 | IN\tc\tPWRN-a-3-1 165 | IN\tb\tPWRN-a-3-1 166 | IN\td\tPWRN-a-3-1 167 | IN\tg\tPWRN-a-4-1 168 | IN\tf\tPWRN-a-4-1 169 | IN\th\tPWRN-a-4-1 170 | IN\ti\tPWRN-a-1-1 171 | IN\tj\tPWRN-a-1-1 172 | IN\tPWRN-a-4-1\tPWRN-a-1-1 173 | IN\tm\tPWRN-a-1-1 174 | SET\tPWRN-a-1-1\t1.0 175 | SET\tPWRN-a-2-1\t1.0 176 | SET\tPWRN-a-3-1\t1.0 177 | SET\tPWRN-a-4-1\t1.0 178 | EDGE\tPWRN-a-2-1\tPWRN-a-2-1\t1.0 179 | EDGE\tPWRN-a-3-1\tf\t1.0 180 | EDGE\tPWRN-a-4-1\tl\t1.0 181 | EDGE\tPWRN-a-1-1\tPWRN-a-1-1\t1.0 182 | """ 183 | 184 | cases['pnode-to-clique.lp'] = """ 185 | NODE\tb 186 | NODE\td 187 | NODE\ta 188 | NODE\tf 189 | NODE\te 190 | NODE\tc 191 | IN\te\tPWRN-a-1-2 192 | IN\tc\tPWRN-a-1-2 193 | IN\td\tPWRN-a-1-2 194 | IN\ta\tPWRN-a-1-1 195 | IN\tf\tPWRN-a-1-1 196 | IN\tb\tPWRN-a-1-1 197 | SET\tPWRN-a-1-2\t1.0 198 | SET\tPWRN-a-1-1\t1.0 199 | EDGE\tPWRN-a-1-2\tPWRN-a-1-2\t1.0 200 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 201 | """ 202 | 203 | cases['clique.lp'] = """ 204 | NODE\tc 205 | NODE\tb 206 | NODE\ta 207 | NODE\td 208 | IN\tc\tPWRN-a-1-1 209 | IN\tb\tPWRN-a-1-1 210 | IN\ta\tPWRN-a-1-1 211 | IN\td\tPWRN-a-1-1 212 | SET\tPWRN-a-1-1\t1.0 213 | EDGE\tPWRN-a-1-1\tPWRN-a-1-1\t1.0 214 | """ 215 | 216 | cases['concomp.lp'] = """ 217 | NODE\t23 218 | NODE\t42 219 | EDGE\t23\t42\t1.0 220 | NODE\t1 221 | NODE\t2 222 | NODE\t3 223 | NODE\t4 224 | NODE\t5 225 | NODE\t6 226 | IN\t1\tPWRN-1-1-1 227 | IN\t2\tPWRN-1-1-2 228 | IN\t3\tPWRN-1-1-2 229 | IN\t4\tPWRN-1-1-2 230 | IN\t5\tPWRN-1-1-2 231 | IN\t6\tPWRN-1-1-1 232 | SET\tPWRN-1-1-1\t1.0 233 | SET\tPWRN-1-1-2\t1.0 234 | EDGE\tPWRN-1-1-1\tPWRN-1-1-2\t1.0 235 | NODE\ta 236 | NODE\tb 237 | NODE\tc 238 | NODE\td 239 | NODE\te 240 | IN\ta\tPWRN-a-1-1 241 | IN\tb\tPWRN-a-1-1 242 | IN\tc\tPWRN-a-1-1 243 | IN\td\tPWRN-a-1-1 244 | SET\tPWRN-a-1-1\t1.0 245 | EDGE\tPWRN-a-1-1\te\t1.0 246 | """ 247 | 248 | cases['prio_deg.lp'] = """ 249 | NODE\ta 250 | NODE\tb 251 | NODE\tc 252 | NODE\td 253 | NODE\te 254 | NODE\tf 255 | NODE\tg 256 | NODE\th 257 | NODE\ts 258 | IN\tg\tPWRN-a-2-1 259 | IN\tf\tPWRN-a-2-1 260 | IN\th\tPWRN-a-2-1 261 | IN\tc\tPWRN-a-1-1 262 | IN\tb\tPWRN-a-1-1 263 | IN\ta\tPWRN-a-1-1 264 | IN\te\tPWRN-a-1-2 265 | IN\td\tPWRN-a-1-2 266 | SET\tPWRN-a-1-1\t1.0 267 | SET\tPWRN-a-1-2\t1.0 268 | SET\tPWRN-a-2-1\t1.0 269 | EDGE\tPWRN-a-2-1\ts\t1.0 270 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 271 | EDGE\ta\ts\t1.0 272 | """ 273 | 274 | cases['perfectfit.lp'] = """ 275 | NODE\ta 276 | NODE\tb 277 | NODE\tc 278 | NODE\td 279 | NODE\te 280 | NODE\tf 281 | NODE\tg 282 | NODE\th 283 | NODE\ti 284 | NODE\tj 285 | NODE\tl 286 | IN\tPWRN-a-2-1\tPWRN-a-1-2 287 | IN\tb\tPWRN-a-1-1 288 | IN\th\tPWRN-a-1-2 289 | IN\ti\tPWRN-a-1-2 290 | IN\tPWRN-a-3-1\tPWRN-a-1-1 291 | IN\ta\tPWRN-a-1-1 292 | IN\tc\tPWRN-a-3-1 293 | IN\td\tPWRN-a-3-1 294 | IN\te\tPWRN-a-2-1 295 | IN\tf\tPWRN-a-2-1 296 | IN\tg\tPWRN-a-2-1 297 | IN\tj\tPWRN-a-2-2 298 | IN\tl\tPWRN-a-2-2 299 | SET\tPWRN-a-1-1\t1.0 300 | SET\tPWRN-a-1-2\t1.0 301 | SET\tPWRN-a-2-1\t1.0 302 | SET\tPWRN-a-2-2\t1.0 303 | SET\tPWRN-a-3-1\t1.0 304 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 305 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 306 | EDGE\tPWRN-a-2-2\tPWRN-a-3-1\t1.0 307 | """ 308 | 309 | cases['variable-name.gml'] = """ 310 | NODE\tA 311 | NODE\tB 312 | NODE\tC 313 | NODE\tD 314 | NODE\tE 315 | SET\tPWRN-A-1-1\t1.0 316 | IN\tA\tPWRN-A-1-1 317 | IN\tC\tPWRN-A-1-1 318 | IN\tD\tPWRN-A-1-1 319 | EDGE\tB\tPWRN-A-1-1\t1.0 320 | EDGE\tA\tE\t1.0 321 | """ 322 | 323 | cases['unclique.lp'] = """ 324 | NODE\ta 325 | NODE\tb 326 | NODE\tc 327 | NODE\td 328 | NODE\te 329 | NODE\tf 330 | NODE\tg 331 | NODE\th 332 | NODE\ti 333 | IN\tc\tPWRN-a-1-1 334 | IN\te\tPWRN-a-1-1 335 | IN\tf\tPWRN-a-1-1 336 | IN\tg\tPWRN-a-1-1 337 | IN\th\tPWRN-a-1-2 338 | IN\ti\tPWRN-a-1-2 339 | IN\td\tPWRN-a-2-1 340 | IN\tb\tPWRN-a-2-1 341 | IN\ta\tPWRN-a-2-1 342 | SET\tPWRN-a-1-1\t1.0 343 | SET\tPWRN-a-1-2\t1.0 344 | SET\tPWRN-a-2-1\t1.0 345 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 346 | EDGE\tPWRN-a-2-1\tc\t1.0 347 | EDGE\tPWRN-a-2-1\tPWRN-a-2-1\t1.0 348 | """ 349 | 350 | cases['order.lp'] = """ 351 | NODE\tb 352 | NODE\t10 353 | NODE\t4 354 | NODE\t5 355 | NODE\t6 356 | NODE\ta 357 | IN\t4\tPWRN-a-1-1 358 | IN\ta\tPWRN-a-1-1 359 | IN\t6\tPWRN-a-1-1 360 | IN\t5\tPWRN-a-1-1 361 | SET\tPWRN-a-1-1\t1.0 362 | EDGE\ta\tb\t1.0 363 | EDGE\t10\tPWRN-a-1-1\t1.0 364 | """ 365 | 366 | cases['quoting.lp'] = """ 367 | NODE\ta 368 | NODE\tb 369 | NODE\tc 370 | IN\tc\tPWRN-a-1-1 371 | IN\ta\tPWRN-a-1-1 372 | SET\tPWRN-a-1-1\t1.0 373 | EDGE\tPWRN-a-1-1\tb\t1.0 374 | """ 375 | 376 | cases['single-node.lp'] = """ 377 | NODE\ta 378 | """ if constants.KEEP_SINGLE_NODES else "" 379 | 380 | cases['empty.lp'] = """ 381 | """ 382 | 383 | cases['star.lp'] = """ 384 | NODE\ta 385 | NODE\tb 386 | NODE\tc 387 | NODE\td 388 | NODE\te 389 | IN\ta\tPWRN-a-1-1 390 | IN\tb\tPWRN-a-1-1 391 | IN\tc\tPWRN-a-1-1 392 | IN\td\tPWRN-a-1-1 393 | SET\tPWRN-a-1-1\t1.0 394 | EDGE\tPWRN-a-1-1\te\t1.0 395 | """ 396 | 397 | cases['test.graphml'] = """ 398 | NODE\t1 399 | NODE\t2 400 | NODE\t3 401 | NODE\t4 402 | IN\t1\tPWRN-1-1-1 403 | IN\t4\tPWRN-1-1-1 404 | IN\t3\tPWRN-1-1-2 405 | IN\t2\tPWRN-1-1-2 406 | SET\tPWRN-1-1-1\t1.0 407 | SET\tPWRN-1-1-2\t1.0 408 | EDGE\tPWRN-1-1-1\tPWRN-1-1-2\t1.0 409 | """ 410 | 411 | cases['one_edge.lp'] = """ 412 | NODE\ta 413 | NODE\tb 414 | EDGE\ta\tb\t1.0 415 | """ 416 | 417 | cases['horrible_data.lp'] = """ 418 | NODE\t_c92__c34_echo_c32_coucou_c92__c34_ 419 | NODE\t_c91_a_c93_ 420 | NODE\t_c39_echo_c32_coucou_c39_ 421 | SET\tPWRN-_c39_echo_c32_coucou_c39_-1-1\t1.0 422 | IN\t_c92__c34_echo_c32_coucou_c92__c34_\tPWRN-_c39_echo_c32_coucou_c39_-1-1 423 | IN\t_c39_echo_c32_coucou_c39_\tPWRN-_c39_echo_c32_coucou_c39_-1-1 424 | EDGE\tPWRN-_c39_echo_c32_coucou_c39_-1-1\t_c91_a_c93_\t1.0 425 | NODE\t_c91_a_c44_b_c93_ 426 | NODE\t_c36_PYTHONPATH 427 | EDGE\t_c36_PYTHONPATH\t_c91_a_c44_b_c93_\t1.0 428 | """ 429 | 430 | cases['inclusions.lp'] = """ 431 | NODE\t1 432 | NODE\t2 433 | NODE\t3 434 | NODE\t5 435 | NODE\t6 436 | NODE\t7 437 | NODE\t8 438 | NODE\t9 439 | NODE\t10 440 | NODE\ta 441 | NODE\tb 442 | NODE\tc 443 | NODE\td 444 | NODE\te 445 | NODE\tf 446 | NODE\tg 447 | NODE\th 448 | NODE\ti 449 | NODE\tj 450 | NODE\tk 451 | NODE\tl 452 | NODE\tm 453 | NODE\tn 454 | NODE\to 455 | NODE\tp 456 | NODE\tq 457 | NODE\tr 458 | NODE\tv 459 | NODE\tv2 460 | NODE\tw 461 | NODE\tw2 462 | IN\tPWRN-a-6-2\tPWRN-a-2-1 463 | IN\tPWRN-a-6-1\tPWRN-a-4-1 464 | IN\tPWRN-a-5-1\tPWRN-a-6-1 465 | IN\tPWRN-a-4-1\tPWRN-a-1-1 466 | IN\tPWRN-a-4-2\tPWRN-a-3-1 467 | IN\t10\tPWRN-a-2-1 468 | IN\t1\tPWRN-a-3-1 469 | IN\t2\tPWRN-a-3-1 470 | IN\t3\tPWRN-a-3-1 471 | IN\t5\tPWRN-a-2-1 472 | IN\t6\tPWRN-a-2-1 473 | IN\t7\tPWRN-a-2-1 474 | IN\t8\tPWRN-a-2-1 475 | IN\t9\tPWRN-a-2-1 476 | IN\ta\tPWRN-a-1-1 477 | IN\tb\tPWRN-a-1-1 478 | IN\tc\tPWRN-a-1-1 479 | IN\td\tPWRN-a-4-1 480 | IN\te\tPWRN-a-6-1 481 | IN\tf\tPWRN-a-5-1 482 | IN\tg\tPWRN-a-5-1 483 | IN\th\tPWRN-a-1-1 484 | IN\ti\tPWRN-a-1-1 485 | IN\tj\tPWRN-a-1-1 486 | IN\tk\tPWRN-a-1-1 487 | IN\tl\tPWRN-a-1-1 488 | IN\tm\tPWRN-a-4-2 489 | IN\tn\tPWRN-a-4-2 490 | IN\to\tPWRN-a-4-2 491 | IN\tp\tPWRN-a-4-2 492 | IN\tq\tPWRN-a-6-2 493 | IN\tr\tPWRN-a-6-2 494 | IN\tv2\tPWRN-a-5-2 495 | IN\tv\tPWRN-a-5-2 496 | IN\tw2\tPWRN-a-5-2 497 | IN\tw\tPWRN-a-5-2 498 | SET\tPWRN-a-1-1\t1.0 499 | SET\tPWRN-a-2-1\t1.0 500 | SET\tPWRN-a-3-1\t1.0 501 | SET\tPWRN-a-4-1\t1.0 502 | SET\tPWRN-a-5-1\t1.0 503 | SET\tPWRN-a-6-1\t1.0 504 | SET\tPWRN-a-4-2\t1.0 505 | SET\tPWRN-a-5-2\t1.0 506 | SET\tPWRN-a-6-2\t1.0 507 | EDGE\tPWRN-a-1-1\tPWRN-a-1-1\t1.0 508 | EDGE\tPWRN-a-2-1\tPWRN-a-2-1\t1.0 509 | EDGE\tPWRN-a-3-1\tPWRN-a-3-1\t1.0 510 | EDGE\tPWRN-a-4-1\tPWRN-a-4-2\t1.0 511 | EDGE\tPWRN-a-5-1\tPWRN-a-5-2\t1.0 512 | EDGE\tPWRN-a-6-1\tPWRN-a-6-2\t1.0 513 | """ 514 | 515 | cases['disjoint-subpnodes.lp'] = """ 516 | NODE\ta 517 | NODE\tb 518 | NODE\tc 519 | NODE\td 520 | NODE\te 521 | NODE\tf 522 | NODE\tg 523 | NODE\th 524 | IN\ta\tPWRN-a-1-1 525 | IN\tb\tPWRN-a-3-1 526 | IN\tc\tPWRN-a-3-1 527 | IN\td\tPWRN-a-2-1 528 | IN\te\tPWRN-a-2-1 529 | IN\tf\tPWRN-a-2-1 530 | IN\tPWRN-a-2-1\tPWRN-a-1-1 531 | IN\tPWRN-a-3-1\tPWRN-a-1-1 532 | SET\tPWRN-a-1-1\t1.0 533 | SET\tPWRN-a-2-1\t1.0 534 | SET\tPWRN-a-3-1\t1.0 535 | EDGE\tPWRN-a-1-1\tPWRN-a-1-1\t1.0 536 | EDGE\tPWRN-a-2-1\tg\t1.0 537 | EDGE\tPWRN-a-3-1\th\t1.0 538 | """ 539 | 540 | 541 | cases['consider-included-nodes.lp'] = """ 542 | NODE\ta 543 | NODE\tb 544 | NODE\tc 545 | NODE\td 546 | NODE\te 547 | NODE\tf 548 | NODE\tg 549 | NODE\th 550 | NODE\ti 551 | NODE\tj 552 | NODE\tl 553 | NODE\tm 554 | NODE\troot 555 | NODE\troot2 556 | NODE\troot3 557 | SET\tPWRN-a-1-1\t1.0 558 | SET\tPWRN-a-1-2\t1.0 559 | SET\tPWRN-a-2-1\t1.0 560 | SET\tPWRN-a-2-2\t1.0 561 | IN\tPWRN-a-2-1\tPWRN-a-1-1 562 | IN\tPWRN-a-2-2\tPWRN-a-1-1 563 | IN\ta\tPWRN-a-1-1 564 | IN\tb\tPWRN-a-2-1 565 | IN\tc\tPWRN-a-2-1 566 | IN\td\tPWRN-a-2-2 567 | IN\te\tPWRN-a-2-2 568 | IN\tf\tPWRN-a-2-2 569 | IN\tg\tPWRN-a-2-2 570 | IN\th\tPWRN-a-2-2 571 | IN\ti\tPWRN-a-1-1 572 | IN\tj\tPWRN-a-1-1 573 | IN\tl\tPWRN-a-1-1 574 | IN\tm\tPWRN-a-1-1 575 | IN\troot2\tPWRN-a-1-2 576 | IN\troot3\tPWRN-a-1-2 577 | IN\troot\tPWRN-a-1-2 578 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 579 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 580 | EDGE\ta\tb\t1.0 581 | EDGE\ta\td\t1.0 582 | """ 583 | 584 | cases['motif-overlapping.lp'] = """ 585 | # CONNECTED COMPONENT 1 586 | NODE\tc 587 | NODE\te 588 | NODE\tb 589 | NODE\tf 590 | NODE\td 591 | NODE\ta 592 | SET\tPWRN-a-1-2\t1.0 593 | SET\tPWRN-a-1-1\t1.0 594 | IN\te\tPWRN-a-1-2 595 | IN\td\tPWRN-a-1-2 596 | IN\tf\tPWRN-a-1-2 597 | IN\tc\tPWRN-a-1-1 598 | IN\tb\tPWRN-a-1-1 599 | IN\ta\tPWRN-a-1-1 600 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 601 | EDGE\tPWRN-a-1-1\tPWRN-a-1-1\t1.0 602 | # CONNECTED COMPONENT 2 603 | NODE\ta3 604 | NODE\tb4 605 | NODE\tc1 606 | NODE\tc9 607 | NODE\ta5 608 | NODE\ta4 609 | NODE\tc8 610 | NODE\tb2 611 | NODE\tc4 612 | NODE\tb3 613 | NODE\tc5 614 | NODE\tc7 615 | NODE\tc3 616 | NODE\th 617 | NODE\tb1 618 | NODE\ta2 619 | NODE\tc2 620 | NODE\tc6 621 | NODE\ta1 622 | SET\tPWRN-a1-4-1\t1.0 623 | SET\tPWRN-a1-1-1\t1.0 624 | SET\tPWRN-a1-2-1\t1.0 625 | IN\ta1\tPWRN-a1-1-1 626 | IN\ta2\tPWRN-a1-2-1 627 | IN\ta3\tPWRN-a1-2-1 628 | IN\ta4\tPWRN-a1-2-1 629 | IN\ta5\tPWRN-a1-2-1 630 | IN\tb1\tPWRN-a1-4-1 631 | IN\tb2\tPWRN-a1-4-1 632 | IN\tb3\tPWRN-a1-4-1 633 | IN\tb4\tPWRN-a1-1-1 634 | IN\tc1\tPWRN-a1-1-1 635 | IN\tc2\tPWRN-a1-1-1 636 | IN\tc3\tPWRN-a1-1-1 637 | IN\tc4\tPWRN-a1-1-1 638 | IN\tc5\tPWRN-a1-1-1 639 | IN\tc6\tPWRN-a1-1-1 640 | IN\tc7\tPWRN-a1-1-1 641 | IN\tc8\tPWRN-a1-1-1 642 | IN\tc9\tPWRN-a1-1-1 643 | EDGE\tPWRN-a1-4-1\tb4\t1.0 644 | EDGE\tPWRN-a1-4-1\tPWRN-a1-4-1\t1.0 645 | EDGE\tPWRN-a1-1-1\th\t1.0 646 | EDGE\tPWRN-a1-2-1\ta1\t1.0 647 | EDGE\tPWRN-a1-2-1\tPWRN-a1-2-1\t1.0 648 | # CONNECTED COMPONENT 3 649 | NODE\tx2 650 | NODE\tz2 651 | NODE\tx1 652 | NODE\tx4 653 | NODE\tz1 654 | NODE\ty1 655 | NODE\tx3 656 | NODE\tz3 657 | NODE\ty2 658 | SET\tPWRN-x1-1-2\t1.0 659 | SET\tPWRN-x1-1-1\t1.0 660 | SET\tPWRN-x1-2-1\t1.0 661 | IN\tz1\tPWRN-x1-1-2 662 | IN\tz3\tPWRN-x1-1-2 663 | IN\tz2\tPWRN-x1-1-2 664 | IN\ty1\tPWRN-x1-1-1 665 | IN\ty2\tPWRN-x1-1-1 666 | IN\tx1\tPWRN-x1-2-1 667 | IN\tx2\tPWRN-x1-2-1 668 | IN\tx3\tPWRN-x1-2-1 669 | IN\tx4\tPWRN-x1-1-1 670 | EDGE\tPWRN-x1-1-1\tPWRN-x1-1-2\t1.0 671 | EDGE\tPWRN-x1-2-1\tx4\t1.0 672 | EDGE\tPWRN-x1-2-1\tPWRN-x1-2-1\t1.0 673 | """ 674 | -------------------------------------------------------------------------------- /test/test_multishot_compression.py: -------------------------------------------------------------------------------- 1 | """Test of ambiguous and multishot graph compression. 2 | 3 | Note that the test_* functions are generated 4 | from the template_test_function function. 5 | 6 | """ 7 | import os 8 | import itertools 9 | 10 | from powergrasp.routines import compress_by_cc 11 | from .ambiguous_test_cases import cases 12 | from .definitions import unified_bubble, gen_test_functions 13 | 14 | 15 | def template_test_function(file:str, all_bubblelines:set): 16 | def test_function(): 17 | found = unified_bubble(compress_by_cc(file)) 18 | variants_keys = itertools.permutations(all_bubblelines['values']) 19 | variants = {all_bubblelines['common'] + '\n' 20 | + all_bubblelines['variant'].format(**dict(zip('abcde', keys))) 21 | for keys in variants_keys} 22 | expecteds = tuple(unified_bubble(variant.splitlines(keepends=False)) 23 | for variant in variants) 24 | # The following lines are here to get a proper understanding of the data 25 | # in case of error. 26 | for expected in expecteds: 27 | if found == expected: 28 | return 29 | print('FOUND:', found) 30 | for idx, expected in enumerate(expecteds, start=1): 31 | print('EXPECTED', idx, ':', expected - found) 32 | assert found in expecteds, "Expected not found" 33 | return test_function 34 | 35 | 36 | for name, func in gen_test_functions(cases, template_test_function): 37 | globals()[name] = func 38 | -------------------------------------------------------------------------------- /test/test_recipes.py: -------------------------------------------------------------------------------- 1 | """Test of recipe'd graph compression. 2 | 3 | Note that the test_* functions are generated 4 | from the template_test_function function. 5 | 6 | """ 7 | 8 | import pytest 9 | from powergrasp.constants import USE_STAR_MOTIF 10 | from powergrasp.routines import compress_by_cc 11 | from powergrasp.recipe import RecipeError 12 | from .definitions import unified_bubble, gen_test_functions 13 | 14 | 15 | def test_recipe_build_from_generator(): 16 | "Same as test_simple_recipe, but with initialization from generator" 17 | def gen_recipe(): 18 | yield 'biclique c g h i' 19 | yield 'biclique a b d e' 20 | yield 'biclique a b f' 21 | yield 'biclique c d e' 22 | found = unified_bubble(compress_by_cc('data/recipe-test.lp', recipe_files=[gen_recipe()])) 23 | expected = unified_bubble(BUBBLELINES_SIMPLE.splitlines(keepends=False)) 24 | with open('out/out.bbl', 'w') as fd: 25 | fd.write('\n'.join(found)) 26 | assert found == expected 27 | 28 | 29 | def test_simple_recipe(): 30 | found = unified_bubble(compress_by_cc('data/recipe-test.lp', recipe_files='data/recipe-test.txt')) 31 | expected = unified_bubble(BUBBLELINES_SIMPLE.splitlines(keepends=False)) 32 | # with open('out/out.bbl', 'w') as fd: 33 | # fd.write('\n'.join(found)) 34 | assert found == expected 35 | 36 | def test_recipe_options(): 37 | found = unified_bubble(compress_by_cc('data/recipe-option-test.lp', recipe_files='data/recipe-option-test.txt')) 38 | expected = unified_bubble(BUBBLELINES_OPTIONS.splitlines(keepends=False)) 39 | # with open('out/out.bbl', 'w') as fd: 40 | # fd.write('\n'.join(found)) 41 | assert found == expected 42 | 43 | def test_recipe_error_because_of_unknow_nodes(): 44 | with pytest.raises(RecipeError): 45 | unified_bubble(compress_by_cc('data/recipe-option-test.lp', recipe_files=""" 46 | biclique c g h i 47 | biclique,open a b d e 48 | biclique unexisting nodes are not compressible 49 | """)) 50 | 51 | def test_recipe_error_because_of_impossible_compression(): 52 | with pytest.raises(RecipeError): 53 | unified_bubble(compress_by_cc('data/recipe-option-test.lp', recipe_files=""" 54 | biclique c g h i 55 | biclique a b d e c 56 | """)) 57 | 58 | def test_recipe_error_because_of_overlapping_entries(): 59 | with pytest.raises(RecipeError): 60 | unified_bubble(compress_by_cc('data/recipe-option-test.lp', recipe_files=""" 61 | biclique c g h i 62 | biclique a b d e 63 | biclique a b c d e f 64 | """)) 65 | 66 | def _test_recipe_use_of_already_defined_powernodes(): 67 | found = unified_bubble(compress_by_cc('data/suboptimal.lp', recipe_files=""" 68 | biclique,star a b i e f 69 | biclique,star c d a b l 70 | biclique,star e f g h j 71 | biclique,star,last g h k c d 72 | """)) 73 | expected = unified_bubble(BUBBLELINES_POWERNODE.splitlines(keepends=False)) 74 | # with open('out/out.bbl', 'w') as fd: 75 | # fd.write('\n'.join(found)) 76 | assert found == expected 77 | 78 | @pytest.mark.skip(reason="this is a core bug that should be fixed ASAP") 79 | def test_after_recipe_use_of_already_defined_powernode(): 80 | found = unified_bubble(compress_by_cc('data/recipe-test-inclusion.lp', recipe_files=""" 81 | biclique,star e f g h 82 | """)) 83 | expected = unified_bubble(BUBBLELINES_POWERNODE_REUSE.splitlines(keepends=False)) 84 | with open('out/out.bbl', 'w') as fd: 85 | fd.write('\n'.join(found)) 86 | assert found == expected 87 | 88 | 89 | BUBBLELINES_POWERNODE_REUSE = """ 90 | NODE\ta 91 | NODE\tb 92 | NODE\tc 93 | NODE\td 94 | NODE\te 95 | NODE\tf 96 | NODE\tg 97 | NODE\th 98 | SET\tPWRN-a-1-1\t1.0 99 | SET\tPWRN-a-1-2\t1.0 100 | SET\tPWRN-a-2-1\t1.0 101 | SET\tPWRN-a-2-2\t1.0 102 | IN\ta\tPWRN-a-2-1 103 | IN\tb\tPWRN-a-2-1 104 | IN\tc\tPWRN-a-2-2 105 | IN\td\tPWRN-a-2-2 106 | IN\te\tPWRN-a-1-1 107 | IN\tf\tPWRN-a-1-1 108 | IN\tg\tPWRN-a-1-2 109 | IN\th\tPWRN-a-1-2 110 | IN\tPWRN-a-1-1\tPWRN-a-2-2 111 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 112 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 113 | """ 114 | 115 | BUBBLELINES_POWERNODE = """ 116 | NODE\ta 117 | NODE\tb 118 | NODE\tc 119 | NODE\td 120 | NODE\te 121 | NODE\tf 122 | NODE\tg 123 | NODE\th 124 | NODE\ti 125 | NODE\tj 126 | NODE\tk 127 | NODE\tl 128 | SET\tPWRN-a-1-1\t1.0 129 | SET\tPWRN-a-1-2\t1.0 130 | SET\tPWRN-a-2-1\t1.0 131 | SET\tPWRN-a-2-2\t1.0 132 | SET\tPWRN-a-3-1\t1.0 133 | SET\tPWRN-a-3-2\t1.0 134 | SET\tPWRN-a-4-1\t1.0 135 | SET\tPWRN-a-4-2\t1.0 136 | IN\ta\tPWRN-a-1-1 137 | IN\tb\tPWRN-a-1-1 138 | IN\ti\tPWRN-a-1-2 139 | IN\tc\tPWRN-a-2-1 140 | IN\td\tPWRN-a-2-1 141 | IN\tl\tPWRN-a-2-2 142 | IN\te\tPWRN-a-3-1 143 | IN\tf\tPWRN-a-3-1 144 | IN\tj\tPWRN-a-3-2 145 | IN\tg\tPWRN-a-4-1 146 | IN\th\tPWRN-a-4-1 147 | IN\tk\tPWRN-a-4-2 148 | IN\tPWRN-a-1-1\tPWRN-a-2-2 149 | IN\tPWRN-a-3-1\tPWRN-a-1-2 150 | IN\tPWRN-a-4-1\tPWRN-a-3-2 151 | IN\tPWRN-a-2-1\tPWRN-a-4-2 152 | EDGE\tPWRN-a-1-1\tPWRN-a-1-2\t1.0 153 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 154 | EDGE\tPWRN-a-3-1\tPWRN-a-3-2\t1.0 155 | EDGE\tPWRN-a-4-1\tPWRN-a-4-2\t1.0 156 | """ 157 | 158 | if USE_STAR_MOTIF: 159 | BUBBLELINES_SIMPLE = """ 160 | NODE\ta 161 | NODE\tb 162 | NODE\tc 163 | NODE\td 164 | NODE\te 165 | NODE\tf 166 | NODE\tg 167 | NODE\th 168 | NODE\ti 169 | NODE\tj 170 | SET\tPWRN-a-1-1\t1.0 171 | SET\tPWRN-a-2-1\t1.0 172 | SET\tPWRN-a-2-2\t1.0 173 | SET\tPWRN-a-5-1\t1.0 174 | IN\ta\tPWRN-a-2-1 175 | IN\tb\tPWRN-a-2-1 176 | IN\td\tPWRN-a-2-2 177 | IN\te\tPWRN-a-2-2 178 | IN\tf\tPWRN-a-5-1 179 | IN\tg\tPWRN-a-1-1 180 | IN\th\tPWRN-a-1-1 181 | IN\ti\tPWRN-a-1-1 182 | IN\tj\tPWRN-a-5-1 183 | EDGE\tPWRN-a-1-1\tc\t1.0 184 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 185 | EDGE\tPWRN-a-2-1\tf\t1.0 186 | EDGE\tPWRN-a-2-2\tc\t1.0 187 | EDGE\tPWRN-a-5-1\tc\t1.0 188 | """ 189 | BUBBLELINES_OPTIONS = """ 190 | NODE\ta 191 | NODE\tb 192 | NODE\tc 193 | NODE\td 194 | NODE\te 195 | NODE\tf 196 | NODE\tg 197 | NODE\th 198 | NODE\ti 199 | NODE\tj 200 | NODE\tk 201 | NODE\tl 202 | NODE\tm 203 | NODE\tn 204 | SET\tPWRN-a-1-1\t1.0 205 | SET\tPWRN-a-2-1\t1.0 206 | SET\tPWRN-a-2-2\t1.0 207 | SET\tPWRN-a-4-1\t1.0 208 | SET\tPWRN-a-5-1\t1.0 209 | SET\tPWRN-a-7-1\t1.0 210 | IN\tPWRN-a-5-1\tPWRN-a-1-1 211 | IN\ta\tPWRN-a-2-1 212 | IN\tb\tPWRN-a-2-1 213 | IN\tc\tPWRN-a-2-1 214 | IN\td\tPWRN-a-2-2 215 | IN\te\tPWRN-a-2-2 216 | IN\tf\tPWRN-a-2-2 217 | IN\tg\tPWRN-a-5-1 218 | IN\th\tPWRN-a-5-1 219 | IN\ti\tPWRN-a-1-1 220 | IN\tj\tPWRN-a-7-1 221 | IN\tk\tPWRN-a-7-1 222 | IN\tl\tPWRN-a-4-1 223 | IN\tm\tPWRN-a-4-1 224 | IN\tn\tPWRN-a-4-1 225 | EDGE\tPWRN-a-1-1\tc\t1.0 226 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 227 | EDGE\tPWRN-a-4-1\ta\t1.0 228 | EDGE\tPWRN-a-5-1\ta\t1.0 229 | EDGE\tPWRN-a-7-1\tc\t1.0 230 | EDGE\ta\tj\t1.0 231 | EDGE\ta\tk\t1.0 232 | EDGE\tc\tl\t1.0 233 | EDGE\tc\tm\t1.0 234 | EDGE\tc\tn\t1.0 235 | """ 236 | else: 237 | # in such case, the stars are handled as bicliques, and in this case, 238 | # node c being smaller than its neighbor, it is placed in set 1 instead of 2. 239 | BUBBLELINES_SIMPLE = """ 240 | NODE\ta 241 | NODE\tb 242 | NODE\tc 243 | NODE\td 244 | NODE\te 245 | NODE\tf 246 | NODE\tg 247 | NODE\th 248 | NODE\ti 249 | NODE\tj 250 | SET\tPWRN-a-2-1\t1.0 251 | SET\tPWRN-a-2-2\t1.0 252 | # Sets modifications: 253 | SET\tPWRN-a-1-2\t1.0 254 | SET\tPWRN-a-5-2\t1.0 255 | IN\ta\tPWRN-a-2-1 256 | IN\tb\tPWRN-a-2-1 257 | IN\td\tPWRN-a-2-2 258 | IN\te\tPWRN-a-2-2 259 | # Inclusions modifications: 260 | IN\tf\tPWRN-a-5-2 261 | IN\tg\tPWRN-a-1-2 262 | IN\th\tPWRN-a-1-2 263 | IN\ti\tPWRN-a-1-2 264 | IN\tj\tPWRN-a-5-2 265 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 266 | EDGE\tPWRN-a-2-1\tf\t1.0 267 | EDGE\tPWRN-a-2-2\tc\t1.0 268 | # Edges modifications: 269 | EDGE\tPWRN-a-1-2\tc\t1.0 270 | EDGE\tPWRN-a-5-2\tc\t1.0 271 | """ 272 | BUBBLELINES_OPTIONS = """ 273 | NODE\ta 274 | NODE\tb 275 | NODE\tc 276 | NODE\td 277 | NODE\te 278 | NODE\tf 279 | NODE\tg 280 | NODE\th 281 | NODE\ti 282 | NODE\tj 283 | NODE\tk 284 | NODE\tl 285 | NODE\tm 286 | NODE\tn 287 | SET\tPWRN-a-2-1\t1.0 288 | SET\tPWRN-a-2-2\t1.0 289 | # Sets modifications: 290 | SET\tPWRN-a-1-2\t1.0 291 | SET\tPWRN-a-4-2\t1.0 292 | SET\tPWRN-a-5-2\t1.0 293 | SET\tPWRN-a-7-2\t1.0 294 | IN\ta\tPWRN-a-2-1 295 | IN\tb\tPWRN-a-2-1 296 | IN\tc\tPWRN-a-2-1 297 | IN\td\tPWRN-a-2-2 298 | IN\te\tPWRN-a-2-2 299 | IN\tf\tPWRN-a-2-2 300 | # Inclusions modifications: 301 | IN\tPWRN-a-5-2\tPWRN-a-1-2 302 | IN\ti\tPWRN-a-1-2 303 | IN\tl\tPWRN-a-4-2 304 | IN\tm\tPWRN-a-4-2 305 | IN\tn\tPWRN-a-4-2 306 | IN\tg\tPWRN-a-5-2 307 | IN\th\tPWRN-a-5-2 308 | IN\tj\tPWRN-a-7-2 309 | IN\tk\tPWRN-a-7-2 310 | EDGE\tPWRN-a-2-1\tPWRN-a-2-2\t1.0 311 | EDGE\ta\tj\t1.0 312 | EDGE\ta\tk\t1.0 313 | EDGE\tc\tl\t1.0 314 | EDGE\tc\tm\t1.0 315 | EDGE\tc\tn\t1.0 316 | # Edges modifications: 317 | EDGE\tPWRN-a-1-2\tc\t1.0 318 | EDGE\tPWRN-a-4-2\ta\t1.0 319 | EDGE\tPWRN-a-5-2\ta\t1.0 320 | EDGE\tPWRN-a-7-2\tc\t1.0 321 | """ 322 | -------------------------------------------------------------------------------- /test/test_unambiguous_compression.py: -------------------------------------------------------------------------------- 1 | """Test of graph compression. 2 | 3 | Note that the test_* functions are generated 4 | from the template_test_function function. 5 | 6 | """ 7 | 8 | from powergrasp.routines import compress_by_cc 9 | from .test_cases import cases 10 | from .definitions import unified_bubble, gen_test_functions 11 | 12 | 13 | def template_test_function(file:str, bubblelines:str): 14 | def test_function(): 15 | found = unified_bubble(compress_by_cc(file)) 16 | expected = unified_bubble(bubblelines.splitlines(keepends=False)) 17 | assert found == expected 18 | return test_function 19 | 20 | 21 | for name, func in gen_test_functions(cases, template_test_function): 22 | globals()[name] = func 23 | -------------------------------------------------------------------------------- /test/test_utils.py: -------------------------------------------------------------------------------- 1 | 2 | from powergrasp.utils import quoted 3 | 4 | def test_quoted(): 5 | """Hard to test in docstring because of all the backslashs""" 6 | assert quoted('"a') == r'"\"a"' 7 | assert quoted('a"b') == r'"a\"b"' 8 | assert len(quoted('a"b')) == 6 9 | assert quoted(r'"\"a"') == r'"\"\"a\""' 10 | assert quoted(r'"\"a\""') == r'"\"\"a\"\""' 11 | assert len(quoted('"a')) == 5 12 | assert '{}'.format(quoted('"a')) == r'"\"a"' 13 | assert len('{}'.format(quoted('"a'))) == 5 14 | assert quoted(r'"\"a"') == r'"\"\"a\""' 15 | -------------------------------------------------------------------------------- /triplet/.gitignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | .pytest_cache/ 3 | Session.vim 4 | __pycache__/ 5 | debug/ 6 | dist/ 7 | powergrasp.egg-info/ 8 | PowerGrASP.egg-info/ 9 | venv/ 10 | -------------------------------------------------------------------------------- /triplet/Makefile: -------------------------------------------------------------------------------- 1 | 2 | METHOD=search-byenum.lp 3 | # METHOD=search-byconcept.lp 4 | INFILE_DIR=../data 5 | INFILE=double_biclique_unambiguous.lp 6 | OPTIONS= 7 | 8 | ## Usage and tests 9 | compress: 10 | # clingo 0 --opt-mode=optN -t 4 $(INFILE_DIR)/$(INFILE) $(METHOD) 11 | python search.py $(INFILE_DIR)/$(INFILE) $(METHOD) $(OPTIONS) 12 | 13 | thesis: 14 | - rm out/*.png out/*.bbl 15 | $(MAKE) real-puceron-mi-m-diff-no3019 OPTIONS="" 16 | $(MAKE) real-puceron-mi-m-diff-no3019 OPTIONS="-na 3 -nb 3" 17 | $(MAKE) real-puceron-mi-m-diff-no3019 OPTIONS="-nc 2" 18 | $(MAKE) real-puceron-mi-m-diff-no3019 OPTIONS="-nc 3" 19 | $(MAKE) real-matrixdb-core27 OPTIONS="" 20 | $(MAKE) real-matrixdb-core27 OPTIONS="-na 3 -nb 3" 21 | $(MAKE) real-matrixdb-core27 OPTIONS="-nc 2" 22 | $(MAKE) real-matrixdb-core27 OPTIONS="-nc 3" 23 | 24 | clear-cache: 25 | rm cases_cache/*.dat 26 | 27 | ## All real test cases 28 | real-puceron-mi-m-diff: 29 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=miRNA_mRNA_diff.lp 30 | real-puceron-mi-m-diff-no3019: 31 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=miRNA_mRNA_diff-no3019.lp 32 | real-puceron-mi-lnc: 33 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=miRNA_lncRNA.lp 34 | real-puceron-lnc-m: 35 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=lncRNA_mRNA.lp 36 | real-puceron-mi-m-lnc: 37 | $(MAKE) compress INFILE_DIR=~/data/puceron/data-playing/output INFILE=ternary_concepts_mi_m_lnc-edge.lp 38 | real-matrixdb-core27: 39 | $(MAKE) compress INFILE_DIR=~/data/MatrixDb/compmatrixdb/matrixdb_CORE27_example INFILE=matrixdb_CORE27_example.lp 40 | real-matrixdb-all: 41 | $(MAKE) compress INFILE_DIR=~/data/MatrixDb/compmatrixdb/matrixdb_Human_Human_171107_extended INFILE=matrixdb_Human_Human_171107_extended_0.0.lp 42 | 43 | 44 | ## All test cases 45 | abnormal: 46 | $(MAKE) compress INFILE=abnormal.lp 47 | bintree: 48 | $(MAKE) compress INFILE=bintree.lp 49 | clique: 50 | $(MAKE) compress INFILE=clique.lp 51 | cliques: 52 | $(MAKE) compress INFILE=cliques.lp 53 | concomp: 54 | $(MAKE) compress INFILE=concomp.lp 55 | concept-loop: 56 | $(MAKE) compress INFILE=concept-loop.lp 57 | ddiam: 58 | $(MAKE) compress INFILE=ddiam.lp 59 | diacli: 60 | $(MAKE) compress INFILE=diacli.lp 61 | diamond: 62 | $(MAKE) compress INFILE=diamond.lp 63 | disjoint-subpnodes: 64 | $(MAKE) compress INFILE=disjoint-subpnodes.lp 65 | double_biclique_unambiguous: 66 | $(MAKE) compress INFILE=double_biclique_unambiguous.lp 67 | double-p-groups: 68 | $(MAKE) compress INFILE=double-p-groups.lp 69 | hanging-bio-notree-cc0: 70 | $(MAKE) compress INFILE=hanging-bio-notree-cc0.lp 71 | horrible_data: 72 | $(MAKE) compress INFILE=horrible_data.lp 73 | inclusions: 74 | $(MAKE) compress INFILE=inclusions.lp 75 | consider-included-nodes: 76 | $(MAKE) compress INFILE=consider-included-nodes.lp 77 | motif-overlapping: 78 | $(MAKE) compress INFILE=motif-overlapping.lp 79 | multiple-optimals: 80 | $(MAKE) compress INFILE=multiple-optimals.lp 81 | n8_d0: 82 | $(MAKE) compress INFILE=n8_d0.7.lp 83 | one_edge: 84 | $(MAKE) compress INFILE=one_edge.lp 85 | order: 86 | $(MAKE) compress INFILE=order.lp 87 | overlapping-bicliques: 88 | $(MAKE) compress INFILE=overlapping-bicliques.lp 89 | partition: 90 | $(MAKE) compress INFILE=partition.lp 91 | perfectfit: 92 | $(MAKE) compress INFILE=perfectfit.lp 93 | phosphatase: 94 | $(MAKE) compress INFILE=phosphatase.lp 95 | pnode-to-clique: 96 | $(MAKE) compress INFILE=pnode-to-clique.lp 97 | prio_deg: 98 | $(MAKE) compress INFILE=prio_deg.lp 99 | quasibiclique: 100 | $(MAKE) compress INFILE=quasibiclique.lp 101 | quoting: 102 | $(MAKE) compress INFILE=quoting.lp 103 | single-node: 104 | $(MAKE) compress INFILE=single-node.lp 105 | star: 106 | $(MAKE) compress INFILE=star.lp 107 | structural-binding: 108 | $(MAKE) compress INFILE=structural-binding.lp 109 | structural-binding-maincc: 110 | $(MAKE) compress INFILE=structural-binding-maincc.lp 111 | structural-binding-nobridge: 112 | $(MAKE) compress INFILE=structural-binding-nobridge.lp 113 | testblocks: 114 | $(MAKE) compress INFILE=testblocks.lp 115 | test-gml: 116 | $(MAKE) compress INFILE=test.gml 117 | test-graphml: 118 | $(MAKE) compress INFILE=test.graphml 119 | todel: 120 | $(MAKE) compress INFILE=todel.lp 121 | triplets: 122 | $(MAKE) compress INFILE=triplets.lp 123 | typical: 124 | $(MAKE) compress INFILE=typical-use-case.lp 125 | unclique: 126 | $(MAKE) compress INFILE=unclique.lp 127 | variable-name: 128 | $(MAKE) compress INFILE=variable-name.gml 129 | wiki-tree-decomposition: 130 | $(MAKE) compress INFILE=wiki-tree-decomposition.lp 131 | zorro: 132 | $(MAKE) compress INFILE=zorro.lp 133 | -------------------------------------------------------------------------------- /triplet/README: -------------------------------------------------------------------------------- 1 | Distribution of triplet concepts, computation of graphics 2 | -------------------------------------------------------------------------------- /triplet/cases_cache/backup-incomplete/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/backup-incomplete/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/backup-incomplete/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/backup-incomplete/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/backup-incomplete/miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/backup-incomplete/miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/backup-incomplete/miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/backup-incomplete/miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/double_biclique_unambiguous__a_0-_b_0-_c_0-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/double_biclique_unambiguous__a_0-_b_0-_c_0-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/double_biclique_unambiguous__a_0-_b_0-_c_0-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/double_biclique_unambiguous__a_0-_b_0-_c_0-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_0-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_0-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_0-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_0-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_2-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_2-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_2-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_2-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_3-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_3-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_3-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/matrixdb_CORE27_example__a_0-_b_0-_c_3-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/matrixdb_CORE27_example__a_3-_b_3-_c_0-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/matrixdb_CORE27_example__a_3-_b_3-_c_0-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/matrixdb_CORE27_example__a_3-_b_3-_c_0-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/matrixdb_CORE27_example__a_3-_b_3-_c_0-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_2-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_2-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_2-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_2-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_3-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_3-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_3-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_0-_b_0-_c_3-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_3-_b_2-_c_0-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_3-_b_2-_c_0-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_3-_b_2-_c_0-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_3-_b_2-_c_0-.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.concepts.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.concepts.dat -------------------------------------------------------------------------------- /triplet/cases_cache/miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/cases_cache/miRNA_mRNA_diff-no3019__a_3-_b_3-_c_0-.dat -------------------------------------------------------------------------------- /triplet/combinations.py: -------------------------------------------------------------------------------- 1 | """Create a table of triplet state combinations""" 2 | 3 | 4 | import itertools 5 | CROSS = r'\x' 6 | EMPTY = r' ' 7 | 8 | A_CASES, B_CASES, C_CASES = (0, 1, 2), (0, 1, 2), (0, 1, 2) 9 | COLSEP = '&' 10 | 11 | 12 | def nb_edge_of(a, b, c): 13 | return int(a * b + a * c + b * c + (c*(c-1))/2) 14 | def is_canonical(a, b, c): 15 | if a == 1 or b == 1: 16 | return False 17 | if (not a) and b: # a empty, but not b 18 | return False 19 | return nb_edge_of(a, b, c) > 0 20 | 21 | def desc_other_forms(a, b, c): 22 | P002 = '$7$', 'equivalent to $A=0, B=0, C=2$' 23 | if nb_edge_of(a, b, c) == 0: return 24 | if a == 0 and b == 0: 25 | if c == 2: 26 | return r'$1+\frac{|C|!}{(|C|-2)!}+2\times |C|$', r'\newline$\forall x,y \in C$: $A=\{x\} \land B=\{y\}$' # permutation writing 27 | elif c == 1: 28 | return r'$3$', r'$A=\{x\} or B=\{x\} or C=\{x\}$' 29 | elif a == 0: 30 | if b == 1: 31 | return P002 32 | else: 33 | assert b == 2 34 | if c == 1: 35 | return r'$2 \times 2$', 'move $C$ in $A$ and $A\leftrightharpoons B$' 36 | elif c == 2: 37 | return r'$1 + |C| \times 2$', 'move $c\in C$ in $A$ and $A\leftrightharpoons B$' 38 | elif b == 0: 39 | if a == 1: 40 | return P002 41 | else: 42 | assert a == 2 43 | if c == 1: 44 | return r'$2 \times 2$', 'move $C$ in $B$ and $A\leftrightharpoons B$' 45 | elif c == 2: 46 | return r'$1 + |C| \times 2$', 'move $c\in C$ in $B$ and $A\leftrightharpoons B$' 47 | if a == 1 and b == 1: 48 | if c == 0: 49 | return P002 50 | elif c == 1: 51 | return P002 52 | else: 53 | return P002 54 | elif a == 1: 55 | assert b == 2 56 | return r'2', r'$A=\emptyset \land C=C\cup A$' 57 | elif b == 1: 58 | assert a == 2 59 | return r'2', r'$B=\emptyset \land C=C\cup B$' 60 | elif a == 2 and b == 2: 61 | return r'2', r'$A\leftrightharpoons B$' 62 | assert False, f'MISSING CASE: ({a}, {b}, {c})' 63 | 64 | columns = { 65 | r'$A_0$': lambda a, b, c: a == 0, 66 | r'$A_1$': lambda a, b, c: a == 1, 67 | r'$A_{2+}$': lambda a, b, c: a == 2, 68 | r'$B_0$': lambda a, b, c: b == 0, 69 | r'$B_1$': lambda a, b, c: b == 1, 70 | r'$B_{2+}$': lambda a, b, c: b == 2, 71 | r'$C_0$': lambda a, b, c: c == 0, 72 | r'$C_1$': lambda a, b, c: c == 1, 73 | r'$C_{2+}$': lambda a, b, c: c == 2, 74 | # 'has edge': lambda a, b, c: nb_edge_of(a, b, c) > 0, 75 | # 'canonical': is_canonical, 76 | 'edge': lambda a, b, c: nb_edge_of(a, b, c) > 0, 77 | 'can.': is_canonical, 78 | r'\# of form': desc_other_forms, 79 | } 80 | def render_desc_other_forms(segments): 81 | if segments is None: return '' # 'no edges' # clearer when empty ? 82 | return ' $~\LeftRightArrow~$ '.join(v for v in segments if v) 83 | 84 | renderer = { 85 | r'\# of form': render_desc_other_forms, 86 | } 87 | default_renderer = lambda x: CROSS if x else EMPTY # used if column not in renderer dict 88 | 89 | lambda segs: ' ' + ' + '.join(segs) + ' ' 90 | print(r""" 91 | \begin{table} 92 | \centering\footnotesize\tabcolsep=0.11cm 93 | \begin{tabular}{|c|c|c||c|c|c||c|c|c||c|c||c|} 94 | \cline{1-9} 95 | \multicolumn{9}{|c|}{Triplet composition (in node number)} & \multicolumn{3}{c}{} \\\hline 96 | """) 97 | print(r'\begin{tabular}{|' + '|'.join('c' for _ in columns) + '|}') 98 | print(' ' + f' {COLSEP} '.join(columns) + r' \\\hline\hline') 99 | for a, b, c in itertools.product(A_CASES, B_CASES, C_CASES): 100 | if is_canonical(a, b, c) or True: 101 | line = COLSEP.join(( 102 | str(renderer.get(col, default_renderer)(call(a, b, c))).center(len(col)+2) 103 | for col, call in columns.items() 104 | )) 105 | print(line + r'\\\hline') 106 | print(r""" 107 | \end{tabular} 108 | \caption{Canonicity and number of alternative writing of all triplets according to their node composition. The rightmost column indicates the number of alternative writing, based on the number of node in set $C$, and on the permutation of sets $A$ and $B$, noted $A\leftrightharpoons B$.} 109 | % see ~/packages/powergrasp/triplet/combinations.py for generation of that table (it has been edited directly here since) 110 | \label{tab:triplet-concept:canonicity-distribution} 111 | \end{table} % Table tab:triplet-concept:canonicity-distribution 112 | """) 113 | -------------------------------------------------------------------------------- /triplet/compute-concepts.lp: -------------------------------------------------------------------------------- 1 | edge(X,Y) :- edge(Y,X). % add symmetry 2 | edge(X,X) :- edge(X,_). % add reflexivity 3 | ext(X) :- edge(X,_) ; edge(X,Y): int(Y). 4 | int(Y) :- edge(_,Y) ; edge(X,Y): ext(X). 5 | #show ext/1. 6 | #show int/1. 7 | -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_allindex_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_allindex_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_allindex_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_formal_concept_per_score_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_formal_concept_per_score_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_formal_concept_per_score_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_formal_concept_per_score_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_formal_concept_per_score_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_allindex_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_allindex_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_allindex_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_2-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_matrixdb_CORE27_example__a_0-_b_0-_c_3-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_matrixdb_CORE27_example__a_3-_b_3-_c_0-.png -------------------------------------------------------------------------------- /triplet/out/number_triplet_concept_per_score_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aluriak/PowerGrASP/2b601e40c483dcc1dc1eb27ac31d76bbc99e7e94/triplet/out/number_triplet_concept_per_score_miRNA_mRNA_diff-no3019__a_0-_b_0-_c_0-.png -------------------------------------------------------------------------------- /triplet/search-byconcept.lp: -------------------------------------------------------------------------------- 1 | % Search for a maximal triplet, using concept method. 2 | % input: edge(X,Y): X is linked to Y 3 | rel(X,Y) :- edge(X,Y). 4 | 5 | % Maximization: 6 | % nb(a,Na) :- Na = {a(_)}. 7 | % nb(b,Nb) :- Nb = {b(_)}. 8 | % nb(c,Nc) :- Nc = {c(_)}. 9 | % cover(ab,N) :- N=Na*Nb ; nb(a,Na) ; nb(b,Nb). 10 | % cover(ac,N) :- N=Na*Nc ; nb(a,Na) ; nb(c,Nc). 11 | % cover(bc,N) :- N=Nb*Nc ; nb(b,Nb) ; nb(c,Nc). 12 | % cover(cc,N) :- N=(Nc*(Nc-1))/2 ; nb(c,Nc). 13 | 14 | % cover(N) :- N=#sum{X:cover(_,X)}. 15 | % cover(N) :- N=(Na*Nb)+(Na*Nc)+(Nb*Nc)+(Nc*(Nc-1))/2 ; Na = {a(_)} ; Nb = {b(_)} ; Nc = {c(_)}. 16 | 17 | % #maximize{N:cover(N)}. 18 | #show a/1. 19 | #show b/1. 20 | #show c/1. 21 | 22 | 23 | #const min_a=0. 24 | #const min_b=0. 25 | #const min_c=0. 26 | #const max_a=#sup. 27 | #const max_b=#sup. 28 | #const max_c=#sup. 29 | 30 | :- {a(_)}min_a-1. 31 | :- {b(_)}min_b-1. 32 | :- {c(_)}min_c-1. 33 | :- max_a+1{a(_)}. 34 | :- max_b+1{b(_)}. 35 | :- max_c+1{c(_)}. 36 | 37 | 38 | % Mining of triplet concepts, by deriving a triplet from each formal concept 39 | % found in the graph context with all reflexive edges. 40 | % Don't care positions to yield triplet concepts seems to not be necessary. 41 | 42 | 43 | % Ensure symmetry of the input relation. 44 | rel(X,Y) :- rel(Y,X). 45 | rel(X,X) :- rel(X,_). % use all reflexive edges 46 | 47 | % Mine formal concepts. 48 | obj(O) :- rel(O,_) ; rel(O,A): att(A). 49 | att(A) :- rel(A,_) ; rel(O,A): obj(O). 50 | 51 | % Convert formal concept as triplet. 52 | a(O) :- obj(O) ; not att(O). 53 | b(A) :- att(A) ; not obj(A). 54 | c(C) :- obj(C) ; att(C). 55 | 56 | % break symmetry 57 | :- b(A) ; A