├── .gitignore ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── bin ├── cat_imagenet_tree.sh ├── install_mvn.sh ├── launch_inf.sh ├── launch_predict_only.sh ├── launch_predict_only_imagenet.sh ├── launch_samples.sh ├── run_inf.sh ├── run_predict_only.sh ├── sample_triples.sh ├── score_tree.sh └── setup.sh ├── config ├── aloi │ ├── aloi.json │ └── build_samples.json ├── covtype │ ├── build_samples.json │ └── covtype.json ├── glass │ ├── build_samples.json │ └── glass.json └── ilsvrc │ ├── build_samples.json │ └── ilsvrc.json ├── data ├── covtype.evalpts5k └── imagenet_eval_pts.ids ├── env.yml ├── pom.xml └── src ├── python └── ghhc │ ├── inference │ ├── __init__.py │ ├── run_inference.py │ └── run_predict_only.py │ ├── model │ ├── __init__.py │ └── ghhc.py │ └── util │ ├── Config.py │ ├── __init__.py │ ├── eval_dp.py │ ├── initializers.py │ ├── io.py │ ├── load.py │ └── sample_triples.py └── scala └── ghhc ├── eval └── EvalDendrogramPurity.scala └── package.scala /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | .idea 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # SageMath parsed files 85 | *.sage.py 86 | 87 | # Environments 88 | .env 89 | .venv 90 | env/ 91 | venv/ 92 | ENV/ 93 | env.bak/ 94 | venv.bak/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | .spyproject 99 | 100 | # Rope project settings 101 | .ropeproject 102 | 103 | # mkdocs documentation 104 | /site 105 | 106 | # mypy 107 | .mypy_cache/ 108 | 109 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | hyperbolic_hierarchical_clustering 2 | 3 | This software is Copyright (C) 2019 Authors of gHHC 4 | and is licensed under the 5 | terms of the Apache License, Version 2.0 (see LICENSE.txt) or (at your option) any subsequent version. 6 | 7 | The license is approved by the Open Source Initiative, and is available 8 | from their website at http://www.opensource.org. 9 | 10 | THIRD PARTY COMPONENTS 11 | 12 | factorie is Copyright (C) 2008-2019 University of Massachusetts 13 | Amherst, Department of Computer Science, and is licensed under the 14 | terms of the Apache License, Version 2.0 15 | 16 | xcluster is Copyright (C) 2017-2019 University of Massachusetts 17 | Amherst, Department of Computer Science, and is licensed under the 18 | terms of the Apache License, Version 2.0 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # gHHC 3 | 4 | Code for: [Gradient-based Hierarchical Clustering using Continuous Representations of Trees in Hyperbolic Space](https://dl.acm.org/citation.cfm?id=3330997). Nicholas Monath, Manzil Zaheer, Daniel Silva, Andrew McCallum, Amr Ahmed. KDD 2019. 5 | 6 | ## Setup 7 | 8 | In each shell session, run: 9 | 10 | ``` 11 | source bin/setup.sh 12 | ``` 13 | 14 | to set environment variables. 15 | 16 | Install jq (if not already installed): https://stedolan.github.io/jq/ 17 | 18 | Install maven (if not already installed): 19 | 20 | ``` 21 | sh bin/install_mvn.sh 22 | ``` 23 | 24 | Install python dependencies: 25 | 26 | ``` 27 | conda create -n env_ghhc pip python=3.6 28 | source activate env_ghhc 29 | # Either (linux) 30 | wget https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.12.0-cp36-cp36m-linux_x86_64.whl 31 | pip install tensorflow-1.12.0-cp36-cp36m-linux_x86_64.whl 32 | # or (mac) 33 | wget https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.12.0-py3-none-any.whl 34 | pip install tensorflow-1.12.0-py3-none-any.whl 35 | conda install scikit-learn 36 | conda install tensorflow-base=1.13.1 37 | ``` 38 | 39 | See [env.yml](env.yml) for a complete list of dependencies if you run into issues 40 | with the above. 41 | 42 | Build scala code: 43 | 44 | ``` 45 | mvn clean package 46 | ``` 47 | 48 | Note you may need to set `JAVA_HOME` and `JAVA_HOME_8` on your system. 49 | 50 | ALOI and Glass are downloadable from: https://github.com/iesl/xcluster 51 | 52 | Covtype is available here: https://archive.ics.uci.edu/ml/datasets/covertype 53 | 54 | Contact me regarding the ImageNet data. 55 | 56 | ## Clustering Experiments 57 | 58 | ### Step 1. Building triples for inference 59 | 60 | Sample triples of datapoints that will be used for inference: 61 | 62 | On a compute machine: 63 | 64 | ``` 65 | sh bin/sample_triples.sh config/glass/build_samples.json 66 | ``` 67 | 68 | Using slurm cluster manager: 69 | 70 | ``` 71 | sh bin/launch_samples.sh config/glass/build_samples.json 72 | ``` 73 | 74 | Note the above example is for the `glass` dataset, but the same 75 | procedure and scripts are available for all datasets. 76 | 77 | ### Step 2. Run Inference 78 | 79 | Update the representations of the internal nodes of the tree structure. 80 | 81 | On a compute machine: 82 | 83 | ``` 84 | sh bin/run_inf.sh config/glass/glass.json 85 | ``` 86 | 87 | Using slurm cluster manager: 88 | 89 | ``` 90 | sh bin/launch_inf.sh config/glass/glass.json 91 | ``` 92 | 93 | This will create a directory in `exp_out/dataset_name/ghhc/timestamp` 94 | containing the internal node parameters and configs to run the next step. 95 | For example, this would create the following: 96 | 97 | ``` 98 | exp_out/glass/ghhc/2019-11-29-20-13-29-alg_name=ghhc-init_method=randompts-tree_learning_rate=0.01-loss=sigmoid-lca_type=conditional-num_samples=50000-batch_size=500-struct_prior=pcn 99 | ``` 100 | 101 | ### Step 3. Final clustering 102 | 103 | Produce assignment of datapoints in the hierarchical clustering and 104 | produce internal structure. 105 | 106 | For datasets other than ImageNet: 107 | 108 | On a compute machine: 109 | 110 | ``` 111 | # Generally: 112 | sh bin/run_predict_only.sh exp_out/data/ghhc/timestap/config.json data/datasetname/data_to_run_on.tsv 113 | 114 | # For example: 115 | sh bin/run_predict_only.sh exp_out/glass/ghhc/2019-11-29-20-13-29-alg_name=ghhc-init_method=randompts-tree_learning_rate=0.01-loss=sigmoid-lca_type=conditional-num_samples=50000-batch_size=500-struct_prior=pcn/config.json data/glass/glass.tsv 116 | ``` 117 | 118 | Using slurm cluster manager: 119 | 120 | ``` 121 | sh bin/launch_predict_only.sh exp_out/glass/ghhc/2019-11-29-20-13-29-alg_name=ghhc-init_method=randompts-tree_learning_rate=0.01-loss=sigmoid-lca_type=conditional-num_samples=50000-batch_size=500-struct_prior=pcn/config.json data/glass/glass.tsv 122 | ``` 123 | 124 | This will create a file: `exp_out/glass/ghhc/2019-11-29-20-13-29-alg_name=ghhc-init_method=randompts-tree_learning_rate=0.01-loss=sigmoid-lca_type=conditional-num_samples=50000-batch_size=500-struct_prior=pcn/results/tree.tsv` 125 | which can be evaluated using 126 | 127 | ``` 128 | sh bin/score_tree.sh exp_out/glass/ghhc/2019-11-29-20-13-29-alg_name=ghhc-init_method=randompts-tree_learning_rate=0.01-loss=sigmoid-lca_type=conditional-num_samples=50000-batch_size=500-struct_prior=pcn/results/tree.tsv 129 | ``` 130 | 131 | When evaluating the tree for covtype, use the expected dendrogram purity point id file from the data directory: 132 | 133 | ``` 134 | sh bin/score_tree.sh /path/to/tree.tsv ghhc covtype $num_threads data/covtype.evalpts5k 135 | ``` 136 | 137 | 138 | For ImageNet: 139 | 140 | ``` 141 | sh bin/launch_predict_only_imagenet.sh exp_out/ilsvrc/ghhc/2019-11-29-08-04-23-alg_name=ghhc-init_method=randhac-tree_learning_rate=0.01-loss=sigmoid-lca_type=conditional-num_samples=50000-batch_size=100-struct_prior=pcn/config.json data/ilsvrc/ilsvrc12.tsv.1 cpu 32000 142 | ``` 143 | 144 | This assumes that the ImageNet data file has been split into 13 files: 145 | 146 | ``` 147 | data/ilsvrc/ilsvrc12.tsv.1.split_aa 148 | data/ilsvrc/ilsvrc12.tsv.1.split_ab 149 | ... 150 | data/ilsvrc/ilsvrc12.tsv.1.split_am 151 | ``` 152 | 153 | Then when all jobs finish, concatenate results: 154 | 155 | ``` 156 | sh bin/cat_imagenet_tree.sh exp_out/ilsvrc/ghhc/2019-11-29-08-04-23-alg_name=ghhc-init_method=randhac-tree_learning_rate=0.01-loss=sigmoid-lca_type=conditional-num_samples=50000-batch_size=100-struct_prior=pcn/results/ 157 | ``` 158 | 159 | This will create a file containing the entire tree: 160 | 161 | ``` 162 | exp_out/ilsvrc/ghhc/2019-11-29-08-04-23-alg_name=ghhc-init_method=randhac-tree_learning_rate=0.01-loss=sigmoid-lca_type=conditional-num_samples=50000-batch_size=100-struct_prior=pcn/results/tree.tsv 163 | ``` 164 | 165 | which can be evaluated using: 166 | 167 | ``` 168 | sh bin/score_tree.sh exp_out/ilsvrc/ghhc/2019-11-29-08-04-23-alg_name=ghhc-init_method=randhac-tree_learning_rate=0.01-loss=sigmoid-lca_type=conditional-num_samples=50000-batch_size=100-struct_prior=pcn/results/tree.tsv ghhc ilsvrc12 $num_threads data/imagenet_eval_pts.ids 169 | ``` 170 | 171 | ## Citation 172 | 173 | ``` 174 | @inproceedings{Monath:2019:GHC:3292500.3330997, 175 | author = {Monath, Nicholas and Zaheer, Manzil and Silva, Daniel and McCallum, Andrew and Ahmed, Amr}, 176 | title = {Gradient-based Hierarchical Clustering Using Continuous Representations of Trees in Hyperbolic Space}, 177 | booktitle = {Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery \& Data Mining}, 178 | series = {KDD '19}, 179 | year = {2019}, 180 | isbn = {978-1-4503-6201-6}, 181 | location = {Anchorage, AK, USA}, 182 | pages = {714--722}, 183 | numpages = {9}, 184 | url = {http://doi.acm.org/10.1145/3292500.3330997}, 185 | doi = {10.1145/3292500.3330997}, 186 | acmid = {3330997}, 187 | publisher = {ACM}, 188 | address = {New York, NY, USA}, 189 | keywords = {clustering, gradient-based clustering, hierarchical clustering}, 190 | } 191 | ``` 192 | 193 | ## License 194 | 195 | Apache License, Version 2.0 196 | 197 | ## Questions / Comments / Bugs / Issues 198 | 199 | Please contact Nicholas Monath (nmonath@cs.umass.edu). 200 | 201 | Also, please contact me for access to the data. 202 | 203 | -------------------------------------------------------------------------------- /bin/cat_imagenet_tree.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exu 4 | 5 | results_dir=$1 6 | 7 | pushd $results_dir 8 | cat tree-aa.tsv.leaves tree-ab.tsv.leaves tree-ac.tsv.leaves tree-ad.tsv.leaves tree-ae.tsv.leaves tree-af.tsv.leaves tree-ag.tsv.leaves tree-ah.tsv.leaves tree-ai.tsv.leaves tree-aj.tsv.leaves tree-ak.tsv.leaves tree-al.tsv.leaves tree-am.tsv.leaves tree-aa.tsv.internals > tree.tsv 9 | popd -------------------------------------------------------------------------------- /bin/install_mvn.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -xu 4 | 5 | mkdir $GHHC_ROOT/dep 6 | pushd $GHHC_ROOT/dep 7 | wget http://mirror.cc.columbia.edu/pub/software/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz 8 | tar -xvf apache-maven-3.6.3-bin.tar.gz 9 | popd 10 | -------------------------------------------------------------------------------- /bin/launch_inf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exu 4 | 5 | config=$1 6 | partition=$2 7 | mem=${3:-12000} 8 | 9 | EMAIL=None 10 | TIME=`(date +%Y-%m-%d-%H-%M-%S)` 11 | 12 | threads=`cat $config | jq .threads` 13 | 14 | export MKL_NUM_THREADS=$threads 15 | export OPENBLAS_NUM_THREADS=$threads 16 | export OMP_NUM_THREADS=$threads 17 | 18 | log_dir=logs/inf/$TIME 19 | 20 | mkdir -p $log_dir 21 | 22 | 23 | sbatch -J inf-$TIME \ 24 | -e $log_dir/inf.err \ 25 | -o $log_dir/inf.log \ 26 | --cpus-per-task $threads \ 27 | --partition=$partition \ 28 | --ntasks=1 \ 29 | --nodes=1 \ 30 | --mem=$mem \ 31 | --time=0-08:00 \ 32 | bin/run_inf.sh $config -------------------------------------------------------------------------------- /bin/launch_predict_only.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exu 4 | 5 | config=$1 6 | filename=$2 7 | partition=$3 8 | mem=${4:-12000} 9 | out_file=${5:-"tree.tsv"} 10 | 11 | EMAIL=None 12 | TIME=`(date +%Y-%m-%d-%H-%M-%S)` 13 | 14 | threads=`cat $config | jq .threads` 15 | 16 | export MKL_NUM_THREADS=$threads 17 | export OPENBLAS_NUM_THREADS=$threads 18 | export OMP_NUM_THREADS=$threads 19 | 20 | log_dir=logs/inf/$TIME 21 | 22 | mkdir -p $log_dir 23 | 24 | 25 | sbatch -J inf-po-$TIME \ 26 | -e $log_dir/inf.err \ 27 | -o $log_dir/inf.log \ 28 | --cpus-per-task $threads \ 29 | --partition=$partition \ 30 | --ntasks=1 \ 31 | --nodes=1 \ 32 | --mem=$mem \ 33 | --time=0-08:00 \ 34 | bin/run_predict_only.sh $config $filename $out_file -------------------------------------------------------------------------------- /bin/launch_predict_only_imagenet.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exu 4 | 5 | config=$1 6 | filename=$2 7 | partition=$3 8 | mem=${4:-12000} 9 | 10 | split_names=( "aa" "ab" "ac" "ad" "ae" "af" "ag" "ah" "ai" "aj" "ak" "al" "am" ) 11 | #split_names=( "aa" "ab" "ac" ) 12 | #split_names=( "ad" "ae" "af" "ag" "ah" "ai" "aj" "ak" "al" "am" ) 13 | 14 | for i in "${split_names[@]}" 15 | do 16 | sh bin/launch_predict_only.sh $config "${filename}.split_${i}" $partition $mem "tree-$i.tsv" 17 | sleep 1 18 | done -------------------------------------------------------------------------------- /bin/launch_samples.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exu 4 | 5 | config=$1 6 | partition=$2 7 | mem=${3:-12000} 8 | 9 | threads=`cat $config | jq .threads` 10 | 11 | EMAIL=None 12 | TIME=`(date +%Y-%m-%d-%H-%M-%S)` 13 | 14 | export MKL_NUM_THREADS=$threads 15 | export OPENBLAS_NUM_THREADS=$threads 16 | export OMP_NUM_THREADS=$threads 17 | 18 | log_dir=logs/samples/$TIME 19 | 20 | mkdir -p $log_dir 21 | 22 | 23 | sbatch -J samples-$TIME \ 24 | -e $log_dir/samples.err \ 25 | -o $log_dir/samples.log \ 26 | --cpus-per-task $threads \ 27 | --partition=$partition \ 28 | --ntasks=1 \ 29 | --nodes=1 \ 30 | --mem=$mem \ 31 | --time=0-10:00 \ 32 | bin/sample_triples.sh $config -------------------------------------------------------------------------------- /bin/run_inf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exu 4 | 5 | input=$1 6 | 7 | python -m ghhc.inference.run_inference $input -------------------------------------------------------------------------------- /bin/run_predict_only.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exu 4 | 5 | input=$1 6 | filename=$2 7 | out_file=${3:-"tree.tsv"} 8 | 9 | 10 | python -m ghhc.inference.run_predict_only --config $input --data_filename $filename --output_filename $out_file -------------------------------------------------------------------------------- /bin/sample_triples.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exu 4 | 5 | config=$1 6 | 7 | python -m ghhc.util.sample_triples $config -------------------------------------------------------------------------------- /bin/score_tree.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exu 4 | 5 | tree=$1 6 | algorithm=${2:-alg} 7 | dataset=${3:-dataset} 8 | threads=${4:-24} 9 | expected_dp_point_file=${5:-"None"} 10 | 11 | java -Xmx50G -cp target/ghhc-0.1-SNAPSHOT-jar-with-dependencies.jar ghhc.eval.EvalDendrogramPurity \ 12 | --input $tree --algorithm $algorithm --dataset $dataset --threads $threads \ 13 | --print true --id-file $expected_dp_point_file -------------------------------------------------------------------------------- /bin/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export GHHC_ROOT=`pwd` 4 | 5 | export PYTHONPATH=$GHHC_ROOT/src/python:$PYTHONPATH 6 | export PATH=$GHHC_ROOT/dep/apache-maven-3.6.3/bin:$PATH 7 | -------------------------------------------------------------------------------- /config/aloi/aloi.json: -------------------------------------------------------------------------------- 1 | { 2 | "alg_name": "ghhc", 3 | "batch_size": 100, 4 | "dataset_name": "aloi", 5 | "dev_every": 10000, 6 | "dev_file": "data/aloi/aloi.5k.tsv", 7 | "dev_points_file": "None", 8 | "episode_size": 5000, 9 | "exp_out_base": "exp_out", 10 | "gamma": 0.5, 11 | "inference_file": "data/aloi/aloi.tsv.1", 12 | "init_method": "randhac", 13 | "lca_type": "conditional", 14 | "loss": "sigmoid", 15 | "max_norm": 0.9, 16 | "nn_batch_size": 1000, 17 | "num_internals": 40000, 18 | "num_iterations": 5, 19 | "num_samples": 50000, 20 | "percent_random": 0.1, 21 | "random_pts_scale": 0.8 , 22 | "sample_dataset": null, 23 | "sample_file": "data/aloi/aloi.ghhc_samples.npy", 24 | "sample_outfile": null, 25 | "save_dev_pics": false, 26 | "save_every": 100000, 27 | "shuffle": true, 28 | "threads": 22, 29 | "tree_learning_rate": 0.01, 30 | "triplet_k": 5, 31 | "unit_norm": true, 32 | "zero_mean": true, 33 | "struct_prior_every": 250, 34 | "struct_prior": "pcn", 35 | "num_struct_prior_batches": 25 36 | } -------------------------------------------------------------------------------- /config/aloi/build_samples.json: -------------------------------------------------------------------------------- 1 | { 2 | "dataset_name": "aloi", 3 | "sample_dataset": "data/aloi/aloi.tsv.1", 4 | "sample_outfile": "data/aloi/aloi.ghhc_samples.npy", 5 | "num_samples": 500000, 6 | "percent_random": 0.0, 7 | "threads": 22 8 | } -------------------------------------------------------------------------------- /config/covtype/build_samples.json: -------------------------------------------------------------------------------- 1 | { 2 | "dataset_name": "covtype", 3 | "sample_dataset": "data/covtype/covtype.50k.tsv", 4 | "sample_outfile": "data/covtype/covtype.50k.ghhc_samples.npy", 5 | "num_samples": 300000, 6 | "threads": 22, 7 | "percent_random": 0.0 8 | } -------------------------------------------------------------------------------- /config/covtype/covtype.json: -------------------------------------------------------------------------------- 1 | { 2 | "alg_name": "ghhc", 3 | "batch_size": 100, 4 | "dataset_name": "covtype", 5 | "dev_every": 10000, 6 | "dev_file": "data/covtype/covtype.5k.tsv", 7 | "dev_points_file": "None", 8 | "episode_size": 5000, 9 | "exp_out_base": "exp_out", 10 | "gamma": 0.5, 11 | "inference_file": "data/covtype/covtype.50k.tsv", 12 | "init_method": "randhac", 13 | "lca_type": "conditional", 14 | "loss": "sigmoid", 15 | "max_norm": 0.9, 16 | "nn_batch_size": 1000, 17 | "num_internals": 5000, 18 | "num_iterations": 10, 19 | "num_samples": 50000, 20 | "percent_random": 0.1, 21 | "random_pts_scale": 0.8 , 22 | "random_seed": 1451, 23 | "sample_dataset": null, 24 | "sample_file": "data/covtype/covtype.50k.ghhc_samples.npy", 25 | "sample_outfile": null, 26 | "save_dev_pics": false, 27 | "save_every": 100000, 28 | "shuffle": true, 29 | "threads": 22, 30 | "tree_learning_rate": 0.01, 31 | "triplet_k": 5, 32 | "unit_norm": true, 33 | "zero_mean": true, 34 | "struct_prior_every": 1000, 35 | "struct_prior": "pcn", 36 | "num_struct_prior_batches": 100 37 | } -------------------------------------------------------------------------------- /config/glass/build_samples.json: -------------------------------------------------------------------------------- 1 | { 2 | "dataset_name": "glass", 3 | "sample_dataset": "data/glass/glass.tsv", 4 | "sample_outfile": "data/glass/glass.ghhc_samples.npy", 5 | "threads": 4 6 | } -------------------------------------------------------------------------------- /config/glass/glass.json: -------------------------------------------------------------------------------- 1 | { 2 | "dataset_name": "glass", 3 | "inference_file": "data/glass/glass.tsv", 4 | "dev_file": "data/glass/glass.tsv", 5 | "dev_every": 10000, 6 | "sample_file": "data/glass/glass.ghhc_samples.npy", 7 | "num_internals": 64, 8 | "threads": 4 9 | } -------------------------------------------------------------------------------- /config/ilsvrc/build_samples.json: -------------------------------------------------------------------------------- 1 | { 2 | "dataset_name": "ilsvrc", 3 | "sample_dataset": "data/ilsvrc/ilsvrc12.50k.tsv", 4 | "sample_outfile": "data/ilsvrc/ilsvrc12.50k.ghhc_samples.npy", 5 | "num_samples": 300000, 6 | "threads": 22, 7 | "percent_random": 0.0 8 | } -------------------------------------------------------------------------------- /config/ilsvrc/ilsvrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "alg_name": "ghhc", 3 | "batch_size": 100, 4 | "dataset_name": "ilsvrc", 5 | "dev_every": 10000, 6 | "dev_file": "data/ilsvrc/ilsvrc12.5k.tsv", 7 | "dev_points_file": "None", 8 | "episode_size": 5000, 9 | "exp_out_base": "exp_out", 10 | "gamma": 0.5, 11 | "inference_file": "data/ilsvrc/ilsvrc12.50k.tsv", 12 | "init_method": "randhac", 13 | "lca_type": "conditional", 14 | "loss": "sigmoid", 15 | "loss_type": "compute_soft_loss_three_sparsemax", 16 | "max_norm": 0.9, 17 | "nn_batch_size": 1000, 18 | "num_internals": 20000, 19 | "num_iterations": 10, 20 | "num_samples": 50000, 21 | "percent_random": 0.1, 22 | "random_pts_scale": 0.8 , 23 | "sample_dataset": null, 24 | "sample_file": "data/ilsvrc/ilsvrc12.50k.ghhc_samples.npy", 25 | "sample_outfile": null, 26 | "save_dev_pics": false, 27 | "save_every": 100000, 28 | "shuffle": true, 29 | "threads": 22, 30 | "tree_learning_rate": 0.01, 31 | "triplet_k": 5, 32 | "unit_norm": true, 33 | "zero_mean": true, 34 | "struct_prior_every": 5000, 35 | "struct_prior": "pcn", 36 | "num_struct_prior_batches": 100 37 | } -------------------------------------------------------------------------------- /data/covtype.evalpts5k: -------------------------------------------------------------------------------- 1 | 13993 2 | 104991 3 | 89769 4 | 232503 5 | 318623 6 | 361776 7 | 257285 8 | 507206 9 | 262982 10 | 461493 11 | 3152 12 | 323632 13 | 59203 14 | 138675 15 | 187478 16 | 299388 17 | 137665 18 | 242625 19 | 353839 20 | 423959 21 | 9891 22 | 444187 23 | 17334 24 | 150662 25 | 423867 26 | 319346 27 | 527354 28 | 390147 29 | 287552 30 | 204990 31 | 285914 32 | 65171 33 | 1094 34 | 508459 35 | 161722 36 | 46799 37 | 498771 38 | 330456 39 | 419492 40 | 62598 41 | 18414 42 | 520603 43 | 368022 44 | 369989 45 | 474302 46 | 87955 47 | 418224 48 | 342932 49 | 157850 50 | 163820 51 | 549090 52 | 494486 53 | 417438 54 | 71247 55 | 124274 56 | 259612 57 | 48076 58 | 572160 59 | 550677 60 | 307567 61 | 104083 62 | 394470 63 | 54661 64 | 164806 65 | 50949 66 | 336968 67 | 552700 68 | 12672 69 | 324451 70 | 489363 71 | 529725 72 | 417900 73 | 13518 74 | 466051 75 | 280427 76 | 449118 77 | 290543 78 | 297050 79 | 415250 80 | 425092 81 | 351474 82 | 239283 83 | 6563 84 | 25416 85 | 259516 86 | 410754 87 | 567437 88 | 289200 89 | 90578 90 | 452127 91 | 222144 92 | 159672 93 | 235539 94 | 552057 95 | 221480 96 | 255772 97 | 303373 98 | 406871 99 | 498140 100 | 12661 101 | 343842 102 | 185591 103 | 319422 104 | 140376 105 | 265242 106 | 74381 107 | 272825 108 | 360245 109 | 485185 110 | 73173 111 | 414292 112 | 273792 113 | 419536 114 | 36978 115 | 75237 116 | 188839 117 | 281645 118 | 417584 119 | 441454 120 | 91411 121 | 338334 122 | 538409 123 | 13417 124 | 149734 125 | 137482 126 | 135076 127 | 479475 128 | 446565 129 | 308191 130 | 154845 131 | 372791 132 | 65844 133 | 139204 134 | 524839 135 | 445304 136 | 292010 137 | 579658 138 | 76362 139 | 12423 140 | 282277 141 | 539832 142 | 204890 143 | 227526 144 | 291807 145 | 108398 146 | 216317 147 | 110832 148 | 339779 149 | 89658 150 | 189962 151 | 25985 152 | 220412 153 | 294575 154 | 318596 155 | 549912 156 | 87174 157 | 545421 158 | 447054 159 | 378753 160 | 509243 161 | 44012 162 | 351707 163 | 163834 164 | 305816 165 | 89875 166 | 194729 167 | 28695 168 | 539953 169 | 219935 170 | 193040 171 | 251974 172 | 302035 173 | 423376 174 | 310718 175 | 523156 176 | 58497 177 | 53787 178 | 189849 179 | 538691 180 | 186206 181 | 287717 182 | 356605 183 | 434031 184 | 346394 185 | 9268 186 | 239837 187 | 478531 188 | 256604 189 | 113744 190 | 448708 191 | 324133 192 | 546717 193 | 98353 194 | 151890 195 | 141589 196 | 219761 197 | 542281 198 | 434780 199 | 432174 200 | 545185 201 | 555701 202 | 54553 203 | 374595 204 | 158250 205 | 572436 206 | 576640 207 | 90970 208 | 436821 209 | 183728 210 | 106114 211 | 404903 212 | 243733 213 | 369940 214 | 257680 215 | 163101 216 | 243321 217 | 302758 218 | 40359 219 | 308436 220 | 227212 221 | 16819 222 | 439342 223 | 424494 224 | 334718 225 | 457153 226 | 579190 227 | 183836 228 | 461612 229 | 211841 230 | 378092 231 | 139706 232 | 417142 233 | 474665 234 | 242151 235 | 235873 236 | 560733 237 | 368136 238 | 244660 239 | 99337 240 | 106155 241 | 112964 242 | 79909 243 | 570872 244 | 215306 245 | 558553 246 | 556070 247 | 28351 248 | 5165 249 | 240585 250 | 409321 251 | 563346 252 | 176383 253 | 456235 254 | 99719 255 | 378983 256 | 68863 257 | 1227 258 | 429989 259 | 380738 260 | 556076 261 | 170687 262 | 496314 263 | 149308 264 | 190487 265 | 303750 266 | 276169 267 | 257909 268 | 343493 269 | 396975 270 | 66078 271 | 63795 272 | 564395 273 | 192965 274 | 558954 275 | 411023 276 | 15373 277 | 542366 278 | 470387 279 | 490612 280 | 430897 281 | 577257 282 | 253968 283 | 359604 284 | 468252 285 | 372436 286 | 544906 287 | 328631 288 | 311500 289 | 426229 290 | 189866 291 | 502699 292 | 381349 293 | 356045 294 | 501507 295 | 206631 296 | 400462 297 | 437314 298 | 316729 299 | 186407 300 | 532840 301 | 175553 302 | 354904 303 | 127058 304 | 425625 305 | 112215 306 | 96956 307 | 323485 308 | 426156 309 | 514743 310 | 478087 311 | 17394 312 | 296283 313 | 551165 314 | 341282 315 | 159829 316 | 211099 317 | 467458 318 | 24869 319 | 534854 320 | 66910 321 | 221134 322 | 310392 323 | 395726 324 | 16030 325 | 138695 326 | 110104 327 | 483220 328 | 344229 329 | 499495 330 | 228326 331 | 189379 332 | 468866 333 | 141850 334 | 203665 335 | 471466 336 | 413862 337 | 143259 338 | 87804 339 | 100105 340 | 274176 341 | 181277 342 | 370000 343 | 451151 344 | 92801 345 | 552918 346 | 132664 347 | 88070 348 | 315631 349 | 410864 350 | 198896 351 | 367707 352 | 452281 353 | 10419 354 | 477703 355 | 286864 356 | 166904 357 | 497478 358 | 369421 359 | 192913 360 | 236972 361 | 503726 362 | 236786 363 | 162657 364 | 535932 365 | 19415 366 | 360944 367 | 305133 368 | 46589 369 | 385946 370 | 121885 371 | 312616 372 | 386987 373 | 108968 374 | 396839 375 | 425387 376 | 81021 377 | 192120 378 | 301420 379 | 210067 380 | 363413 381 | 359989 382 | 254338 383 | 260107 384 | 146605 385 | 172475 386 | 84104 387 | 501377 388 | 21241 389 | 268265 390 | 515127 391 | 25466 392 | 122510 393 | 178871 394 | 434519 395 | 184593 396 | 454407 397 | 77621 398 | 299112 399 | 309618 400 | 100544 401 | 43556 402 | 502291 403 | 449891 404 | 195860 405 | 196955 406 | 76592 407 | 566329 408 | 396943 409 | 208793 410 | 53030 411 | 242905 412 | 103801 413 | 253783 414 | 119916 415 | 501799 416 | 414432 417 | 249116 418 | 60703 419 | 325083 420 | 414061 421 | 240147 422 | 247962 423 | 239112 424 | 323583 425 | 362845 426 | 273680 427 | 442606 428 | 409407 429 | 178021 430 | 153065 431 | 427703 432 | 388043 433 | 206931 434 | 484309 435 | 415381 436 | 315239 437 | 577247 438 | 335810 439 | 575621 440 | 348108 441 | 4517 442 | 521312 443 | 166920 444 | 73694 445 | 129567 446 | 482918 447 | 177341 448 | 495998 449 | 409569 450 | 288732 451 | 75517 452 | 138431 453 | 479139 454 | 160811 455 | 286170 456 | 342830 457 | 567135 458 | 62750 459 | 10146 460 | 301587 461 | 233027 462 | 302046 463 | 570827 464 | 439626 465 | 3309 466 | 504247 467 | 55567 468 | 571967 469 | 552828 470 | 172815 471 | 551412 472 | 354620 473 | 255068 474 | 174089 475 | 213216 476 | 354455 477 | 41365 478 | 2809 479 | 492291 480 | 103138 481 | 411854 482 | 200188 483 | 499028 484 | 489844 485 | 522631 486 | 160285 487 | 388737 488 | 394150 489 | 443814 490 | 358047 491 | 189662 492 | 464635 493 | 3738 494 | 253254 495 | 506554 496 | 454606 497 | 145322 498 | 561188 499 | 247653 500 | 567896 501 | 310784 502 | 445369 503 | 161556 504 | 281988 505 | 253419 506 | 365829 507 | 152127 508 | 381132 509 | 440121 510 | 414707 511 | 569338 512 | 38371 513 | 477002 514 | 574239 515 | 210513 516 | 503459 517 | 100256 518 | 384119 519 | 433484 520 | 474458 521 | 553894 522 | 278758 523 | 148853 524 | 249795 525 | 517682 526 | 378804 527 | 198311 528 | 386466 529 | 296070 530 | 51968 531 | 206416 532 | 423975 533 | 390421 534 | 551280 535 | 20646 536 | 525695 537 | 467467 538 | 347393 539 | 519739 540 | 160283 541 | 202616 542 | 452794 543 | 516422 544 | 117780 545 | 354594 546 | 192251 547 | 519257 548 | 274652 549 | 378822 550 | 136521 551 | 250458 552 | 289731 553 | 229571 554 | 280047 555 | 539072 556 | 172411 557 | 201407 558 | 214674 559 | 35906 560 | 540360 561 | 92800 562 | 34662 563 | 400703 564 | 103688 565 | 516889 566 | 66074 567 | 208538 568 | 538744 569 | 230649 570 | 305222 571 | 546583 572 | 220189 573 | 306653 574 | 395364 575 | 13988 576 | 103065 577 | 207410 578 | 546664 579 | 198287 580 | 338724 581 | 234980 582 | 218296 583 | 548951 584 | 312862 585 | 225245 586 | 552195 587 | 456783 588 | 158466 589 | 573859 590 | 573874 591 | 68177 592 | 540808 593 | 543376 594 | 332108 595 | 387730 596 | 537972 597 | 140472 598 | 317118 599 | 329846 600 | 206753 601 | 383074 602 | 188917 603 | 415764 604 | 80235 605 | 496197 606 | 307114 607 | 439396 608 | 478803 609 | 260340 610 | 116766 611 | 549297 612 | 217147 613 | 93357 614 | 54272 615 | 521963 616 | 6876 617 | 487382 618 | 198056 619 | 313525 620 | 286314 621 | 476810 622 | 554255 623 | 538569 624 | 327938 625 | 457336 626 | 143934 627 | 128302 628 | 506919 629 | 341676 630 | 463182 631 | 61125 632 | 462257 633 | 414484 634 | 217266 635 | 475064 636 | 250413 637 | 498193 638 | 403434 639 | 234714 640 | 338164 641 | 533204 642 | 148990 643 | 213887 644 | 573267 645 | 229131 646 | 88254 647 | 430563 648 | 273091 649 | 15076 650 | 320500 651 | 134088 652 | 243572 653 | 72391 654 | 340089 655 | 513704 656 | 496703 657 | 552174 658 | 576937 659 | 512683 660 | 456387 661 | 480379 662 | 179638 663 | 497177 664 | 124367 665 | 559757 666 | 288902 667 | 226752 668 | 251521 669 | 78857 670 | 452550 671 | 158261 672 | 274589 673 | 67743 674 | 341735 675 | 95058 676 | 183880 677 | 579745 678 | 42420 679 | 562281 680 | 396608 681 | 156377 682 | 111605 683 | 149594 684 | 404685 685 | 421775 686 | 143450 687 | 554582 688 | 484522 689 | 298306 690 | 257197 691 | 89521 692 | 269851 693 | 335688 694 | 375852 695 | 406375 696 | 331623 697 | 160523 698 | 415410 699 | 473136 700 | 185755 701 | 75752 702 | 501887 703 | 381573 704 | 533685 705 | 469322 706 | 344030 707 | 126852 708 | 466248 709 | 26629 710 | 151042 711 | 115515 712 | 104341 713 | 236722 714 | 398740 715 | 367834 716 | 340941 717 | 208735 718 | 542736 719 | 110303 720 | 574926 721 | 517730 722 | 165050 723 | 145880 724 | 393702 725 | 197437 726 | 304196 727 | 574258 728 | 379777 729 | 450188 730 | 335287 731 | 320937 732 | 297350 733 | 5158 734 | 343915 735 | 3036 736 | 44492 737 | 476662 738 | 438712 739 | 483006 740 | 368774 741 | 422027 742 | 196562 743 | 527292 744 | 203459 745 | 306094 746 | 61014 747 | 30149 748 | 191009 749 | 134022 750 | 140845 751 | 190297 752 | 387783 753 | 218989 754 | 278806 755 | 183481 756 | 4445 757 | 553285 758 | 534914 759 | 71643 760 | 572493 761 | 112106 762 | 453984 763 | 133264 764 | 184311 765 | 499523 766 | 516346 767 | 374266 768 | 319773 769 | 542834 770 | 42458 771 | 484825 772 | 338362 773 | 316117 774 | 132536 775 | 362528 776 | 489453 777 | 226305 778 | 140822 779 | 253591 780 | 500969 781 | 329231 782 | 334755 783 | 150149 784 | 248693 785 | 225782 786 | 318685 787 | 436494 788 | 173042 789 | 392328 790 | 165094 791 | 351111 792 | 125571 793 | 443150 794 | 82080 795 | 465841 796 | 265927 797 | 163816 798 | 13337 799 | 344145 800 | 76633 801 | 310288 802 | 255432 803 | 499681 804 | 557872 805 | 237656 806 | 137773 807 | 42437 808 | 523124 809 | 61059 810 | 52505 811 | 214007 812 | 200924 813 | 249724 814 | 512473 815 | 336576 816 | 17455 817 | 308727 818 | 284233 819 | 102364 820 | 399605 821 | 473883 822 | 532210 823 | 251292 824 | 322940 825 | 132525 826 | 502728 827 | 75883 828 | 86566 829 | 555740 830 | 210094 831 | 471726 832 | 91154 833 | 179323 834 | 223907 835 | 542491 836 | 342344 837 | 215634 838 | 465781 839 | 523538 840 | 570866 841 | 128234 842 | 550229 843 | 576801 844 | 310811 845 | 376272 846 | 166056 847 | 458349 848 | 409325 849 | 537329 850 | 348065 851 | 277568 852 | 459415 853 | 576883 854 | 111387 855 | 549375 856 | 572911 857 | 159017 858 | 443022 859 | 172504 860 | 116554 861 | 135690 862 | 361775 863 | 426911 864 | 70500 865 | 412330 866 | 437834 867 | 424390 868 | 61072 869 | 500273 870 | 444127 871 | 198133 872 | 191177 873 | 60710 874 | 262305 875 | 144128 876 | 447874 877 | 134905 878 | 572461 879 | 63332 880 | 140339 881 | 437363 882 | 433545 883 | 268428 884 | 380576 885 | 374864 886 | 23027 887 | 569995 888 | 87865 889 | 455240 890 | 53133 891 | 113655 892 | 230685 893 | 48907 894 | 264319 895 | 321817 896 | 148306 897 | 427383 898 | 413324 899 | 532060 900 | 86104 901 | 540707 902 | 402462 903 | 231836 904 | 138287 905 | 169885 906 | 490468 907 | 573922 908 | 289968 909 | 240459 910 | 110078 911 | 141788 912 | 18590 913 | 560844 914 | 256054 915 | 369461 916 | 248689 917 | 420575 918 | 374641 919 | 383438 920 | 183874 921 | 252037 922 | 314029 923 | 330151 924 | 234971 925 | 129918 926 | 10936 927 | 349621 928 | 124338 929 | 444039 930 | 492486 931 | 20979 932 | 237167 933 | 539059 934 | 443263 935 | 492424 936 | 543938 937 | 448816 938 | 528084 939 | 191193 940 | 53441 941 | 388163 942 | 176160 943 | 84511 944 | 255403 945 | 174206 946 | 134954 947 | 303956 948 | 544815 949 | 241353 950 | 2003 951 | 550641 952 | 115528 953 | 523119 954 | 91794 955 | 396931 956 | 286690 957 | 442211 958 | 100405 959 | 100386 960 | 296969 961 | 450532 962 | 65487 963 | 85149 964 | 48737 965 | 213600 966 | 356699 967 | 161254 968 | 120902 969 | 51669 970 | 251723 971 | 76937 972 | 546455 973 | 405027 974 | 470603 975 | 182822 976 | 267729 977 | 184491 978 | 95644 979 | 351226 980 | 319709 981 | 250607 982 | 180845 983 | 459861 984 | 165521 985 | 168088 986 | 556765 987 | 171263 988 | 551153 989 | 94521 990 | 441229 991 | 510496 992 | 521014 993 | 266666 994 | 458097 995 | 52542 996 | 413897 997 | 469607 998 | 194689 999 | 502546 1000 | 342635 1001 | 278393 1002 | 73291 1003 | 273856 1004 | 21160 1005 | 57626 1006 | 225785 1007 | 153498 1008 | 401492 1009 | 148286 1010 | 352545 1011 | 227797 1012 | 275105 1013 | 9811 1014 | 29691 1015 | 153228 1016 | 450423 1017 | 16546 1018 | 401880 1019 | 541885 1020 | 332316 1021 | 388327 1022 | 330032 1023 | 580408 1024 | 311448 1025 | 359282 1026 | 84604 1027 | 351185 1028 | 97529 1029 | 50961 1030 | 30752 1031 | 138658 1032 | 245341 1033 | 94710 1034 | 567654 1035 | 80952 1036 | 20799 1037 | 538216 1038 | 288197 1039 | 288884 1040 | 94731 1041 | 4631 1042 | 546438 1043 | 253913 1044 | 134758 1045 | 79120 1046 | 176036 1047 | 286704 1048 | 401191 1049 | 569186 1050 | 458129 1051 | 142178 1052 | 258743 1053 | 297352 1054 | 200669 1055 | 512029 1056 | 285982 1057 | 177733 1058 | 295515 1059 | 59687 1060 | 230466 1061 | 483199 1062 | 248597 1063 | 289726 1064 | 571108 1065 | 102751 1066 | 232696 1067 | 196971 1068 | 277123 1069 | 150780 1070 | 566169 1071 | 508667 1072 | 524806 1073 | 367451 1074 | 68168 1075 | 395468 1076 | 259283 1077 | 496333 1078 | 197186 1079 | 91738 1080 | 149844 1081 | 489228 1082 | 244260 1083 | 21106 1084 | 283315 1085 | 243899 1086 | 125148 1087 | 100728 1088 | 353519 1089 | 385815 1090 | 446709 1091 | 192017 1092 | 302004 1093 | 471555 1094 | 171046 1095 | 123724 1096 | 552865 1097 | 154629 1098 | 339184 1099 | 519529 1100 | 387900 1101 | 296931 1102 | 574607 1103 | 407805 1104 | 61624 1105 | 103427 1106 | 215726 1107 | 500353 1108 | 223758 1109 | 47232 1110 | 96508 1111 | 296610 1112 | 345414 1113 | 89260 1114 | 441444 1115 | 476518 1116 | 384880 1117 | 506313 1118 | 355306 1119 | 60885 1120 | 506884 1121 | 196031 1122 | 240600 1123 | 377967 1124 | 249783 1125 | 340233 1126 | 169950 1127 | 460079 1128 | 10536 1129 | 70708 1130 | 534450 1131 | 463952 1132 | 39505 1133 | 226338 1134 | 394740 1135 | 130144 1136 | 288878 1137 | 249966 1138 | 331117 1139 | 281690 1140 | 68542 1141 | 2355 1142 | 160268 1143 | 525949 1144 | 97977 1145 | 340888 1146 | 446049 1147 | 192564 1148 | 386584 1149 | 475035 1150 | 454012 1151 | 508892 1152 | 255134 1153 | 88338 1154 | 140293 1155 | 309294 1156 | 182083 1157 | 179883 1158 | 147385 1159 | 577776 1160 | 156511 1161 | 37028 1162 | 7747 1163 | 170433 1164 | 170623 1165 | 393356 1166 | 144411 1167 | 361278 1168 | 382307 1169 | 421474 1170 | 18388 1171 | 534048 1172 | 245577 1173 | 118424 1174 | 152008 1175 | 184428 1176 | 488487 1177 | 388096 1178 | 368293 1179 | 109381 1180 | 220312 1181 | 498795 1182 | 307288 1183 | 49408 1184 | 225311 1185 | 572768 1186 | 17153 1187 | 426676 1188 | 562517 1189 | 379646 1190 | 14733 1191 | 164775 1192 | 242249 1193 | 499313 1194 | 448457 1195 | 127004 1196 | 40912 1197 | 562110 1198 | 442769 1199 | 49963 1200 | 81549 1201 | 246799 1202 | 277235 1203 | 366373 1204 | 47638 1205 | 423971 1206 | 469451 1207 | 222840 1208 | 100725 1209 | 332667 1210 | 470016 1211 | 224301 1212 | 76142 1213 | 572070 1214 | 69826 1215 | 420216 1216 | 190324 1217 | 522190 1218 | 393841 1219 | 478337 1220 | 411787 1221 | 160443 1222 | 514093 1223 | 438497 1224 | 267195 1225 | 558088 1226 | 426635 1227 | 91335 1228 | 132501 1229 | 62196 1230 | 274182 1231 | 394487 1232 | 539090 1233 | 302188 1234 | 62115 1235 | 384837 1236 | 266010 1237 | 446783 1238 | 357392 1239 | 535965 1240 | 557550 1241 | 572944 1242 | 425398 1243 | 334547 1244 | 57303 1245 | 137281 1246 | 78797 1247 | 514380 1248 | 242902 1249 | 540178 1250 | 22317 1251 | 175599 1252 | 239917 1253 | 489928 1254 | 578798 1255 | 100968 1256 | 396695 1257 | 217882 1258 | 449168 1259 | 74275 1260 | 469997 1261 | 206764 1262 | 504105 1263 | 360866 1264 | 381332 1265 | 559818 1266 | 237250 1267 | 251065 1268 | 180896 1269 | 580016 1270 | 167421 1271 | 442103 1272 | 344144 1273 | 54081 1274 | 393112 1275 | 190168 1276 | 129377 1277 | 185377 1278 | 188089 1279 | 218186 1280 | 495348 1281 | 535422 1282 | 42569 1283 | 248862 1284 | 345018 1285 | 210200 1286 | 375445 1287 | 251000 1288 | 505392 1289 | 310454 1290 | 566985 1291 | 346522 1292 | 129927 1293 | 546890 1294 | 147287 1295 | 447866 1296 | 472683 1297 | 34245 1298 | 331483 1299 | 410653 1300 | 529579 1301 | 410014 1302 | 218004 1303 | 441507 1304 | 107398 1305 | 18804 1306 | 575714 1307 | 208235 1308 | 364118 1309 | 227840 1310 | 552070 1311 | 539115 1312 | 472609 1313 | 575527 1314 | 50369 1315 | 142864 1316 | 171035 1317 | 260334 1318 | 562373 1319 | 541439 1320 | 254687 1321 | 159096 1322 | 139590 1323 | 373341 1324 | 330620 1325 | 518273 1326 | 498596 1327 | 381074 1328 | 337202 1329 | 439098 1330 | 467022 1331 | 455599 1332 | 384089 1333 | 173378 1334 | 481643 1335 | 60602 1336 | 206455 1337 | 94387 1338 | 449418 1339 | 541884 1340 | 513879 1341 | 470708 1342 | 403401 1343 | 330348 1344 | 296196 1345 | 235080 1346 | 112895 1347 | 458748 1348 | 180380 1349 | 251119 1350 | 449234 1351 | 533188 1352 | 226129 1353 | 389177 1354 | 499860 1355 | 41884 1356 | 454957 1357 | 8491 1358 | 244345 1359 | 406099 1360 | 173832 1361 | 185921 1362 | 276289 1363 | 557925 1364 | 164939 1365 | 48044 1366 | 560222 1367 | 347904 1368 | 442860 1369 | 540927 1370 | 541773 1371 | 459870 1372 | 54765 1373 | 338519 1374 | 253977 1375 | 286680 1376 | 273851 1377 | 303745 1378 | 257654 1379 | 459051 1380 | 365996 1381 | 480875 1382 | 531847 1383 | 65645 1384 | 207029 1385 | 430811 1386 | 264111 1387 | 268322 1388 | 333503 1389 | 469583 1390 | 528409 1391 | 111143 1392 | 539408 1393 | 157945 1394 | 466488 1395 | 345838 1396 | 357580 1397 | 126100 1398 | 426299 1399 | 552770 1400 | 406447 1401 | 521930 1402 | 306316 1403 | 204340 1404 | 569603 1405 | 315196 1406 | 563090 1407 | 508536 1408 | 359862 1409 | 431913 1410 | 18107 1411 | 534860 1412 | 226883 1413 | 244989 1414 | 526919 1415 | 182455 1416 | 402730 1417 | 46234 1418 | 86117 1419 | 193673 1420 | 396328 1421 | 27628 1422 | 262045 1423 | 40717 1424 | 337985 1425 | 446307 1426 | 369132 1427 | 246148 1428 | 250135 1429 | 509255 1430 | 176491 1431 | 19242 1432 | 111460 1433 | 329315 1434 | 339738 1435 | 94298 1436 | 232733 1437 | 94674 1438 | 189331 1439 | 232332 1440 | 221368 1441 | 220909 1442 | 344094 1443 | 73646 1444 | 315073 1445 | 552025 1446 | 9046 1447 | 147910 1448 | 122912 1449 | 191494 1450 | 129846 1451 | 133199 1452 | 492041 1453 | 560476 1454 | 184523 1455 | 291235 1456 | 191626 1457 | 429897 1458 | 191499 1459 | 487673 1460 | 391220 1461 | 171109 1462 | 28244 1463 | 281866 1464 | 377996 1465 | 401057 1466 | 517698 1467 | 347224 1468 | 235760 1469 | 120560 1470 | 196223 1471 | 462009 1472 | 233460 1473 | 353196 1474 | 336802 1475 | 381760 1476 | 462146 1477 | 352175 1478 | 450165 1479 | 247949 1480 | 67512 1481 | 540053 1482 | 535804 1483 | 401428 1484 | 172645 1485 | 4705 1486 | 412139 1487 | 239419 1488 | 64642 1489 | 438590 1490 | 408813 1491 | 208557 1492 | 446399 1493 | 267315 1494 | 499831 1495 | 41970 1496 | 362983 1497 | 452836 1498 | 417673 1499 | 118139 1500 | 161773 1501 | 202675 1502 | 210791 1503 | 23965 1504 | 562260 1505 | 121126 1506 | 281993 1507 | 216695 1508 | 566862 1509 | 453175 1510 | 33945 1511 | 149025 1512 | 304653 1513 | 22433 1514 | 56231 1515 | 481904 1516 | 145519 1517 | 422332 1518 | 274257 1519 | 321341 1520 | 398309 1521 | 272613 1522 | 333689 1523 | 448972 1524 | 554201 1525 | 54287 1526 | 22010 1527 | 536064 1528 | 154094 1529 | 100915 1530 | 26225 1531 | 111515 1532 | 414500 1533 | 185579 1534 | 194144 1535 | 296390 1536 | 93171 1537 | 573229 1538 | 504322 1539 | 376734 1540 | 269832 1541 | 12354 1542 | 343864 1543 | 289412 1544 | 178196 1545 | 34496 1546 | 432449 1547 | 20516 1548 | 210803 1549 | 18955 1550 | 455722 1551 | 240026 1552 | 131035 1553 | 261607 1554 | 218427 1555 | 146934 1556 | 434570 1557 | 551196 1558 | 133840 1559 | 491742 1560 | 17777 1561 | 518508 1562 | 411058 1563 | 47428 1564 | 225808 1565 | 310357 1566 | 225263 1567 | 148594 1568 | 320532 1569 | 245506 1570 | 318525 1571 | 414039 1572 | 25845 1573 | 341346 1574 | 452940 1575 | 235201 1576 | 85693 1577 | 422255 1578 | 336033 1579 | 432394 1580 | 543729 1581 | 498420 1582 | 478091 1583 | 387484 1584 | 116009 1585 | 483842 1586 | 171272 1587 | 9462 1588 | 175537 1589 | 572989 1590 | 323735 1591 | 90149 1592 | 219893 1593 | 204512 1594 | 394820 1595 | 149082 1596 | 41328 1597 | 119491 1598 | 169201 1599 | 366046 1600 | 316133 1601 | 231200 1602 | 237883 1603 | 65755 1604 | 97604 1605 | 282330 1606 | 539519 1607 | 172225 1608 | 391617 1609 | 497275 1610 | 439351 1611 | 211934 1612 | 140959 1613 | 251128 1614 | 355613 1615 | 505516 1616 | 9809 1617 | 190255 1618 | 413779 1619 | 168290 1620 | 329336 1621 | 64565 1622 | 116645 1623 | 208490 1624 | 68208 1625 | 289370 1626 | 371912 1627 | 436812 1628 | 497361 1629 | 64044 1630 | 470794 1631 | 245877 1632 | 501328 1633 | 213063 1634 | 192297 1635 | 208448 1636 | 545155 1637 | 353344 1638 | 125096 1639 | 529638 1640 | 458179 1641 | 442012 1642 | 146483 1643 | 112251 1644 | 471505 1645 | 311911 1646 | 494442 1647 | 574961 1648 | 357778 1649 | 537500 1650 | 126477 1651 | 285650 1652 | 62902 1653 | 47954 1654 | 359254 1655 | 148489 1656 | 527014 1657 | 354049 1658 | 406043 1659 | 404545 1660 | 135275 1661 | 267707 1662 | 464445 1663 | 414963 1664 | 49584 1665 | 34942 1666 | 124768 1667 | 354852 1668 | 54721 1669 | 149372 1670 | 167817 1671 | 161841 1672 | 168485 1673 | 568731 1674 | 397219 1675 | 531461 1676 | 391419 1677 | 85871 1678 | 242141 1679 | 64191 1680 | 110733 1681 | 512630 1682 | 284722 1683 | 68844 1684 | 369324 1685 | 145636 1686 | 532055 1687 | 28058 1688 | 205328 1689 | 311018 1690 | 48622 1691 | 56014 1692 | 340046 1693 | 525170 1694 | 168960 1695 | 384957 1696 | 49961 1697 | 347147 1698 | 502041 1699 | 117328 1700 | 372175 1701 | 129701 1702 | 118381 1703 | 383863 1704 | 418665 1705 | 224205 1706 | 571001 1707 | 130690 1708 | 88621 1709 | 436890 1710 | 103617 1711 | 553563 1712 | 565930 1713 | 295593 1714 | 421258 1715 | 67047 1716 | 494757 1717 | 262259 1718 | 119474 1719 | 548354 1720 | 405154 1721 | 239520 1722 | 147962 1723 | 3233 1724 | 332295 1725 | 437822 1726 | 154372 1727 | 55027 1728 | 488424 1729 | 261105 1730 | 321489 1731 | 182594 1732 | 138321 1733 | 556469 1734 | 568333 1735 | 377080 1736 | 514831 1737 | 552966 1738 | 243012 1739 | 220698 1740 | 282936 1741 | 84654 1742 | 434842 1743 | 559300 1744 | 557649 1745 | 195413 1746 | 16537 1747 | 76349 1748 | 372404 1749 | 389712 1750 | 52571 1751 | 489294 1752 | 547977 1753 | 265007 1754 | 399977 1755 | 541159 1756 | 204240 1757 | 441939 1758 | 488900 1759 | 95492 1760 | 289474 1761 | 131618 1762 | 569674 1763 | 556837 1764 | 302071 1765 | 144287 1766 | 436427 1767 | 130787 1768 | 560874 1769 | 132506 1770 | 34502 1771 | 516799 1772 | 477513 1773 | 6465 1774 | 287184 1775 | 119913 1776 | 549497 1777 | 108928 1778 | 85822 1779 | 189175 1780 | 242713 1781 | 415065 1782 | 291566 1783 | 171834 1784 | 102214 1785 | 12323 1786 | 204351 1787 | 434820 1788 | 484631 1789 | 224384 1790 | 365386 1791 | 570478 1792 | 563736 1793 | 142300 1794 | 123703 1795 | 363697 1796 | 125557 1797 | 331402 1798 | 130184 1799 | 576337 1800 | 309631 1801 | 499295 1802 | 468690 1803 | 240802 1804 | 236152 1805 | 329763 1806 | 361421 1807 | 103327 1808 | 249051 1809 | 243600 1810 | 264075 1811 | 425336 1812 | 53002 1813 | 252084 1814 | 368993 1815 | 149979 1816 | 135087 1817 | 385562 1818 | 320249 1819 | 340040 1820 | 396647 1821 | 424948 1822 | 153980 1823 | 107826 1824 | 203624 1825 | 237528 1826 | 470727 1827 | 445644 1828 | 31238 1829 | 2040 1830 | 396717 1831 | 183935 1832 | 512085 1833 | 282550 1834 | 136081 1835 | 261895 1836 | 121949 1837 | 551772 1838 | 113245 1839 | 182061 1840 | 171928 1841 | 234936 1842 | 580940 1843 | 295333 1844 | 345936 1845 | 75545 1846 | 138678 1847 | 17350 1848 | 315633 1849 | 437056 1850 | 266627 1851 | 530430 1852 | 47339 1853 | 436956 1854 | 530967 1855 | 40629 1856 | 497304 1857 | 352016 1858 | 327670 1859 | 382742 1860 | 310830 1861 | 579878 1862 | 442794 1863 | 335552 1864 | 269058 1865 | 422940 1866 | 54142 1867 | 102656 1868 | 112927 1869 | 146271 1870 | 356120 1871 | 440400 1872 | 285733 1873 | 218448 1874 | 329991 1875 | 395227 1876 | 176538 1877 | 338695 1878 | 65494 1879 | 392768 1880 | 27632 1881 | 294823 1882 | 563112 1883 | 232151 1884 | 101336 1885 | 156955 1886 | 168954 1887 | 269988 1888 | 335576 1889 | 282089 1890 | 467752 1891 | 575356 1892 | 104832 1893 | 274068 1894 | 574826 1895 | 153758 1896 | 519890 1897 | 482883 1898 | 401155 1899 | 429274 1900 | 192514 1901 | 249722 1902 | 247397 1903 | 164704 1904 | 134125 1905 | 5561 1906 | 426222 1907 | 505290 1908 | 220789 1909 | 237084 1910 | 455971 1911 | 150526 1912 | 551475 1913 | 20268 1914 | 261563 1915 | 495417 1916 | 107551 1917 | 121172 1918 | 150091 1919 | 17365 1920 | 214553 1921 | 297467 1922 | 477107 1923 | 529323 1924 | 532357 1925 | 340251 1926 | 303307 1927 | 490804 1928 | 43984 1929 | 180728 1930 | 518492 1931 | 572503 1932 | 507896 1933 | 472469 1934 | 523155 1935 | 493572 1936 | 425320 1937 | 535101 1938 | 22050 1939 | 138205 1940 | 519157 1941 | 191623 1942 | 472402 1943 | 407777 1944 | 572080 1945 | 3198 1946 | 388868 1947 | 386923 1948 | 113155 1949 | 297228 1950 | 428726 1951 | 241770 1952 | 68545 1953 | 52883 1954 | 68294 1955 | 110215 1956 | 124047 1957 | 64902 1958 | 150041 1959 | 431433 1960 | 495168 1961 | 229176 1962 | 36052 1963 | 324725 1964 | 534714 1965 | 130812 1966 | 366031 1967 | 178363 1968 | 471522 1969 | 229778 1970 | 380973 1971 | 57902 1972 | 364542 1973 | 578759 1974 | 339740 1975 | 39695 1976 | 324529 1977 | 268958 1978 | 578422 1979 | 56292 1980 | 62442 1981 | 434999 1982 | 144545 1983 | 471406 1984 | 51709 1985 | 53839 1986 | 216925 1987 | 98373 1988 | 429220 1989 | 309307 1990 | 165947 1991 | 85429 1992 | 451272 1993 | 53101 1994 | 205451 1995 | 346801 1996 | 56252 1997 | 126877 1998 | 190744 1999 | 324314 2000 | 498472 2001 | 356720 2002 | 540457 2003 | 250080 2004 | 65815 2005 | 449096 2006 | 111230 2007 | 342205 2008 | 262216 2009 | 523290 2010 | 480376 2011 | 511287 2012 | 351407 2013 | 66259 2014 | 197485 2015 | 462949 2016 | 4610 2017 | 75542 2018 | 85231 2019 | 205063 2020 | 399612 2021 | 490539 2022 | 372360 2023 | 281800 2024 | 313564 2025 | 237937 2026 | 86879 2027 | 478174 2028 | 32700 2029 | 91725 2030 | 239288 2031 | 504980 2032 | 542335 2033 | 136513 2034 | 75922 2035 | 95809 2036 | 358681 2037 | 367634 2038 | 312336 2039 | 339449 2040 | 274259 2041 | 391978 2042 | 70305 2043 | 225586 2044 | 421209 2045 | 306336 2046 | 2589 2047 | 343346 2048 | 552282 2049 | 537541 2050 | 322531 2051 | 139909 2052 | 245977 2053 | 435518 2054 | 110249 2055 | 419479 2056 | 208641 2057 | 495622 2058 | 359353 2059 | 49006 2060 | 375637 2061 | 196400 2062 | 362304 2063 | 509888 2064 | 102041 2065 | 180352 2066 | 155055 2067 | 202077 2068 | 235417 2069 | 466115 2070 | 334009 2071 | 571055 2072 | 288973 2073 | 376783 2074 | 440670 2075 | 442501 2076 | 312519 2077 | 20145 2078 | 46493 2079 | 172547 2080 | 287799 2081 | 457045 2082 | 29834 2083 | 182409 2084 | 476180 2085 | 46 2086 | 248130 2087 | 35110 2088 | 538380 2089 | 305442 2090 | 539678 2091 | 150403 2092 | 277716 2093 | 67005 2094 | 9412 2095 | 541571 2096 | 256828 2097 | 18843 2098 | 91006 2099 | 520323 2100 | 47064 2101 | 428356 2102 | 367165 2103 | 42771 2104 | 134278 2105 | 509136 2106 | 230546 2107 | 338545 2108 | 352873 2109 | 433140 2110 | 97947 2111 | 393465 2112 | 110450 2113 | 259714 2114 | 100879 2115 | 257434 2116 | 573418 2117 | 438035 2118 | 466719 2119 | 214026 2120 | 385598 2121 | 106618 2122 | 180054 2123 | 522553 2124 | 275303 2125 | 357160 2126 | 270162 2127 | 283183 2128 | 556896 2129 | 54326 2130 | 169704 2131 | 228284 2132 | 236043 2133 | 440989 2134 | 391241 2135 | 127571 2136 | 305481 2137 | 111618 2138 | 209626 2139 | 561034 2140 | 507930 2141 | 291408 2142 | 233721 2143 | 181887 2144 | 279448 2145 | 277821 2146 | 358262 2147 | 470300 2148 | 340874 2149 | 322770 2150 | 112886 2151 | 160276 2152 | 524031 2153 | 15833 2154 | 547025 2155 | 318395 2156 | 328070 2157 | 512041 2158 | 438751 2159 | 398403 2160 | 10863 2161 | 268921 2162 | 414960 2163 | 353733 2164 | 451185 2165 | 489434 2166 | 256348 2167 | 301596 2168 | 366529 2169 | 437636 2170 | 431791 2171 | 537344 2172 | 26013 2173 | 535941 2174 | 538592 2175 | 119107 2176 | 289260 2177 | 561496 2178 | 261307 2179 | 123417 2180 | 170026 2181 | 315782 2182 | 236398 2183 | 500068 2184 | 283484 2185 | 327151 2186 | 377717 2187 | 418591 2188 | 37518 2189 | 568653 2190 | 230474 2191 | 118276 2192 | 531498 2193 | 348525 2194 | 343688 2195 | 53130 2196 | 349173 2197 | 100906 2198 | 288023 2199 | 185372 2200 | 292837 2201 | 84819 2202 | 227005 2203 | 201809 2204 | 523094 2205 | 517813 2206 | 531286 2207 | 409474 2208 | 384482 2209 | 256549 2210 | 429987 2211 | 265438 2212 | 321175 2213 | 555888 2214 | 355652 2215 | 55996 2216 | 433068 2217 | 45205 2218 | 107062 2219 | 534319 2220 | 109708 2221 | 197517 2222 | 473065 2223 | 116010 2224 | 122926 2225 | 479526 2226 | 171144 2227 | 132145 2228 | 486063 2229 | 432553 2230 | 51692 2231 | 495363 2232 | 428853 2233 | 187379 2234 | 463531 2235 | 257056 2236 | 429809 2237 | 126599 2238 | 168514 2239 | 402344 2240 | 382697 2241 | 251375 2242 | 30631 2243 | 477739 2244 | 411970 2245 | 105596 2246 | 572888 2247 | 482547 2248 | 271601 2249 | 65795 2250 | 229012 2251 | 156781 2252 | 457348 2253 | 395380 2254 | 240790 2255 | 480536 2256 | 72869 2257 | 290917 2258 | 396549 2259 | 181857 2260 | 415997 2261 | 420078 2262 | 237729 2263 | 377558 2264 | 127909 2265 | 270627 2266 | 229402 2267 | 373800 2268 | 468494 2269 | 106775 2270 | 393907 2271 | 83240 2272 | 499819 2273 | 37020 2274 | 337606 2275 | 289684 2276 | 517986 2277 | 252604 2278 | 318631 2279 | 119588 2280 | 107823 2281 | 46044 2282 | 18443 2283 | 495877 2284 | 118074 2285 | 170203 2286 | 244946 2287 | 454662 2288 | 458 2289 | 531697 2290 | 268476 2291 | 393947 2292 | 513409 2293 | 93143 2294 | 510488 2295 | 457987 2296 | 293908 2297 | 568984 2298 | 333028 2299 | 261832 2300 | 99748 2301 | 575049 2302 | 407007 2303 | 313232 2304 | 346483 2305 | 93789 2306 | 242325 2307 | 235591 2308 | 563258 2309 | 263246 2310 | 200896 2311 | 61304 2312 | 6607 2313 | 363487 2314 | 297125 2315 | 217517 2316 | 239586 2317 | 500155 2318 | 185942 2319 | 377802 2320 | 461917 2321 | 3145 2322 | 166546 2323 | 300447 2324 | 145909 2325 | 429957 2326 | 385778 2327 | 440524 2328 | 62254 2329 | 331216 2330 | 261679 2331 | 506561 2332 | 423661 2333 | 259947 2334 | 141611 2335 | 52618 2336 | 77222 2337 | 426512 2338 | 175778 2339 | 397130 2340 | 259864 2341 | 371593 2342 | 170860 2343 | 557345 2344 | 51084 2345 | 434334 2346 | 556699 2347 | 177744 2348 | 54560 2349 | 117546 2350 | 371033 2351 | 279119 2352 | 312148 2353 | 221014 2354 | 263688 2355 | 61534 2356 | 70654 2357 | 536120 2358 | 132788 2359 | 491124 2360 | 171328 2361 | 177870 2362 | 355572 2363 | 235324 2364 | 181736 2365 | 373078 2366 | 424386 2367 | 482709 2368 | 350044 2369 | 335836 2370 | 478829 2371 | 442354 2372 | 60466 2373 | 236862 2374 | 579587 2375 | 384377 2376 | 126729 2377 | 340809 2378 | 261545 2379 | 87629 2380 | 505809 2381 | 170917 2382 | 489596 2383 | 297098 2384 | 293472 2385 | 162907 2386 | 281260 2387 | 308533 2388 | 206744 2389 | 88576 2390 | 481318 2391 | 198607 2392 | 517051 2393 | 163589 2394 | 283973 2395 | 333119 2396 | 29626 2397 | 87352 2398 | 61246 2399 | 515521 2400 | 286100 2401 | 487424 2402 | 235128 2403 | 95696 2404 | 227718 2405 | 227550 2406 | 98317 2407 | 190070 2408 | 392708 2409 | 214670 2410 | 485800 2411 | 313926 2412 | 420654 2413 | 435555 2414 | 566292 2415 | 443879 2416 | 280545 2417 | 389352 2418 | 368642 2419 | 66619 2420 | 522543 2421 | 39537 2422 | 558778 2423 | 337583 2424 | 110298 2425 | 37415 2426 | 148069 2427 | 495073 2428 | 2688 2429 | 446651 2430 | 187321 2431 | 190932 2432 | 25502 2433 | 346247 2434 | 285889 2435 | 102036 2436 | 293220 2437 | 120428 2438 | 86311 2439 | 560339 2440 | 173051 2441 | 185918 2442 | 289056 2443 | 323001 2444 | 191844 2445 | 259033 2446 | 209014 2447 | 501405 2448 | 486055 2449 | 78088 2450 | 457971 2451 | 554020 2452 | 509842 2453 | 464051 2454 | 431220 2455 | 224010 2456 | 578801 2457 | 566427 2458 | 465736 2459 | 76273 2460 | 577073 2461 | 416088 2462 | 424212 2463 | 532584 2464 | 181830 2465 | 477462 2466 | 514100 2467 | 501961 2468 | 19168 2469 | 358186 2470 | 330959 2471 | 322880 2472 | 332276 2473 | 77072 2474 | 249589 2475 | 69589 2476 | 45622 2477 | 390173 2478 | 468127 2479 | 49177 2480 | 440197 2481 | 257100 2482 | 532430 2483 | 459094 2484 | 282767 2485 | 239980 2486 | 9385 2487 | 246619 2488 | 402859 2489 | 524387 2490 | 131284 2491 | 308116 2492 | 411659 2493 | 220132 2494 | 87039 2495 | 141470 2496 | 188856 2497 | 57138 2498 | 559982 2499 | 455873 2500 | 286767 2501 | 282708 2502 | 182913 2503 | 73388 2504 | 569063 2505 | 198291 2506 | 11201 2507 | 423540 2508 | 475794 2509 | 401029 2510 | 414696 2511 | 324340 2512 | 288560 2513 | 300306 2514 | 554976 2515 | 453488 2516 | 416741 2517 | 479636 2518 | 194300 2519 | 503803 2520 | 74187 2521 | 394100 2522 | 149460 2523 | 320080 2524 | 30154 2525 | 299241 2526 | 150273 2527 | 51680 2528 | 115587 2529 | 486083 2530 | 145026 2531 | 239343 2532 | 253413 2533 | 53337 2534 | 38366 2535 | 432239 2536 | 35929 2537 | 140260 2538 | 395695 2539 | 25314 2540 | 82911 2541 | 339988 2542 | 163928 2543 | 445425 2544 | 120675 2545 | 555979 2546 | 66723 2547 | 446272 2548 | 120912 2549 | 88660 2550 | 397691 2551 | 63670 2552 | 319870 2553 | 85443 2554 | 257535 2555 | 129300 2556 | 324424 2557 | 365086 2558 | 367459 2559 | 529689 2560 | 120321 2561 | 65541 2562 | 89172 2563 | 509835 2564 | 169827 2565 | 81588 2566 | 123371 2567 | 114086 2568 | 542163 2569 | 44718 2570 | 509884 2571 | 165524 2572 | 344424 2573 | 172647 2574 | 134161 2575 | 468265 2576 | 468977 2577 | 31910 2578 | 415082 2579 | 366422 2580 | 109980 2581 | 296723 2582 | 549100 2583 | 507271 2584 | 417953 2585 | 55766 2586 | 93043 2587 | 572086 2588 | 136312 2589 | 72454 2590 | 212397 2591 | 561810 2592 | 447662 2593 | 350694 2594 | 163099 2595 | 276994 2596 | 211632 2597 | 508125 2598 | 238595 2599 | 300659 2600 | 112057 2601 | 513688 2602 | 27000 2603 | 402078 2604 | 327141 2605 | 269455 2606 | 142519 2607 | 183602 2608 | 333165 2609 | 559715 2610 | 33063 2611 | 311677 2612 | 451772 2613 | 543517 2614 | 97884 2615 | 201726 2616 | 533028 2617 | 1702 2618 | 280534 2619 | 501566 2620 | 564588 2621 | 328827 2622 | 49477 2623 | 225761 2624 | 153504 2625 | 142755 2626 | 573772 2627 | 363759 2628 | 333047 2629 | 179116 2630 | 217590 2631 | 82284 2632 | 26761 2633 | 44889 2634 | 301713 2635 | 326216 2636 | 326832 2637 | 62331 2638 | 438514 2639 | 361109 2640 | 575749 2641 | 447318 2642 | 309139 2643 | 386643 2644 | 446314 2645 | 410391 2646 | 567725 2647 | 446238 2648 | 128352 2649 | 157950 2650 | 316430 2651 | 485731 2652 | 111304 2653 | 174875 2654 | 538121 2655 | 57443 2656 | 350758 2657 | 112950 2658 | 310595 2659 | 307442 2660 | 359946 2661 | 466730 2662 | 566471 2663 | 389682 2664 | 5832 2665 | 147730 2666 | 576268 2667 | 551584 2668 | 369235 2669 | 6395 2670 | 401004 2671 | 216061 2672 | 571780 2673 | 41575 2674 | 449978 2675 | 300098 2676 | 67359 2677 | 249006 2678 | 472526 2679 | 111786 2680 | 335114 2681 | 158011 2682 | 35858 2683 | 92515 2684 | 529141 2685 | 109586 2686 | 506572 2687 | 523960 2688 | 536220 2689 | 235010 2690 | 324573 2691 | 467966 2692 | 93258 2693 | 221043 2694 | 346661 2695 | 225882 2696 | 532145 2697 | 172667 2698 | 527736 2699 | 385109 2700 | 312191 2701 | 245580 2702 | 385725 2703 | 465747 2704 | 273493 2705 | 71550 2706 | 370999 2707 | 18455 2708 | 249077 2709 | 35078 2710 | 295881 2711 | 392956 2712 | 345377 2713 | 55538 2714 | 578728 2715 | 203213 2716 | 225102 2717 | 30849 2718 | 525883 2719 | 206990 2720 | 411372 2721 | 65987 2722 | 79515 2723 | 65993 2724 | 290825 2725 | 339203 2726 | 121697 2727 | 374610 2728 | 317216 2729 | 69890 2730 | 545116 2731 | 374248 2732 | 76658 2733 | 525345 2734 | 503850 2735 | 391814 2736 | 369 2737 | 79078 2738 | 546257 2739 | 161047 2740 | 559231 2741 | 161813 2742 | 223446 2743 | 500734 2744 | 119860 2745 | 526739 2746 | 127037 2747 | 107710 2748 | 151632 2749 | 258324 2750 | 539555 2751 | 173241 2752 | 355000 2753 | 548873 2754 | 193549 2755 | 41215 2756 | 62342 2757 | 534354 2758 | 118649 2759 | 387679 2760 | 38623 2761 | 272941 2762 | 246264 2763 | 433347 2764 | 529607 2765 | 310217 2766 | 181711 2767 | 250557 2768 | 155528 2769 | 41339 2770 | 385551 2771 | 344976 2772 | 524425 2773 | 402899 2774 | 497532 2775 | 562721 2776 | 368968 2777 | 509892 2778 | 24081 2779 | 165116 2780 | 219008 2781 | 368401 2782 | 170004 2783 | 136260 2784 | 458620 2785 | 513571 2786 | 535333 2787 | 243749 2788 | 478498 2789 | 347572 2790 | 454094 2791 | 577042 2792 | 224052 2793 | 379641 2794 | 423619 2795 | 295041 2796 | 242213 2797 | 384607 2798 | 528639 2799 | 543129 2800 | 547415 2801 | 256738 2802 | 478638 2803 | 159066 2804 | 380144 2805 | 403212 2806 | 119878 2807 | 209472 2808 | 34339 2809 | 156314 2810 | 238819 2811 | 515293 2812 | 557520 2813 | 157925 2814 | 118529 2815 | 54497 2816 | 84733 2817 | 90459 2818 | 481683 2819 | 508605 2820 | 357849 2821 | 201229 2822 | 163090 2823 | 456753 2824 | 367280 2825 | 304646 2826 | 192009 2827 | 227278 2828 | 406185 2829 | 323101 2830 | 67402 2831 | 290225 2832 | 313456 2833 | 284395 2834 | 444951 2835 | 544529 2836 | 307179 2837 | 297318 2838 | 64659 2839 | 213314 2840 | 175234 2841 | 514496 2842 | 252505 2843 | 121386 2844 | 51432 2845 | 210788 2846 | 233200 2847 | 167823 2848 | 550065 2849 | 498081 2850 | 130320 2851 | 328562 2852 | 173415 2853 | 87507 2854 | 537013 2855 | 54962 2856 | 86414 2857 | 120261 2858 | 89170 2859 | 407395 2860 | 506123 2861 | 80678 2862 | 174832 2863 | 398107 2864 | 121962 2865 | 481996 2866 | 196146 2867 | 443155 2868 | 72634 2869 | 466297 2870 | 193329 2871 | 574939 2872 | 324382 2873 | 216591 2874 | 257258 2875 | 507867 2876 | 263638 2877 | 375399 2878 | 425385 2879 | 7260 2880 | 342374 2881 | 1145 2882 | 92324 2883 | 424902 2884 | 398609 2885 | 398173 2886 | 49839 2887 | 265379 2888 | 127351 2889 | 33097 2890 | 124662 2891 | 374653 2892 | 465351 2893 | 40703 2894 | 300463 2895 | 104802 2896 | 556183 2897 | 110032 2898 | 305282 2899 | 262647 2900 | 300368 2901 | 264054 2902 | 305144 2903 | 133707 2904 | 499726 2905 | 212183 2906 | 277919 2907 | 444256 2908 | 39948 2909 | 122521 2910 | 69899 2911 | 111974 2912 | 274920 2913 | 505564 2914 | 402628 2915 | 55687 2916 | 234391 2917 | 241642 2918 | 492747 2919 | 492649 2920 | 65446 2921 | 85411 2922 | 530523 2923 | 455679 2924 | 259149 2925 | 333968 2926 | 532543 2927 | 259038 2928 | 513468 2929 | 560209 2930 | 28675 2931 | 277263 2932 | 304324 2933 | 541002 2934 | 397678 2935 | 258475 2936 | 123562 2937 | 75167 2938 | 203991 2939 | 129759 2940 | 29355 2941 | 450453 2942 | 229377 2943 | 482487 2944 | 316163 2945 | 578402 2946 | 257317 2947 | 221034 2948 | 268395 2949 | 280208 2950 | 32747 2951 | 164481 2952 | 425495 2953 | 257799 2954 | 37721 2955 | 285879 2956 | 506094 2957 | 209398 2958 | 207746 2959 | 300848 2960 | 260168 2961 | 450700 2962 | 150193 2963 | 146851 2964 | 69771 2965 | 104667 2966 | 441677 2967 | 218906 2968 | 294960 2969 | 229805 2970 | 60525 2971 | 116628 2972 | 140144 2973 | 350098 2974 | 533455 2975 | 386848 2976 | 3513 2977 | 267376 2978 | 565399 2979 | 63961 2980 | 475960 2981 | 317346 2982 | 436534 2983 | 12874 2984 | 264046 2985 | 303772 2986 | 86032 2987 | 314092 2988 | 246473 2989 | 342887 2990 | 97617 2991 | 209075 2992 | 477526 2993 | 141279 2994 | 267962 2995 | 244967 2996 | 321981 2997 | 35118 2998 | 51903 2999 | 244245 3000 | 520773 3001 | 238613 3002 | 461292 3003 | 71110 3004 | 57472 3005 | 477012 3006 | 404778 3007 | 252947 3008 | 68521 3009 | 380743 3010 | 401897 3011 | 322443 3012 | 474480 3013 | 37877 3014 | 83351 3015 | 69912 3016 | 261630 3017 | 362225 3018 | 101776 3019 | 380240 3020 | 10845 3021 | 276111 3022 | 457637 3023 | 385179 3024 | 153538 3025 | 358007 3026 | 397479 3027 | 87056 3028 | 143820 3029 | 118602 3030 | 309586 3031 | 326333 3032 | 552615 3033 | 289317 3034 | 17392 3035 | 564542 3036 | 108427 3037 | 361272 3038 | 498110 3039 | 437327 3040 | 166043 3041 | 234944 3042 | 380191 3043 | 124901 3044 | 415946 3045 | 339298 3046 | 488209 3047 | 269165 3048 | 291531 3049 | 69054 3050 | 14007 3051 | 426795 3052 | 455030 3053 | 32474 3054 | 311662 3055 | 170454 3056 | 314521 3057 | 371011 3058 | 425749 3059 | 251254 3060 | 235652 3061 | 4556 3062 | 526338 3063 | 64474 3064 | 522068 3065 | 313989 3066 | 532743 3067 | 129806 3068 | 512394 3069 | 266088 3070 | 285025 3071 | 73294 3072 | 333555 3073 | 527288 3074 | 555872 3075 | 239641 3076 | 203854 3077 | 361114 3078 | 312447 3079 | 248887 3080 | 213089 3081 | 25488 3082 | 145732 3083 | 229934 3084 | 288683 3085 | 432783 3086 | 549201 3087 | 184487 3088 | 84183 3089 | 398061 3090 | 127437 3091 | 383621 3092 | 305294 3093 | 73743 3094 | 205075 3095 | 120131 3096 | 378396 3097 | 266642 3098 | 539458 3099 | 40695 3100 | 506865 3101 | 312952 3102 | 318511 3103 | 466499 3104 | 84087 3105 | 456884 3106 | 218488 3107 | 470878 3108 | 458884 3109 | 379002 3110 | 114648 3111 | 277208 3112 | 10244 3113 | 95947 3114 | 242826 3115 | 529281 3116 | 528819 3117 | 70866 3118 | 361530 3119 | 555086 3120 | 555125 3121 | 84140 3122 | 352068 3123 | 13678 3124 | 480910 3125 | 324577 3126 | 168210 3127 | 271111 3128 | 501243 3129 | 237235 3130 | 188504 3131 | 85766 3132 | 347619 3133 | 313673 3134 | 567233 3135 | 547294 3136 | 202162 3137 | 222355 3138 | 470598 3139 | 184885 3140 | 436742 3141 | 206210 3142 | 13670 3143 | 412454 3144 | 95381 3145 | 419032 3146 | 339705 3147 | 105277 3148 | 449948 3149 | 71072 3150 | 235904 3151 | 207795 3152 | 312107 3153 | 103994 3154 | 551215 3155 | 403234 3156 | 544300 3157 | 542345 3158 | 149931 3159 | 77399 3160 | 285081 3161 | 436115 3162 | 411957 3163 | 200467 3164 | 263636 3165 | 491206 3166 | 441312 3167 | 61409 3168 | 384317 3169 | 393456 3170 | 428380 3171 | 151922 3172 | 401915 3173 | 135085 3174 | 45126 3175 | 579792 3176 | 51848 3177 | 246739 3178 | 341778 3179 | 80779 3180 | 193643 3181 | 307911 3182 | 400792 3183 | 572468 3184 | 82552 3185 | 85130 3186 | 476858 3187 | 58565 3188 | 495099 3189 | 28282 3190 | 288156 3191 | 297834 3192 | 72186 3193 | 211054 3194 | 508061 3195 | 387552 3196 | 435487 3197 | 329200 3198 | 150586 3199 | 414579 3200 | 564435 3201 | 469937 3202 | 264372 3203 | 28078 3204 | 252249 3205 | 277693 3206 | 161552 3207 | 537879 3208 | 427029 3209 | 254960 3210 | 132019 3211 | 498514 3212 | 463734 3213 | 186223 3214 | 165234 3215 | 169439 3216 | 440500 3217 | 434054 3218 | 110338 3219 | 120592 3220 | 45056 3221 | 441867 3222 | 295772 3223 | 384695 3224 | 572668 3225 | 64560 3226 | 60034 3227 | 118755 3228 | 44508 3229 | 477213 3230 | 563504 3231 | 212911 3232 | 130332 3233 | 568613 3234 | 53416 3235 | 151352 3236 | 312609 3237 | 491424 3238 | 27158 3239 | 258207 3240 | 301041 3241 | 324956 3242 | 307634 3243 | 72240 3244 | 165400 3245 | 538431 3246 | 103294 3247 | 6315 3248 | 529009 3249 | 568884 3250 | 423820 3251 | 211052 3252 | 487278 3253 | 545710 3254 | 41460 3255 | 266607 3256 | 566380 3257 | 449431 3258 | 10779 3259 | 447920 3260 | 156925 3261 | 154558 3262 | 280957 3263 | 480166 3264 | 3891 3265 | 17214 3266 | 372591 3267 | 473697 3268 | 303719 3269 | 37642 3270 | 562325 3271 | 533396 3272 | 84345 3273 | 272808 3274 | 575520 3275 | 460624 3276 | 305110 3277 | 424791 3278 | 181721 3279 | 366852 3280 | 308975 3281 | 478357 3282 | 332412 3283 | 105453 3284 | 129901 3285 | 469023 3286 | 461807 3287 | 102274 3288 | 413679 3289 | 370148 3290 | 13491 3291 | 17460 3292 | 144950 3293 | 347583 3294 | 179359 3295 | 124537 3296 | 575731 3297 | 41267 3298 | 360639 3299 | 470272 3300 | 256660 3301 | 539999 3302 | 57587 3303 | 141638 3304 | 461714 3305 | 124109 3306 | 382073 3307 | 505337 3308 | 92793 3309 | 480083 3310 | 21121 3311 | 330544 3312 | 146290 3313 | 423990 3314 | 215407 3315 | 224513 3316 | 257001 3317 | 339508 3318 | 13177 3319 | 390775 3320 | 328112 3321 | 376667 3322 | 274169 3323 | 490912 3324 | 322221 3325 | 50526 3326 | 508598 3327 | 269940 3328 | 519451 3329 | 79165 3330 | 476664 3331 | 517807 3332 | 151051 3333 | 154760 3334 | 488206 3335 | 155600 3336 | 380356 3337 | 493271 3338 | 352443 3339 | 66303 3340 | 128662 3341 | 504288 3342 | 426283 3343 | 331599 3344 | 301178 3345 | 561636 3346 | 245319 3347 | 29983 3348 | 309719 3349 | 378956 3350 | 136431 3351 | 8770 3352 | 95344 3353 | 381576 3354 | 371062 3355 | 541803 3356 | 38422 3357 | 261184 3358 | 340245 3359 | 75646 3360 | 323500 3361 | 104536 3362 | 472304 3363 | 368721 3364 | 194525 3365 | 142459 3366 | 540686 3367 | 485134 3368 | 24759 3369 | 326277 3370 | 230791 3371 | 110272 3372 | 97143 3373 | 195177 3374 | 473573 3375 | 463095 3376 | 379389 3377 | 6853 3378 | 263907 3379 | 134647 3380 | 246780 3381 | 500431 3382 | 423474 3383 | 218762 3384 | 560516 3385 | 189381 3386 | 327705 3387 | 279482 3388 | 260897 3389 | 208507 3390 | 417485 3391 | 481024 3392 | 499651 3393 | 122165 3394 | 270688 3395 | 118008 3396 | 421838 3397 | 486418 3398 | 109676 3399 | 287514 3400 | 239089 3401 | 569983 3402 | 348389 3403 | 34113 3404 | 85627 3405 | 284205 3406 | 364041 3407 | 121750 3408 | 176543 3409 | 264784 3410 | 48930 3411 | 8665 3412 | 297355 3413 | 92809 3414 | 153367 3415 | 473246 3416 | 423124 3417 | 580360 3418 | 337768 3419 | 6965 3420 | 205686 3421 | 576569 3422 | 550709 3423 | 182902 3424 | 479697 3425 | 304864 3426 | 568829 3427 | 162428 3428 | 14065 3429 | 351134 3430 | 277420 3431 | 186280 3432 | 333611 3433 | 161240 3434 | 4738 3435 | 253201 3436 | 213203 3437 | 16896 3438 | 422494 3439 | 218640 3440 | 288094 3441 | 483803 3442 | 221005 3443 | 73620 3444 | 16024 3445 | 489635 3446 | 469496 3447 | 381494 3448 | 3447 3449 | 139643 3450 | 163270 3451 | 51282 3452 | 162607 3453 | 236209 3454 | 339495 3455 | 513362 3456 | 114267 3457 | 14037 3458 | 455969 3459 | 373579 3460 | 157737 3461 | 162371 3462 | 410053 3463 | 349764 3464 | 483752 3465 | 468054 3466 | 2387 3467 | 353888 3468 | 258885 3469 | 243346 3470 | 8466 3471 | 242760 3472 | 467809 3473 | 381900 3474 | 218198 3475 | 368561 3476 | 460472 3477 | 500627 3478 | 173020 3479 | 108516 3480 | 526048 3481 | 334754 3482 | 497747 3483 | 575692 3484 | 387311 3485 | 432617 3486 | 535641 3487 | 353512 3488 | 319995 3489 | 267930 3490 | 193105 3491 | 571680 3492 | 363950 3493 | 460875 3494 | 234432 3495 | 257624 3496 | 354842 3497 | 555764 3498 | 461410 3499 | 272549 3500 | 180066 3501 | 427565 3502 | 343434 3503 | 70814 3504 | 205934 3505 | 342055 3506 | 273666 3507 | 383268 3508 | 210586 3509 | 267534 3510 | 568398 3511 | 241725 3512 | 291899 3513 | 325904 3514 | 129583 3515 | 575095 3516 | 271355 3517 | 303808 3518 | 377345 3519 | 341304 3520 | 427267 3521 | 572561 3522 | 23311 3523 | 339497 3524 | 157105 3525 | 341279 3526 | 224367 3527 | 504481 3528 | 113006 3529 | 87218 3530 | 547830 3531 | 238150 3532 | 449033 3533 | 287368 3534 | 168409 3535 | 314600 3536 | 352937 3537 | 319829 3538 | 335573 3539 | 120061 3540 | 25633 3541 | 23415 3542 | 33257 3543 | 544921 3544 | 524791 3545 | 228317 3546 | 530857 3547 | 94618 3548 | 41848 3549 | 386852 3550 | 223590 3551 | 122060 3552 | 563712 3553 | 221382 3554 | 127568 3555 | 469751 3556 | 432688 3557 | 158962 3558 | 132940 3559 | 464424 3560 | 15070 3561 | 509681 3562 | 324836 3563 | 114411 3564 | 119236 3565 | 181390 3566 | 1373 3567 | 46397 3568 | 336865 3569 | 238439 3570 | 207440 3571 | 273987 3572 | 183134 3573 | 305029 3574 | 534930 3575 | 550751 3576 | 396584 3577 | 537148 3578 | 272021 3579 | 462079 3580 | 325211 3581 | 146547 3582 | 293465 3583 | 371809 3584 | 530310 3585 | 580531 3586 | 275694 3587 | 84223 3588 | 257893 3589 | 474965 3590 | 453700 3591 | 265076 3592 | 318106 3593 | 339021 3594 | 351715 3595 | 79141 3596 | 229378 3597 | 225039 3598 | 224257 3599 | 538735 3600 | 404261 3601 | 229382 3602 | 136222 3603 | 364692 3604 | 180929 3605 | 250474 3606 | 86231 3607 | 521525 3608 | 232249 3609 | 544374 3610 | 375841 3611 | 268335 3612 | 545756 3613 | 85111 3614 | 379688 3615 | 57425 3616 | 110460 3617 | 83422 3618 | 446588 3619 | 57977 3620 | 209240 3621 | 358518 3622 | 382691 3623 | 286149 3624 | 303431 3625 | 444839 3626 | 474495 3627 | 208089 3628 | 383449 3629 | 305934 3630 | 412626 3631 | 434942 3632 | 171170 3633 | 236536 3634 | 208624 3635 | 19922 3636 | 67874 3637 | 62936 3638 | 116264 3639 | 499258 3640 | 532616 3641 | 390621 3642 | 222846 3643 | 35385 3644 | 26915 3645 | 342017 3646 | 309759 3647 | 213872 3648 | 177558 3649 | 565014 3650 | 1759 3651 | 538558 3652 | 403929 3653 | 204892 3654 | 191579 3655 | 484819 3656 | 423212 3657 | 309562 3658 | 136811 3659 | 267881 3660 | 182680 3661 | 193524 3662 | 166279 3663 | 149870 3664 | 402863 3665 | 284013 3666 | 560871 3667 | 6492 3668 | 56421 3669 | 291695 3670 | 96044 3671 | 525689 3672 | 575986 3673 | 513472 3674 | 283884 3675 | 455837 3676 | 19828 3677 | 144414 3678 | 499670 3679 | 320339 3680 | 318061 3681 | 573913 3682 | 204056 3683 | 404499 3684 | 452829 3685 | 550788 3686 | 198987 3687 | 62480 3688 | 63706 3689 | 449321 3690 | 503967 3691 | 260514 3692 | 344974 3693 | 141440 3694 | 346045 3695 | 576863 3696 | 491868 3697 | 542381 3698 | 181339 3699 | 318290 3700 | 240981 3701 | 459695 3702 | 446992 3703 | 107751 3704 | 270843 3705 | 126275 3706 | 224962 3707 | 237044 3708 | 112794 3709 | 186124 3710 | 378399 3711 | 498979 3712 | 382510 3713 | 205319 3714 | 577461 3715 | 288797 3716 | 226275 3717 | 377015 3718 | 334194 3719 | 216156 3720 | 389719 3721 | 321042 3722 | 346375 3723 | 193835 3724 | 161269 3725 | 477872 3726 | 321998 3727 | 361788 3728 | 109403 3729 | 129053 3730 | 317798 3731 | 381102 3732 | 7080 3733 | 293069 3734 | 420693 3735 | 272127 3736 | 489478 3737 | 58452 3738 | 150429 3739 | 580889 3740 | 277116 3741 | 247431 3742 | 277939 3743 | 520497 3744 | 118571 3745 | 386165 3746 | 1346 3747 | 309685 3748 | 376788 3749 | 487244 3750 | 375033 3751 | 305347 3752 | 466593 3753 | 358984 3754 | 47600 3755 | 202125 3756 | 490645 3757 | 291727 3758 | 95795 3759 | 210450 3760 | 561442 3761 | 34835 3762 | 98194 3763 | 34893 3764 | 79613 3765 | 92004 3766 | 82126 3767 | 269065 3768 | 515942 3769 | 448572 3770 | 140832 3771 | 5784 3772 | 33416 3773 | 481704 3774 | 305120 3775 | 495626 3776 | 423076 3777 | 150817 3778 | 253253 3779 | 484170 3780 | 215279 3781 | 378488 3782 | 442520 3783 | 181472 3784 | 153589 3785 | 172429 3786 | 275810 3787 | 18077 3788 | 468051 3789 | 575303 3790 | 541437 3791 | 12307 3792 | 85599 3793 | 437693 3794 | 580044 3795 | 5897 3796 | 275571 3797 | 537308 3798 | 236052 3799 | 18727 3800 | 531963 3801 | 157050 3802 | 457375 3803 | 449919 3804 | 350874 3805 | 201986 3806 | 83646 3807 | 386798 3808 | 432099 3809 | 175558 3810 | 370479 3811 | 475239 3812 | 505318 3813 | 449737 3814 | 481747 3815 | 574449 3816 | 15785 3817 | 549150 3818 | 132926 3819 | 577739 3820 | 347365 3821 | 277938 3822 | 118150 3823 | 538848 3824 | 481103 3825 | 32956 3826 | 239085 3827 | 232043 3828 | 402290 3829 | 333229 3830 | 572917 3831 | 319159 3832 | 205878 3833 | 267023 3834 | 442784 3835 | 58589 3836 | 574282 3837 | 18441 3838 | 220086 3839 | 248610 3840 | 378863 3841 | 332825 3842 | 490458 3843 | 489681 3844 | 251484 3845 | 247205 3846 | 114780 3847 | 556882 3848 | 340672 3849 | 553436 3850 | 457875 3851 | 197050 3852 | 424164 3853 | 268223 3854 | 319576 3855 | 264623 3856 | 296 3857 | 82174 3858 | 156977 3859 | 260975 3860 | 288001 3861 | 377804 3862 | 421819 3863 | 389336 3864 | 248633 3865 | 52830 3866 | 155702 3867 | 496138 3868 | 194607 3869 | 390835 3870 | 27361 3871 | 123200 3872 | 509219 3873 | 52220 3874 | 240331 3875 | 381274 3876 | 324056 3877 | 495077 3878 | 472737 3879 | 53744 3880 | 332398 3881 | 33721 3882 | 545760 3883 | 189044 3884 | 348627 3885 | 202861 3886 | 312714 3887 | 157367 3888 | 278224 3889 | 389255 3890 | 464706 3891 | 559601 3892 | 329201 3893 | 175704 3894 | 111103 3895 | 218196 3896 | 504019 3897 | 128642 3898 | 243726 3899 | 265556 3900 | 520866 3901 | 235141 3902 | 580939 3903 | 440157 3904 | 157696 3905 | 360159 3906 | 198552 3907 | 68088 3908 | 521715 3909 | 318783 3910 | 489502 3911 | 478269 3912 | 45124 3913 | 162286 3914 | 293359 3915 | 563829 3916 | 553835 3917 | 570641 3918 | 444433 3919 | 544109 3920 | 255682 3921 | 575410 3922 | 560806 3923 | 233980 3924 | 422947 3925 | 176980 3926 | 233824 3927 | 198286 3928 | 195084 3929 | 250176 3930 | 78134 3931 | 482581 3932 | 455935 3933 | 141430 3934 | 332565 3935 | 126501 3936 | 439427 3937 | 366923 3938 | 366068 3939 | 419397 3940 | 465901 3941 | 576102 3942 | 293149 3943 | 197060 3944 | 110727 3945 | 280052 3946 | 386751 3947 | 154734 3948 | 454884 3949 | 269053 3950 | 531868 3951 | 477681 3952 | 150844 3953 | 77762 3954 | 337988 3955 | 327519 3956 | 334475 3957 | 29964 3958 | 293819 3959 | 272805 3960 | 337089 3961 | 18025 3962 | 230519 3963 | 80466 3964 | 357886 3965 | 518723 3966 | 526980 3967 | 150194 3968 | 386554 3969 | 559208 3970 | 333524 3971 | 441015 3972 | 31167 3973 | 52974 3974 | 110285 3975 | 395670 3976 | 197305 3977 | 62610 3978 | 225044 3979 | 422506 3980 | 578868 3981 | 351898 3982 | 378307 3983 | 153981 3984 | 224731 3985 | 478652 3986 | 260778 3987 | 150753 3988 | 580769 3989 | 435025 3990 | 443654 3991 | 511863 3992 | 482836 3993 | 255655 3994 | 176341 3995 | 404201 3996 | 179158 3997 | 47087 3998 | 552648 3999 | 509181 4000 | 242523 4001 | 87762 4002 | 55807 4003 | 548091 4004 | 22032 4005 | 180329 4006 | 352484 4007 | 115859 4008 | 561396 4009 | 369844 4010 | 155855 4011 | 421974 4012 | 555070 4013 | 99750 4014 | 170788 4015 | 309671 4016 | 111878 4017 | 74637 4018 | 567513 4019 | 19531 4020 | 365310 4021 | 579533 4022 | 40599 4023 | 505934 4024 | 82298 4025 | 155944 4026 | 440950 4027 | 171005 4028 | 180586 4029 | 58662 4030 | 225279 4031 | 22802 4032 | 165297 4033 | 161537 4034 | 418590 4035 | 475699 4036 | 26931 4037 | 535130 4038 | 89122 4039 | 461305 4040 | 499336 4041 | 171718 4042 | 443666 4043 | 294246 4044 | 409205 4045 | 525565 4046 | 559913 4047 | 537141 4048 | 159978 4049 | 264769 4050 | 344260 4051 | 432373 4052 | 221945 4053 | 520357 4054 | 92092 4055 | 332061 4056 | 373269 4057 | 288497 4058 | 143810 4059 | 456347 4060 | 418722 4061 | 520732 4062 | 196248 4063 | 152435 4064 | 471869 4065 | 298920 4066 | 129868 4067 | 153970 4068 | 373446 4069 | 107114 4070 | 143442 4071 | 320697 4072 | 501769 4073 | 63190 4074 | 347935 4075 | 62445 4076 | 48662 4077 | 114742 4078 | 399260 4079 | 566771 4080 | 378209 4081 | 78151 4082 | 528674 4083 | 205663 4084 | 131978 4085 | 432405 4086 | 88563 4087 | 9016 4088 | 347922 4089 | 425207 4090 | 474875 4091 | 537195 4092 | 479220 4093 | 59480 4094 | 318369 4095 | 536168 4096 | 487390 4097 | 161732 4098 | 90385 4099 | 389791 4100 | 42792 4101 | 92485 4102 | 417123 4103 | 277917 4104 | 205482 4105 | 516867 4106 | 53592 4107 | 101893 4108 | 441494 4109 | 188243 4110 | 242447 4111 | 318029 4112 | 220091 4113 | 253578 4114 | 114656 4115 | 24753 4116 | 225674 4117 | 263522 4118 | 18914 4119 | 59156 4120 | 570136 4121 | 344724 4122 | 331962 4123 | 300013 4124 | 326925 4125 | 542263 4126 | 530112 4127 | 413580 4128 | 10613 4129 | 245185 4130 | 308976 4131 | 92498 4132 | 387135 4133 | 179190 4134 | 234104 4135 | 244985 4136 | 497562 4137 | 190248 4138 | 512419 4139 | 173541 4140 | 556172 4141 | 264911 4142 | 516234 4143 | 356199 4144 | 125611 4145 | 563514 4146 | 333698 4147 | 207480 4148 | 93172 4149 | 87545 4150 | 354148 4151 | 215797 4152 | 139438 4153 | 389797 4154 | 152988 4155 | 151839 4156 | 42116 4157 | 131695 4158 | 371677 4159 | 290343 4160 | 270658 4161 | 228785 4162 | 189532 4163 | 222002 4164 | 550452 4165 | 53430 4166 | 362411 4167 | 483802 4168 | 131700 4169 | 221336 4170 | 410086 4171 | 273806 4172 | 556228 4173 | 390757 4174 | 452020 4175 | 323565 4176 | 405712 4177 | 381330 4178 | 429469 4179 | 534779 4180 | 48287 4181 | 492780 4182 | 493334 4183 | 88819 4184 | 233627 4185 | 400693 4186 | 422187 4187 | 196781 4188 | 371466 4189 | 196931 4190 | 95768 4191 | 135507 4192 | 515586 4193 | 156784 4194 | 342032 4195 | 136189 4196 | 580635 4197 | 83204 4198 | 569350 4199 | 423785 4200 | 561795 4201 | 74756 4202 | 337584 4203 | 533147 4204 | 295438 4205 | 499924 4206 | 291844 4207 | 57319 4208 | 293001 4209 | 416839 4210 | 76928 4211 | 407332 4212 | 126213 4213 | 527790 4214 | 561926 4215 | 417865 4216 | 258729 4217 | 524628 4218 | 498987 4219 | 433046 4220 | 437160 4221 | 341134 4222 | 146159 4223 | 85418 4224 | 254831 4225 | 69246 4226 | 169770 4227 | 178221 4228 | 574833 4229 | 147424 4230 | 303698 4231 | 237206 4232 | 441498 4233 | 487905 4234 | 278793 4235 | 454760 4236 | 461748 4237 | 215304 4238 | 246207 4239 | 563340 4240 | 81633 4241 | 443448 4242 | 553713 4243 | 486199 4244 | 261339 4245 | 352075 4246 | 275166 4247 | 300361 4248 | 286504 4249 | 461092 4250 | 571471 4251 | 187249 4252 | 162004 4253 | 578456 4254 | 540120 4255 | 492932 4256 | 480578 4257 | 205585 4258 | 476081 4259 | 515940 4260 | 82794 4261 | 343007 4262 | 498589 4263 | 467811 4264 | 117397 4265 | 430063 4266 | 219434 4267 | 125114 4268 | 359637 4269 | 228265 4270 | 30166 4271 | 195585 4272 | 352653 4273 | 219850 4274 | 521121 4275 | 430992 4276 | 105288 4277 | 9731 4278 | 571877 4279 | 302108 4280 | 347567 4281 | 529164 4282 | 223011 4283 | 385976 4284 | 314162 4285 | 328215 4286 | 273132 4287 | 363424 4288 | 512702 4289 | 172952 4290 | 252725 4291 | 342813 4292 | 375824 4293 | 493114 4294 | 200437 4295 | 458175 4296 | 377200 4297 | 405039 4298 | 261539 4299 | 241498 4300 | 338514 4301 | 274022 4302 | 254245 4303 | 509191 4304 | 151305 4305 | 376634 4306 | 522173 4307 | 187921 4308 | 85010 4309 | 298139 4310 | 327759 4311 | 171906 4312 | 330793 4313 | 299869 4314 | 30484 4315 | 426551 4316 | 343569 4317 | 566066 4318 | 461746 4319 | 95905 4320 | 211310 4321 | 184259 4322 | 59962 4323 | 217529 4324 | 470331 4325 | 493396 4326 | 51822 4327 | 52180 4328 | 335707 4329 | 422831 4330 | 329577 4331 | 367693 4332 | 312459 4333 | 563231 4334 | 231134 4335 | 3527 4336 | 256879 4337 | 411129 4338 | 282880 4339 | 321430 4340 | 76232 4341 | 83104 4342 | 487615 4343 | 169070 4344 | 370770 4345 | 498229 4346 | 401854 4347 | 428255 4348 | 554337 4349 | 78306 4350 | 260782 4351 | 569229 4352 | 205825 4353 | 364252 4354 | 339924 4355 | 360519 4356 | 491592 4357 | 88617 4358 | 425285 4359 | 534712 4360 | 136503 4361 | 177190 4362 | 396611 4363 | 216301 4364 | 167150 4365 | 352635 4366 | 225307 4367 | 222511 4368 | 134570 4369 | 252680 4370 | 203385 4371 | 209432 4372 | 493288 4373 | 402422 4374 | 486504 4375 | 113835 4376 | 335928 4377 | 394055 4378 | 391257 4379 | 525305 4380 | 368855 4381 | 431941 4382 | 33071 4383 | 191101 4384 | 263359 4385 | 247858 4386 | 56146 4387 | 1720 4388 | 88639 4389 | 428914 4390 | 348718 4391 | 229488 4392 | 18784 4393 | 453442 4394 | 204238 4395 | 42519 4396 | 428525 4397 | 383603 4398 | 54391 4399 | 414548 4400 | 160095 4401 | 112376 4402 | 526220 4403 | 315166 4404 | 529289 4405 | 197260 4406 | 189926 4407 | 542543 4408 | 253296 4409 | 172913 4410 | 469894 4411 | 412167 4412 | 497018 4413 | 542528 4414 | 1540 4415 | 173860 4416 | 11243 4417 | 425993 4418 | 83390 4419 | 251988 4420 | 80021 4421 | 353929 4422 | 469687 4423 | 333191 4424 | 541396 4425 | 36863 4426 | 321628 4427 | 335796 4428 | 210480 4429 | 526617 4430 | 401126 4431 | 360947 4432 | 246291 4433 | 136032 4434 | 376454 4435 | 444480 4436 | 276217 4437 | 212031 4438 | 533957 4439 | 280556 4440 | 440705 4441 | 204370 4442 | 275579 4443 | 56656 4444 | 398767 4445 | 216240 4446 | 98934 4447 | 478457 4448 | 392433 4449 | 187014 4450 | 513179 4451 | 395200 4452 | 186166 4453 | 539292 4454 | 86504 4455 | 515355 4456 | 285361 4457 | 516167 4458 | 198620 4459 | 192013 4460 | 41311 4461 | 441445 4462 | 178431 4463 | 523396 4464 | 267349 4465 | 360477 4466 | 542450 4467 | 238167 4468 | 525794 4469 | 249805 4470 | 535050 4471 | 86602 4472 | 524779 4473 | 292699 4474 | 400485 4475 | 295397 4476 | 350659 4477 | 499848 4478 | 70722 4479 | 460593 4480 | 444483 4481 | 398880 4482 | 137596 4483 | 321398 4484 | 348554 4485 | 395569 4486 | 558823 4487 | 390916 4488 | 449994 4489 | 97431 4490 | 531612 4491 | 213998 4492 | 368510 4493 | 53539 4494 | 220135 4495 | 152514 4496 | 479777 4497 | 358574 4498 | 185454 4499 | 196204 4500 | 64293 4501 | 230945 4502 | 557631 4503 | 417735 4504 | 507054 4505 | 209512 4506 | 201412 4507 | 228980 4508 | 279641 4509 | 105133 4510 | 243921 4511 | 386997 4512 | 95155 4513 | 301871 4514 | 39052 4515 | 555643 4516 | 342415 4517 | 162074 4518 | 58265 4519 | 114459 4520 | 154881 4521 | 468909 4522 | 87519 4523 | 106477 4524 | 462635 4525 | 288849 4526 | 260476 4527 | 4381 4528 | 274960 4529 | 499541 4530 | 79566 4531 | 186594 4532 | 133422 4533 | 283846 4534 | 306461 4535 | 403919 4536 | 133805 4537 | 280825 4538 | 114584 4539 | 261027 4540 | 29525 4541 | 580966 4542 | 233163 4543 | 117920 4544 | 44770 4545 | 85587 4546 | 238745 4547 | 465755 4548 | 178283 4549 | 104161 4550 | 424163 4551 | 432232 4552 | 357070 4553 | 40821 4554 | 362750 4555 | 195882 4556 | 162132 4557 | 99122 4558 | 239870 4559 | 136320 4560 | 471311 4561 | 6012 4562 | 411940 4563 | 118173 4564 | 147855 4565 | 86773 4566 | 293552 4567 | 3282 4568 | 306412 4569 | 23875 4570 | 473039 4571 | 553061 4572 | 134785 4573 | 346393 4574 | 417161 4575 | 547012 4576 | 304989 4577 | 383186 4578 | 348265 4579 | 57136 4580 | 115197 4581 | 421372 4582 | 441035 4583 | 473453 4584 | 42497 4585 | 250221 4586 | 158918 4587 | 289686 4588 | 261505 4589 | 407681 4590 | 108393 4591 | 73142 4592 | 243846 4593 | 183556 4594 | 443071 4595 | 211117 4596 | 215759 4597 | 579700 4598 | 321099 4599 | 512901 4600 | 504707 4601 | 551882 4602 | 469616 4603 | 478988 4604 | 495329 4605 | 95557 4606 | 548222 4607 | 391204 4608 | 89136 4609 | 84797 4610 | 162056 4611 | 254343 4612 | 316183 4613 | 350707 4614 | 542161 4615 | 34421 4616 | 559620 4617 | 549322 4618 | 219789 4619 | 165160 4620 | 74582 4621 | 195092 4622 | 572257 4623 | 408812 4624 | 168143 4625 | 115242 4626 | 468824 4627 | 358566 4628 | 318094 4629 | 256512 4630 | 321153 4631 | 576657 4632 | 237779 4633 | 127121 4634 | 70773 4635 | 139726 4636 | 278143 4637 | 412877 4638 | 108458 4639 | 271218 4640 | 502570 4641 | 239337 4642 | 349923 4643 | 11025 4644 | 379371 4645 | 491718 4646 | 359619 4647 | 281454 4648 | 501512 4649 | 478200 4650 | 294262 4651 | 546772 4652 | 473418 4653 | 541826 4654 | 571246 4655 | 534867 4656 | 245550 4657 | 352041 4658 | 425628 4659 | 472493 4660 | 122965 4661 | 547652 4662 | 539952 4663 | 205985 4664 | 570145 4665 | 454597 4666 | 32671 4667 | 95192 4668 | 9019 4669 | 432301 4670 | 267044 4671 | 50506 4672 | 213213 4673 | 546006 4674 | 455454 4675 | 509304 4676 | 123421 4677 | 466143 4678 | 435257 4679 | 142179 4680 | 53691 4681 | 170555 4682 | 77482 4683 | 348186 4684 | 430657 4685 | 25071 4686 | 200619 4687 | 185421 4688 | 87255 4689 | 183644 4690 | 220352 4691 | 434417 4692 | 262943 4693 | 574119 4694 | 552352 4695 | 185900 4696 | 207416 4697 | 298002 4698 | 242776 4699 | 161199 4700 | 88588 4701 | 503658 4702 | 287027 4703 | 357081 4704 | 574989 4705 | 426665 4706 | 360313 4707 | 546708 4708 | 295602 4709 | 295163 4710 | 329047 4711 | 105863 4712 | 95106 4713 | 475808 4714 | 169970 4715 | 512296 4716 | 254455 4717 | 141782 4718 | 327390 4719 | 491337 4720 | 181069 4721 | 148992 4722 | 423842 4723 | 279600 4724 | 242038 4725 | 183652 4726 | 497888 4727 | 520863 4728 | 212135 4729 | 315840 4730 | 360260 4731 | 34724 4732 | 83998 4733 | 547317 4734 | 13674 4735 | 457029 4736 | 288048 4737 | 381796 4738 | 455560 4739 | 301456 4740 | 580052 4741 | 472240 4742 | 168542 4743 | 251280 4744 | 364561 4745 | 579963 4746 | 180484 4747 | 106842 4748 | 45422 4749 | 448527 4750 | 108937 4751 | 353147 4752 | 200542 4753 | 305129 4754 | 61836 4755 | 117649 4756 | 232765 4757 | 8044 4758 | 55667 4759 | 317404 4760 | 225452 4761 | 86950 4762 | 23446 4763 | 295930 4764 | 457636 4765 | 133569 4766 | 183097 4767 | 484700 4768 | 307041 4769 | 428523 4770 | 261116 4771 | 151623 4772 | 406279 4773 | 356776 4774 | 452559 4775 | 100910 4776 | 117634 4777 | 505994 4778 | 60 4779 | 508539 4780 | 6831 4781 | 492979 4782 | 402553 4783 | 317075 4784 | 46535 4785 | 1797 4786 | 206069 4787 | 8035 4788 | 448603 4789 | 461635 4790 | 271093 4791 | 288508 4792 | 93438 4793 | 407283 4794 | 543058 4795 | 282958 4796 | 489564 4797 | 335508 4798 | 227043 4799 | 174916 4800 | 98241 4801 | 300781 4802 | 52169 4803 | 175647 4804 | 16963 4805 | 189113 4806 | 76771 4807 | 396206 4808 | 38136 4809 | 347085 4810 | 88336 4811 | 120274 4812 | 465128 4813 | 526172 4814 | 326542 4815 | 531759 4816 | 201369 4817 | 85719 4818 | 253701 4819 | 476379 4820 | 283565 4821 | 326665 4822 | 333645 4823 | 289202 4824 | 273885 4825 | 342928 4826 | 324321 4827 | 91524 4828 | 280040 4829 | 129669 4830 | 177727 4831 | 551953 4832 | 345256 4833 | 325934 4834 | 527698 4835 | 185463 4836 | 395672 4837 | 167742 4838 | 47408 4839 | 476508 4840 | 235798 4841 | 547827 4842 | 210446 4843 | 202101 4844 | 536596 4845 | 139511 4846 | 486271 4847 | 324 4848 | 128775 4849 | 83759 4850 | 577250 4851 | 536019 4852 | 23458 4853 | 87108 4854 | 454428 4855 | 557669 4856 | 106411 4857 | 260624 4858 | 230295 4859 | 317458 4860 | 338460 4861 | 374845 4862 | 282424 4863 | 322976 4864 | 288175 4865 | 212603 4866 | 13877 4867 | 425481 4868 | 310360 4869 | 318256 4870 | 209370 4871 | 210152 4872 | 272912 4873 | 519885 4874 | 694 4875 | 167271 4876 | 158588 4877 | 116439 4878 | 185716 4879 | 332922 4880 | 421935 4881 | 580714 4882 | 32274 4883 | 311583 4884 | 78741 4885 | 271183 4886 | 201491 4887 | 65819 4888 | 237520 4889 | 327494 4890 | 380914 4891 | 507120 4892 | 248135 4893 | 349475 4894 | 51322 4895 | 525844 4896 | 304063 4897 | 346434 4898 | 387958 4899 | 177476 4900 | 522431 4901 | 64382 4902 | 503277 4903 | 317479 4904 | 189670 4905 | 546550 4906 | 289244 4907 | 39741 4908 | 266979 4909 | 260631 4910 | 211932 4911 | 548506 4912 | 571313 4913 | 369424 4914 | 418167 4915 | 156481 4916 | 447951 4917 | 461264 4918 | 309213 4919 | 200998 4920 | 271948 4921 | 54445 4922 | 205377 4923 | 248869 4924 | 570656 4925 | 399662 4926 | 346772 4927 | 22061 4928 | 168128 4929 | 161046 4930 | 236256 4931 | 414323 4932 | 415047 4933 | 100191 4934 | 508213 4935 | 84680 4936 | 439514 4937 | 141515 4938 | 577616 4939 | 569838 4940 | 59567 4941 | 329717 4942 | 370083 4943 | 230267 4944 | 491371 4945 | 167582 4946 | 410470 4947 | 107293 4948 | 474399 4949 | 499536 4950 | 519947 4951 | 74347 4952 | 252883 4953 | 505551 4954 | 162059 4955 | 567387 4956 | 129468 4957 | 195207 4958 | 239298 4959 | 298221 4960 | 568005 4961 | 435543 4962 | 531189 4963 | 417635 4964 | 484028 4965 | 381336 4966 | 520797 4967 | 485140 4968 | 531560 4969 | 356076 4970 | 571019 4971 | 69903 4972 | 231735 4973 | 239793 4974 | 489347 4975 | 277504 4976 | 572205 4977 | 314923 4978 | 554181 4979 | 528927 4980 | 550792 4981 | 387189 4982 | 98755 4983 | 88223 4984 | 208546 4985 | 241116 4986 | 421677 4987 | 72014 4988 | 555925 4989 | 250262 4990 | 370893 4991 | 731 4992 | 144311 4993 | 65026 4994 | 579123 4995 | 217136 4996 | 53442 4997 | 536070 4998 | 557943 4999 | 505791 5000 | 544933 5001 | -------------------------------------------------------------------------------- /env.yml: -------------------------------------------------------------------------------- 1 | name: env_ghhc 2 | channels: 3 | - defaults 4 | dependencies: 5 | - _libgcc_mutex=0.1=main 6 | - blas=1.0=mkl 7 | - c-ares=1.15.0=h7b6447c_1001 8 | - ca-certificates=2019.10.16=0 9 | - certifi=2019.9.11=py36_0 10 | - gast=0.3.2=py_0 11 | - hdf5=1.10.4=hb1b8bf9_0 12 | - intel-openmp=2019.4=243 13 | - joblib=0.14.0=py_0 14 | - keras-applications=1.0.8=py_0 15 | - keras-preprocessing=1.1.0=py_1 16 | - libedit=3.1.20181209=hc058e9b_0 17 | - libffi=3.2.1=hd88cf55_4 18 | - libgcc-ng=9.1.0=hdf63c60_0 19 | - libgfortran-ng=7.3.0=hdf63c60_0 20 | - libprotobuf=3.10.1=hd408876_0 21 | - libstdcxx-ng=9.1.0=hdf63c60_0 22 | - mkl=2019.4=243 23 | - mkl-service=2.3.0=py36he904b0f_0 24 | - mkl_fft=1.0.15=py36ha843d7b_0 25 | - mkl_random=1.1.0=py36hd6b4f25_0 26 | - mock=3.0.5=py36_0 27 | - ncurses=6.1=he6710b0_1 28 | - numpy-base=1.17.4=py36hde5b4d6_0 29 | - openssl=1.1.1d=h7b6447c_3 30 | - pip=19.3.1=py36_0 31 | - python=3.6.9=h265db76_0 32 | - readline=7.0=h7b6447c_5 33 | - scikit-learn=0.21.3=py36hd81dba3_0 34 | - scipy=1.3.1=py36h7c811a0_0 35 | - setuptools=42.0.1=py36_0 36 | - six=1.13.0=py36_0 37 | - sqlite=3.30.1=h7b6447c_0 38 | - tensorflow-base=1.13.1=mkl_py36h7ce6ba3_0 39 | - tensorflow-estimator=1.13.0=py_0 40 | - tk=8.6.8=hbc83047_0 41 | - wheel=0.33.6=py36_0 42 | - xz=5.2.4=h14c3975_4 43 | - zlib=1.2.11=h7b6447c_3 44 | - pip: 45 | - absl-py==0.8.1 46 | - astor==0.8.0 47 | - grpcio==1.25.0 48 | - h5py==2.10.0 49 | - markdown==3.1.1 50 | - numpy==1.17.4 51 | - protobuf==3.11.0 52 | - tensorboard==1.12.2 53 | - tensorflow==1.12.0 54 | - termcolor==1.1.0 55 | - werkzeug==0.16.0 56 | prefix: /path/to/anaconda3/envs/env_ghhc 57 | 58 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | edu.umass.cs.iesl 6 | ghhc 7 | 0.1-SNAPSHOT 8 | 2019 9 | 10 | 2.11 11 | .7 12 | 13 | 14 | 15 | 16 | scala-tools.org 17 | Scala-Tools Maven2 Repository 18 | http://scala-tools.org/repo-releases 19 | 20 | 21 | sonatype-snapshot 22 | https://oss.sonatype.org/content/repositories/snapshots 23 | 24 | 25 | 26 | 27 | 28 | scala-tools.org 29 | Scala-Tools Maven2 Repository 30 | http://scala-tools.org/repo-releases 31 | 32 | 33 | 34 | 35 | 36 | org.scala-lang 37 | scala-library 38 | ${scala.majorVersion}${scala.minorVersion} 39 | 40 | 41 | cc.factorie 42 | factorie_${scala.majorVersion} 43 | 1.2 44 | 45 | 46 | com.google.guava 47 | guava 48 | 21.0 49 | 50 | 51 | org.scala-lang 52 | scala-xml 53 | 2.11.0-M4 54 | 55 | 56 | 57 | 58 | src/scala 59 | 60 | 61 | org.scala-tools 62 | maven-scala-plugin 63 | 64 | 65 | 66 | compile 67 | testCompile 68 | 69 | 70 | 71 | 72 | ${scala.majorVersion}${scala.minorVersion} 73 | 74 | 75 | 76 | org.apache.maven.plugins 77 | maven-compiler-plugin 78 | 3.6.1 79 | 80 | 1.8 81 | 1.8 82 | 83 | 84 | 85 | org.apache.maven.plugins 86 | maven-eclipse-plugin 87 | 88 | true 89 | 90 | ch.epfl.lamp.sdt.core.scalabuilder 91 | 92 | 93 | ch.epfl.lamp.sdt.core.scalanature 94 | 95 | 96 | org.eclipse.jdt.launching.JRE_CONTAINER 97 | ch.epfl.lamp.sdt.launching.SCALA_CONTAINER 98 | 99 | 100 | 101 | 102 | maven-assembly-plugin 103 | 2.4 104 | 105 | 106 | make-assembly 107 | package 108 | 109 | attached 110 | 111 | 112 | 113 | 114 | gnu 115 | 116 | jar-with-dependencies 117 | 118 | 119 | 120 | 121 | 122 | org.apache.maven.plugins 123 | maven-surefire-plugin 124 | 2.7 125 | 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | net.alchim31.maven 135 | scala-maven-plugin 136 | 3.2.0 137 | 138 | 139 | -deprecation 140 | -feature 141 | -optimise 142 | -Yclosure-elim 143 | -Yinline 144 | 145 | 146 | -Xms64m 147 | -Xmx1024m 148 | 149 | 150 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /src/python/ghhc/inference/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmonath/hyperbolic_hierarchical_clustering/c78099d4d576831e414fa1c26ceec8622572dfaa/src/python/ghhc/inference/__init__.py -------------------------------------------------------------------------------- /src/python/ghhc/inference/run_inference.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Authors of gHHC 3 | This file is part of "hyperbolic_hierarchical_clustering" 4 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | """ 15 | 16 | import sys 17 | import os 18 | import datetime 19 | import numpy as np 20 | 21 | from absl import logging 22 | import tensorflow as tf 23 | 24 | from ghhc.util.Config import Config 25 | from ghhc.util.load import load 26 | from ghhc.util.initializers import random_pts,init_from_afkmc2_and_hac,init_from_rand_and_hac 27 | from ghhc.model.ghhc import gHHCTree, gHHCInference 28 | from ghhc.util.io import mkdir_p 29 | 30 | tf.enable_eager_execution() 31 | 32 | logging.set_verbosity(logging.INFO) 33 | 34 | 35 | if __name__ == "__main__": 36 | 37 | config = Config(sys.argv[1]) 38 | 39 | now = datetime.datetime.now() 40 | ts = "{:04d}-{:02d}-{:02d}-{:02d}-{:02d}-{:02d}".format( 41 | now.year, now.month, now.day, now.hour, now.minute, now.second) 42 | config.exp_out_dir = os.path.join(config.exp_out_base, config.dataset_name, config.alg_name, "%s-%s" %(ts,config.to_filename())) 43 | config.checkpoint_dir = os.path.join(config.exp_out_dir, 'models', 'ckpt') 44 | mkdir_p(config.exp_out_dir) 45 | mkdir_p(os.path.join(config.exp_out_dir, 'models')) 46 | config.save_config(config.exp_out_dir,config.to_filename() + ".json") 47 | config.save_config(config.exp_out_dir) 48 | 49 | pids, lbls, dataset = load(config.inference_file, config) 50 | 51 | dev_pids, dev_lbls, dev_dataset = load(config.dev_file, config) 52 | 53 | if config.random_projection is not None: 54 | logging.info('Using random projection: %s', config.random_projection) 55 | _proj = np.random.randn(dataset.shape[1], config.random_projection).astype(np.float32) 56 | def p(x): 57 | projd = tf.matmul(x, _proj) 58 | projd /= tf.linalg.norm(projd,axis=1,keepdims=True) 59 | projd = tf.clip_by_norm(projd, 0.9, axes=[1]) 60 | return projd 61 | proj = lambda x: p(x) 62 | init_tree = random_pts(proj(dataset).numpy(), config.num_internals, config.random_pts_scale) 63 | else: 64 | if config.init_method == 'randompts': 65 | init_tree = random_pts(dataset, config.num_internals, config.random_pts_scale) 66 | elif config.init_method == 'afkmc2hac': 67 | init_tree = init_from_afkmc2_and_hac(dataset, config.num_internals) 68 | elif config.init_method == 'randhac': 69 | init_tree = init_from_rand_and_hac(dataset, config.num_internals, config.random_pts_scale) 70 | proj = None 71 | 72 | tree = gHHCTree(init_tree.copy(), config=config, projection=proj) 73 | optimizer = tf.train.GradientDescentOptimizer(config.tree_learning_rate) 74 | inf = gHHCInference(tree, optimizer, config, dev_dataset, dev_lbls) 75 | 76 | samples = np.load(config.sample_file) 77 | inf.inference(samples, dataset, config.batch_size) -------------------------------------------------------------------------------- /src/python/ghhc/inference/run_predict_only.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Authors of gHHC 3 | This file is part of "hyperbolic_hierarchical_clustering" 4 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | """ 15 | 16 | import sys 17 | import os 18 | import datetime 19 | import numpy as np 20 | 21 | from absl import logging 22 | from absl import flags 23 | from absl import app 24 | 25 | import tensorflow as tf 26 | 27 | from ghhc.util.Config import Config 28 | from ghhc.util.load import load 29 | from ghhc.util.initializers import random_pts 30 | from ghhc.model.ghhc import gHHCTree, gHHCInference 31 | from ghhc.util.io import mkdir_p 32 | 33 | tf.enable_eager_execution() 34 | 35 | FLAGS = flags.FLAGS 36 | 37 | flags.DEFINE_string('config', None, "Config file") 38 | flags.DEFINE_string('data_filename',None, 'data filename') 39 | flags.DEFINE_string('output_filename', 'tree.tsv', 'output filename') 40 | logging.set_verbosity(logging.INFO) 41 | 42 | 43 | def main(argv): 44 | config = Config(FLAGS.config) 45 | 46 | filename = FLAGS.data_filename if FLAGS.data_filename is not None else config.inference_file 47 | 48 | assert(config.exp_out_dir is not None) 49 | assert (config.last_model is not None) 50 | 51 | config.exp_out_dir = os.path.join(config.exp_out_dir, 'results') 52 | mkdir_p(config.exp_out_dir) 53 | config.save_config(config.exp_out_dir,config.to_filename() + ".json") 54 | config.save_config(config.exp_out_dir) 55 | 56 | pids, lbls, dataset = load(filename, config) 57 | 58 | dev_pids, dev_lbls, dev_dataset = load(config.dev_file, config) 59 | 60 | init_tree = random_pts(dataset, config.num_internals, config.random_pts_scale) 61 | 62 | tree = gHHCTree(init_tree.copy(), config=config) 63 | optimizer = tf.train.GradientDescentOptimizer(config.tree_learning_rate) 64 | inf = gHHCInference(tree, optimizer, config, dev_dataset, dev_lbls) 65 | inf.ckpt.restore(tf.train.latest_checkpoint(inf.config.checkpoint_dir)) 66 | 67 | tree.write_tsv(config.exp_out_dir + "/" + FLAGS.output_filename, dataset, lbls=lbls, pids=pids) 68 | 69 | if __name__ == '__main__': 70 | app.run(main) -------------------------------------------------------------------------------- /src/python/ghhc/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmonath/hyperbolic_hierarchical_clustering/c78099d4d576831e414fa1c26ceec8622572dfaa/src/python/ghhc/model/__init__.py -------------------------------------------------------------------------------- /src/python/ghhc/model/ghhc.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Authors of gHHC 3 | This file is part of "hyperbolic_hierarchical_clustering" 4 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | """ 15 | 16 | import os 17 | import time 18 | 19 | import numpy as np 20 | import tensorflow as tf 21 | 22 | from ghhc.util.eval_dp import eval_dp 23 | from ghhc.util.io import mkdir_p 24 | 25 | from absl import logging 26 | 27 | tf.enable_eager_execution() 28 | 29 | def squared_norm(x, axis=1, keepdims=True): 30 | """Squared L2 Norm of x.""" 31 | return tf.reduce_sum(tf.pow(x, 2), axis=axis, keepdims=keepdims) 32 | 33 | 34 | def squared_euclidean_cdist(x, y): 35 | """Squared euclidean distance 36 | 37 | Computed as: ||x||^2 + ||y||^2 - 2 x^T y. 38 | 39 | Args: 40 | x: N by D matrix 41 | y: M by D matrix 42 | :returns matrix (N by M) such that result[i,j] = || x[i,:] - y[j,;] ||^2 43 | """ 44 | norms = squared_norm(x, axis=1, keepdims=True) + tf.transpose(squared_norm(y, axis=1, keepdims=True)) 45 | dot = 2.0*tf.matmul(x, y, transpose_b=True) 46 | return norms - dot 47 | 48 | def poincare_cdist(x, y): 49 | """Poincare distance 50 | 51 | Args: 52 | x: N by D matrix 53 | y: M by D matrix 54 | :returns matrix (N by M) such that result[i,j] = ppoincare dist(x[i,:], y[j,:]) 55 | """ 56 | numerator = squared_euclidean_cdist(x, y) 57 | denom = (1.0 - squared_norm(x)) * (1.0 - tf.transpose(squared_norm(y, axis=1, keepdims=True))) 58 | arccosh_arg = 1.0 + 2.0 * numerator / denom 59 | res = tf.math.acosh(1e-8 + arccosh_arg) 60 | return res 61 | 62 | 63 | def squared_euclidean_dist(x, y): 64 | """Squared euclidean distance 65 | 66 | Computed as: ||x||^2 + ||y||^2 - 2 x^T y. 67 | 68 | Args: 69 | x: N by D matrix 70 | y: N by D matrix 71 | :returns vector (N by 1) such that the ith element is || x[i,:] - y[i,;] ||^2 72 | """ 73 | norms = squared_norm(x, axis=1, keepdims=True) + squared_norm(y, axis=1, keepdims=True) 74 | dot = 2*tf.reduce_sum(tf.multiply(x, y), axis=1, keepdims=True) 75 | return norms - dot 76 | 77 | 78 | def poincare_dist(x, y): 79 | """Poincare distance between x and y. 80 | 81 | Args: 82 | x: N by D matrix 83 | y: N by D matrix 84 | :returns vector (N by 1) such that the ith element is poincare dist(x[i,:], y[i,:]) 85 | """ 86 | numerator = squared_euclidean_dist(x, y) 87 | denom = (1.0 - squared_norm(x)) * (1.0 - squared_norm(y)) 88 | arccosh_arg = 1.0 + 2.0 * numerator / denom 89 | res = tf.math.acosh(arccosh_arg) 90 | return res 91 | 92 | 93 | def poincare_norm(x, axis=1, keepdims=True): 94 | """Squared poincare norm of x.""" 95 | return 2.0*tf.math.atanh(tf.linalg.norm(x, axis=axis, keepdims=keepdims)) 96 | 97 | 98 | def parent_order_penalty(p, c, marg): 99 | """Penalty for parents to have smaller norm than children.""" 100 | return tf.maximum(0.0, poincare_norm(p) - poincare_norm(c) + marg) + 1.0 101 | 102 | 103 | def parent_order_penalty_cdist(p, c, marg): 104 | """Penalty for parents to have smaller norm than children.""" 105 | return tf.maximum(0.0, tf.transpose(poincare_norm(p)) - poincare_norm(c) + marg) + 1.0 106 | 107 | 108 | class gHHCTree(tf.keras.Model): 109 | """Object for a ghhc tree.""" 110 | 111 | def __init__(self, init_tree=None, gamma=0.25, config=None, projection=None): 112 | super(gHHCTree, self).__init__() 113 | self.internals = tf.get_variable('internals', initializer=init_tree) 114 | self.max_norm = 0.8 115 | self.internals_so_far = 0 116 | self.gamma = gamma 117 | self.config = config 118 | self.projection = None 119 | self.cached_pairs = None 120 | if projection is not None: 121 | self.projection = projection 122 | else: 123 | self.projection = lambda x: x 124 | 125 | def project(self, x_i, x_j, x_k): 126 | return self.projection(x_i), self.projection(x_j), self.projection(x_k) 127 | 128 | def clip(self): 129 | tf.assign(self.internals, tf.clip_by_norm(self.internals, self.max_norm, axes=[1])) 130 | 131 | def p_par_broadcast(self, x_i): 132 | return self.p_par_to_broadcast(x_i, self.internals) 133 | 134 | def p_par_to_broadcast(self, x_i, nodes): 135 | dists = poincare_cdist(x_i, nodes) 136 | res = tf.multiply(dists, parent_order_penalty_cdist(nodes, x_i, self.gamma)) 137 | return res 138 | 139 | def p_par_to(self, x_i, nodes): 140 | dists = poincare_dist(x_i, nodes) 141 | res = tf.multiply(dists, parent_order_penalty(nodes, x_i, self.gamma)) 142 | return res 143 | 144 | def p_par_to_batched_np(self, x_i, nodes, batch_size=1000): 145 | dists = np.zeros((x_i.shape[0], nodes.shape[0]), np.float32) 146 | for i in range(0, x_i.shape[0], batch_size): 147 | logging.log_every_n_seconds(logging.INFO,'p_par_to_batched_np processed %s of %s', 5, i, x_i.shape[0]) 148 | for j in range(0, nodes.shape[0], batch_size): 149 | dists[i:(i+batch_size), j:(j+batch_size)] = self.p_par_to_broadcast(x_i[i:(i + batch_size), :], nodes[j:(j + batch_size), :]).numpy() 150 | return dists 151 | 152 | def compute_loss(self, x_i, x_j, x_k): 153 | x_i, x_j, x_k = self.project(x_i, x_j, x_k) 154 | 155 | x_i_dists = self.p_par_to_broadcast(x_i, self.internals) 156 | x_j_dists = self.p_par_to_broadcast(x_j, self.internals) 157 | x_k_dists = self.p_par_to_broadcast(x_k, self.internals) 158 | 159 | max_dists_ij = tf.maximum(x_i_dists, x_j_dists) 160 | gumbel_ij_noise = tf.log(-tf.log(tf.random_uniform(tf.shape(max_dists_ij)))) 161 | gumbel_ijk_noise = tf.log(-tf.log(tf.random_uniform(tf.shape(max_dists_ij)))) 162 | max_dists_ijk = tf.maximum(x_k_dists, max_dists_ij) 163 | lca_ij_softmax = tf.nn.softmax(-max_dists_ij+gumbel_ij_noise, axis=1) 164 | lca_ij_idx = tf.argmin(max_dists_ij, axis=1) 165 | offset = np.zeros_like(max_dists_ij) 166 | offset[np.arange(offset.shape[0]), lca_ij_idx] = 1000 167 | 168 | max_dists_ijk += offset 169 | lca_ijk_softmax = tf.nn.softmax(-max_dists_ijk + gumbel_ijk_noise, axis=1) 170 | 171 | logits1 = lca_ij_softmax * x_i_dists - lca_ijk_softmax * x_i_dists 172 | logits2 = lca_ij_softmax * x_j_dists - lca_ijk_softmax * x_j_dists 173 | logits3 = lca_ijk_softmax * x_k_dists - lca_ij_softmax * x_k_dists 174 | 175 | per_ex_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=tf.zeros_like(logits1), logits=logits1) \ 176 | + tf.nn.sigmoid_cross_entropy_with_logits(labels=tf.zeros_like(logits2), logits=logits2) \ 177 | + tf.nn.sigmoid_cross_entropy_with_logits(labels=tf.zeros_like(logits3), logits=logits3) 178 | loss = tf.reduce_sum(per_ex_loss) 179 | return loss 180 | 181 | def p_par_assign_to_internal(self, children, parents, proj_child=True): 182 | if proj_child: 183 | children = self.projection(children) 184 | 185 | internal_norm = tf.norm(parents, axis=1, keepdims=True) 186 | internal_ordering = tf.argsort(-tf.squeeze(internal_norm)).numpy() 187 | back_to_orig = tf.argsort(internal_ordering) 188 | parents = parents[internal_ordering,:] 189 | children = children[internal_ordering,:] 190 | 191 | dists = self.p_par_to_batched_np(children, parents) 192 | dists[np.tril_indices_from(dists)] = np.Inf 193 | np.fill_diagonal(dists, np.Inf) 194 | dists = dists[back_to_orig,:][:,back_to_orig] 195 | assignments = np.argmin(dists, axis=1) 196 | mindists = np.min(dists, axis=1) 197 | assignments[mindists == np.Inf] = -1 198 | return assignments 199 | 200 | def p_par_assign_to(self, children, parents, exclude_diag=False, proj_child=True): 201 | if proj_child: 202 | children = self.projection(children) 203 | dists = self.p_par_to_batched_np(children, parents) 204 | children_norm = tf.norm(children, axis=1, keepdims=True) 205 | internal_norm = tf.norm(parents, axis=1, keepdims=True) 206 | eligible = tf.less(-children_norm + tf.transpose(internal_norm), 0).numpy() 207 | dists[eligible == False] = np.Inf 208 | if exclude_diag: 209 | np.fill_diagonal(dists, np.Inf) 210 | assignments = np.argmin(dists, axis=1) 211 | mindists = np.min(dists, axis=1) 212 | assignments[mindists == np.Inf] = -1 213 | return assignments 214 | 215 | def write_tsv(self, filename, leaves, pids=None, lbls=None, update_cache=True): 216 | logging.info('Writing tree tsv to %s' % filename) 217 | logging.info('num leaves %s' % leaves.shape[0]) 218 | logging.info('pids is None? %s' % (pids is None)) 219 | logging.info('lbls is None? %s' % (lbls is None)) 220 | internals = self.internals.numpy() 221 | leaf_to_par_assign = self.p_par_assign_to(leaves, internals) 222 | internal_to_par_assign = self.p_par_assign_to_internal(internals, internals, proj_child=False) 223 | self.cached_pairs = np.concatenate([ np.expand_dims(np.arange(internal_to_par_assign.shape[0]),1), np.expand_dims(internal_to_par_assign,1)],axis=1) 224 | self.cached_pairs = self.cached_pairs[self.cached_pairs[:,1]!=-1] 225 | with open(filename + '.internals', 'w') as fouti: 226 | with open(filename + '.leaves', 'w') as foutl: 227 | with open(filename, 'w') as fout: 228 | i = -1 229 | pid = 'int_%s' % i 230 | best_pid = 'best_int_%s' % i 231 | par_id = 'None' 232 | fout.write('%s\t%s\tNone\n' % (pid, par_id)) 233 | fout.write('%s\t%s\tNone\n' % (best_pid, pid)) 234 | 235 | fouti.write('%s\t%s\tNone\n' % (pid, par_id)) 236 | fouti.write('%s\t%s\tNone\n' % (best_pid, pid)) 237 | 238 | for i in range(leaf_to_par_assign.shape[0]): 239 | logging.log_every_n_seconds(logging.INFO,'Wrote %s leaves' % i,5) 240 | pid = 'pt_%s' % i if pids is None else pids[i] 241 | lbl = pid if lbls is None else lbls[i] 242 | par_id = 'best_int_%s' % leaf_to_par_assign[i] 243 | fout.write('%s\t%s\t%s\n' % (pid, par_id, lbl)) 244 | foutl.write('%s\t%s\t%s\n' % (pid, par_id, lbl)) 245 | 246 | for i in range(internal_to_par_assign.shape[0]): 247 | logging.log_every_n_seconds(logging.INFO,'Wrote %s internals' % i,5) 248 | pid = 'int_%s' % i 249 | par_id = 'int_%s' % internal_to_par_assign[i] 250 | best_pid = 'best_int_%s' % i 251 | fout.write('%s\t%s\tNone\n' % (pid, par_id)) 252 | fout.write('%s\t%s\tNone\n' % (best_pid, par_id)) 253 | fouti.write('%s\t%s\tNone\n' % (pid, par_id)) 254 | fouti.write('%s\t%s\tNone\n' % (best_pid, par_id)) 255 | 256 | def plot_tree(self, leaves, filename): 257 | internals = self.internals.numpy() 258 | leaf_to_par_assign = self.p_par_assign_to(leaves, internals) 259 | internal_to_par_assign = self.p_par_assign_to_internal(internals, internals, proj_child=False) 260 | import matplotlib 261 | matplotlib.use('Agg') 262 | import matplotlib.pyplot as plt 263 | fig, ax = plt.subplots(figsize=(10, 10)) 264 | ax.spines['top'].set_visible(False) 265 | ax.spines['right'].set_visible(False) 266 | ax.spines['bottom'].set_visible(False) 267 | ax.spines['left'].set_visible(False) 268 | ax.tick_params(axis='x', which='both', bottom='off', top='off', 269 | color='white') 270 | ax.tick_params(axis='y', which='both', left='off', right='off', 271 | color='white') 272 | # plt.scatter(0, 0, label='root', marker='^', zorder=2) 273 | # plt.annotate('root', xy=(0,0), size=3) 274 | 275 | for idx in range(internals.shape[0]): 276 | plt.scatter(internals[idx, 0], internals[idx, 1], label='int_%s' % idx, s=100, marker='^', zorder=2) 277 | # plt.annotate('int_%s' % idx, xy=(internals[idx,0], internals[idx,1]), size=5) 278 | for idx in range(internals.shape[0]): 279 | if internal_to_par_assign[idx] != -1: 280 | plt.plot([internals[idx,0], internals[internal_to_par_assign[idx],0]], 281 | [internals[idx,1], internals[internal_to_par_assign[idx],1]], linewidth=2, 282 | c='k', zorder=1) 283 | # else: 284 | # plt.plot([internals[idx, 0], 0], 285 | # [internals[idx, 1], 0], linewidth=1, 286 | # c='k', zorder=1) 287 | for idx in range(leaves.shape[0]): 288 | plt.scatter(leaves[idx, 0], leaves[idx, 1], s=100, label='%s' % idx, marker='o', zorder=2) 289 | 290 | # plt.annotate('pt_%s' % idx, xy=(leaves[idx, 0], leaves[idx, 1]), size=5) 291 | for idx in range(leaves.shape[0]): 292 | if leaf_to_par_assign[idx] != -1: 293 | # print('gpid %s lpid %s' % (grinch_par_id, leaf_to_par_assign[idx])) 294 | plt.plot([leaves[idx, 0], internals[leaf_to_par_assign[idx], 0]], 295 | [leaves[idx, 1], internals[leaf_to_par_assign[idx], 1]], linewidth=2, 296 | c='k', zorder=1) 297 | # else: 298 | # plt.plot([leaves[idx, 0], 0], 299 | # [leaves[idx, 1], 0], linewidth=1, 300 | # c='k', zorder=1) 301 | plt.xlim([-1.1, 1.1]) 302 | plt.ylim([-1.1, 1.1]) 303 | circle = plt.Circle((0, 0), 1, color='r',linewidth=5, fill=False) 304 | ax.add_artist(circle) 305 | plt.axis('off') 306 | plt.savefig(filename) 307 | 308 | def structure_loss(self): 309 | res = tf.reduce_sum(self.child_parent_norm_loss(self.cached_pairs)) 310 | # logging.log_every_n(logging.INFO,'cp res: %s', 10,res ) 311 | return res 312 | 313 | def child_parent_norm_loss(self, pairs): 314 | internal_norms = poincare_norm(self.internals) 315 | children = tf.gather(internal_norms, pairs[:,0]) 316 | parents = tf.gather(internal_norms, pairs[:,1]) 317 | logits1 = tf.nn.relu(parents - children + self.gamma) 318 | min_norm = tf.argmin(internal_norms).numpy()[0] 319 | logging.log_every_n(logging.INFO,'min_norm %s %s',500,min_norm,internal_norms[min_norm]) 320 | max_norm = tf.argmax(internal_norms).numpy()[0] 321 | logging.log_every_n(logging.INFO, 'max_norm %s %s', 500, max_norm, internal_norms[max_norm]) 322 | return tf.reduce_sum(logits1) 323 | 324 | 325 | def rsgd_or_sgd(grads_and_vars, rsgd=True): 326 | if rsgd: 327 | res = [] 328 | for g,v in grads_and_vars: 329 | scale = ((1.0 - tf.reduce_sum(tf.multiply(v,v),axis=1,keepdims=True)) ** 2) / 4.0 330 | res.append((scale*g, v)) 331 | return res 332 | else: 333 | return grads_and_vars 334 | 335 | class gHHCInference(object): 336 | def __init__(self, ghhcTree, optimizer, config, dev_set, dev_lbls): 337 | self.ghhcTree = ghhcTree 338 | self.optimizer = optimizer 339 | self.config = config 340 | self.dev_set = dev_set 341 | self.dev_lbls = dev_lbls 342 | self.best_dev_dp_score = 0.0 343 | self.best_dev_iter = 0.0 344 | self.last_dev_dp_score = 0.0 345 | self.last_dev_iter = 0.0 346 | self.checkpoint_prefix = self.config.checkpoint_dir + "/ckpt" 347 | self.ckpt = tf.train.Checkpoint(optimizer=optimizer, 348 | model=ghhcTree, 349 | optimizer_step=tf.train.get_or_create_global_step()) 350 | 351 | def update(self, c1, c2, par_id, gp_id, steps=100): 352 | for i in range(steps): 353 | with tf.GradientTape() as tape: 354 | loss = self.ghhcTree.pull_close_par_gp(c1, c2, par_id, gp_id) 355 | grads = tape.gradient(loss, self.ghhcTree.trainable_variables) 356 | self.optimizer.apply_gradients(rsgd_or_sgd(zip(grads, self.ghhcTree.trainable_variables)), 357 | global_step=tf.train.get_or_create_global_step()) 358 | self.ghhcTree.clip() 359 | 360 | def episode_inference(self, x_i, x_j, x_k, dataset, batch_size=1000, examples_so_far=0): 361 | time_so_far = 0.0 362 | loss_so_far = 0.0 363 | struct_loss_so_far = 0.0 364 | 365 | for idx in range(0, x_i.shape[0], batch_size): 366 | 367 | if self.config.struct_prior is not None and idx+examples_so_far > 0: 368 | if self.ghhcTree.cached_pairs is None: 369 | self.dev_eval(idx + examples_so_far) 370 | 371 | if (idx + examples_so_far) % self.config.struct_prior_every == 0: 372 | for idx2 in range(self.config.num_struct_prior_batches): 373 | start_time = time.time() 374 | logging.log_every_n(logging.INFO, 375 | '[STRUCTURE] Processed %s of %s batches || Avg. Loss %s || Avg Time %s' % (idx2, 100, struct_loss_so_far / max(idx2, 1), time_so_far / max(idx2, 1)),100) 376 | with tf.GradientTape() as tape: 377 | sloss = self.ghhcTree.structure_loss() 378 | struct_loss_so_far += sloss.numpy() 379 | grads = tape.gradient(sloss, self.ghhcTree.trainable_variables) 380 | self.optimizer.apply_gradients(rsgd_or_sgd(zip(grads, self.ghhcTree.trainable_variables)), 381 | global_step=tf.train.get_or_create_global_step()) 382 | self.ghhcTree.clip() 383 | end_time = time.time() 384 | time_so_far += end_time - start_time 385 | logging.log(logging.INFO, '[STRUCTURE] Processed %s of %s batches || Avg. Loss %s || Avg Time %s' % (self.config.num_struct_prior_batches, 100, struct_loss_so_far / max(self.config.num_struct_prior_batches, 1), time_so_far / max(self.config.num_struct_prior_batches, 1))) 386 | 387 | if (idx + examples_so_far) % self.config.dev_every == 0: 388 | self.dev_eval(idx + examples_so_far) 389 | elif (idx + examples_so_far ) % self.config.save_every == 0: 390 | self.ckpt.save(self.checkpoint_prefix) 391 | self.config.last_model = tf.train.latest_checkpoint(self.config.checkpoint_dir) 392 | self.config.save_config(self.config.exp_out_dir, filename='config.json') 393 | 394 | start_time = time.time() 395 | if idx % 100 == 0 and idx > 0: 396 | logging.info('Processed %s of %s batches || Avg. Loss %s || Avg Time %s' % (idx, x_i.shape[0], loss_so_far/idx, time_so_far / max(idx,1))) 397 | with tf.GradientTape() as tape: 398 | bx_i = dataset[x_i[idx:(idx + batch_size)], :] 399 | bx_j = dataset[x_j[idx:(idx + batch_size)], :] 400 | bx_k = dataset[x_k[idx:(idx + batch_size)], :] 401 | loss = self.ghhcTree.compute_loss(bx_i, bx_j, bx_k) 402 | loss_so_far += loss.numpy() 403 | grads = tape.gradient(loss, self.ghhcTree.trainable_variables) 404 | self.optimizer.apply_gradients(rsgd_or_sgd(zip(grads, self.ghhcTree.trainable_variables)), 405 | global_step=tf.train.get_or_create_global_step()) 406 | self.ghhcTree.clip() 407 | end_time = time.time() 408 | time_so_far += end_time - start_time 409 | 410 | logging.info('Processed %s of %s batches || Avg. Loss %s || Avg Time %s' % (x_i.shape[0], x_i.shape[0], loss_so_far / x_i.shape[0], time_so_far / max(x_i.shape[0], 1))) 411 | 412 | # save model at the end of training 413 | self.ckpt.save(self.checkpoint_prefix) 414 | self.config.last_model = tf.train.latest_checkpoint(self.config.checkpoint_dir) 415 | # record the last model in the config. 416 | self.config.save_config(self.config.exp_out_dir, filename='config.json') 417 | return x_i.shape[0] 418 | 419 | def dev_eval(self, steps): 420 | if self.dev_set is not None: 421 | start_dev = time.time() 422 | mkdir_p(os.path.join(self.config.exp_out_dir, 'dev')) 423 | filename = os.path.join(self.config.exp_out_dir, 'dev', 'dev_tree_%s.tsv' % steps) 424 | self.ghhcTree.write_tsv(filename,self.dev_set,lbls=self.dev_lbls) 425 | dp = eval_dp(filename, os.path.join(self.config.exp_out_dir, 'dev', 'dev_score_%s.tsv' % steps), 426 | self.config.threads, self.config.dev_points_file) 427 | logging.info('DEV EVAL @ %s minibatches || %s DP' % (steps,dp)) 428 | end_dev = time.time() 429 | logging.info('Finished Dev Eval in %s seconds' % (end_dev-start_dev)) 430 | if self.config.save_dev_pics: 431 | filename = os.path.join(self.config.exp_out_dir, 'dev', 'dev_tree_%s.png' % steps) 432 | self.ghhcTree.plot_tree(self.dev_set, filename) 433 | 434 | # record the best dev score to try to understand if we end up doing worse, not used at inference time 435 | # last model is used at inference. 436 | self.best_dev_dp_score = max(self.best_dev_dp_score,dp) 437 | self.best_dev_iter = steps if self.best_dev_dp_score == dp else self.best_dev_iter 438 | self.last_dev_dp_score = dp 439 | self.last_dev_iter = steps 440 | # save every time we run this eval 441 | self.ckpt.save(self.checkpoint_prefix) 442 | self.config.last_model = tf.train.latest_checkpoint(self.config.checkpoint_dir) 443 | if self.best_dev_dp_score == dp: 444 | self.config.best_model = tf.train.latest_checkpoint(self.config.checkpoint_dir) 445 | self.config.save_config(self.config.exp_out_dir, filename='config.json') 446 | return dp 447 | else: 448 | return 0.0 449 | 450 | def inference(self, indexes, dataset, batch_size=1000, episode_size=5000): 451 | batches_so_far = 0 452 | curr_idx = 0 453 | episode_size = self.config.episode_size 454 | if self.config.shuffle: 455 | indexes = indexes[np.random.permutation(indexes.shape[0]), :] 456 | for i in range(self.config.num_iterations): 457 | if curr_idx > indexes.shape[0]: 458 | logging.info('Restarting....') 459 | curr_idx = 0 460 | if self.config.shuffle: 461 | indexes = indexes[np.random.permutation(indexes.shape[0]), :] 462 | logging.info('Starting iteration %s of %s' % (i, self.config.num_iterations)) 463 | batches_so_far += self.episode_inference(indexes[curr_idx:(curr_idx+episode_size), 0], 464 | indexes[curr_idx:(curr_idx+episode_size), 1], 465 | indexes[curr_idx:(curr_idx+episode_size), 2], 466 | dataset, batch_size, examples_so_far=batches_so_far) 467 | 468 | 469 | -------------------------------------------------------------------------------- /src/python/ghhc/util/Config.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Authors of gHHC 3 | This file is part of "hyperbolic_hierarchical_clustering" 4 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | """ 15 | 16 | import json 17 | import random 18 | import os 19 | import numpy as np 20 | 21 | 22 | class Config(object): 23 | """Config object""" 24 | 25 | def __init__(self,filename=None): 26 | # Settings 27 | self.config_name = filename 28 | self.dataset_name = 'dataset' 29 | self.alg_name = 'ghhc' 30 | self.exp_out_base = 'exp_out' 31 | self.exp_out_dir = None 32 | 33 | self.inference_file = None 34 | 35 | # Preprocessing 36 | self.unit_norm = True 37 | self.zero_mean = True 38 | 39 | # ghhc 40 | self.max_norm = 0.9 41 | self.init_method = 'randompts' 42 | self.batch_size = 500 43 | self.tree_learning_rate = 0.01 44 | self.num_internals = 100 45 | self.random_pts_scale = 0.001 46 | self.num_iterations = 10 47 | self.shuffle = True 48 | self.dev_points_file = 'None' 49 | self.gamma = 1.0 50 | self.struct_prior_every = 100 51 | self.num_struct_prior_batches = 100 52 | self.struct_prior = 'pcn' 53 | self.last_model = None 54 | 55 | # Triplet Sampling 56 | self.num_samples = 50000 57 | self.percent_random = 0.1 58 | self.sample_file = None 59 | self.sample_dataset = None 60 | self.triplet_k = 5 61 | self.nn_batch_size = 1000 62 | self.sample_outfile = None 63 | 64 | self.dev_file = None 65 | self.dev_every = 10000 66 | self.save_dev_pics = False 67 | self.loss_type = 'threespread' 68 | self.loss = 'sigmoid' 69 | self.lca_type = 'conditional' 70 | self.threads = 1 71 | self.checkpoint_dir = None 72 | self.save_every = 100000 73 | self.random_projection = None 74 | self.random_seed = 1451 75 | 76 | self.episode_size = 5000 77 | 78 | np.random.seed(self.random_seed) 79 | 80 | if filename: 81 | self.__dict__.update(json.load(open(filename))) 82 | self.random = random.Random(self.random_seed) 83 | 84 | def to_json(self): 85 | return json.dumps(self.filter_json(self.__dict__),indent=4,sort_keys=True) 86 | 87 | def save_config(self, exp_dir, filename='config.json'): 88 | with open(os.path.join(exp_dir, filename), 'w') as fout: 89 | fout.write(self.to_json()) 90 | fout.write('\n') 91 | 92 | def to_file_name_from_fields(self, fields): 93 | return "-".join(["%s=%s" % (f,self.__dict__[f]) for f in fields]) 94 | 95 | def to_filename(self): 96 | return self.to_file_name_from_fields(['alg_name', 'init_method', 'tree_learning_rate', 97 | 'loss', 'lca_type', 'num_samples', 98 | 'batch_size', 'struct_prior']) 99 | 100 | def filter_json(self, the_dict): 101 | # print("filter_json") 102 | # print(the_dict) 103 | res = {} 104 | for k in the_dict.keys(): 105 | # print("k : {} \t {} \t {}".format(k,the_dict[k],type(the_dict[k]))) 106 | if type(the_dict[k]) is str or \ 107 | type(the_dict[k]) is float or \ 108 | type(the_dict[k]) is int or \ 109 | type(the_dict[k]) is list or \ 110 | type(the_dict[k]) is bool or \ 111 | the_dict[k] is None: 112 | # print("res[k] : {} \t {} \t {}".format(k, the_dict[k], type(the_dict[k]))) 113 | res[k] = the_dict[k] 114 | elif type(the_dict[k]) is dict: 115 | res[k] = self.filter_json(the_dict[k]) 116 | return res 117 | 118 | DefaultConfig = Config() 119 | 120 | 121 | -------------------------------------------------------------------------------- /src/python/ghhc/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmonath/hyperbolic_hierarchical_clustering/c78099d4d576831e414fa1c26ceec8622572dfaa/src/python/ghhc/util/__init__.py -------------------------------------------------------------------------------- /src/python/ghhc/util/eval_dp.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Authors of gHHC 3 | This file is part of "hyperbolic_hierarchical_clustering" 4 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | """ 15 | 16 | import os 17 | 18 | 19 | def eval_dp(filename, outfile, threads, points_file, model_name='ghhc', dataset_name='dataset'): 20 | """Evaluate dendrogram purity with shell script using xcluster DP code.""" 21 | 22 | os.system("sh bin/score_tree.sh {} {} {} {} {} > {}" 23 | .format(filename, model_name, dataset_name, threads, points_file, outfile)) 24 | cost = None 25 | with open(outfile, 'r') as fin: 26 | for line in fin: 27 | splt = line.strip().split("\t") 28 | cost = float(splt[-1]) 29 | return cost 30 | -------------------------------------------------------------------------------- /src/python/ghhc/util/initializers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Authors of gHHC 3 | This file is part of "hyperbolic_hierarchical_clustering" 4 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | """ 15 | 16 | import numpy as np 17 | 18 | import tensorflow as tf 19 | 20 | from absl import logging 21 | 22 | from ghhc.model.ghhc import squared_euclidean_cdist 23 | from sklearn.cluster import AgglomerativeClustering 24 | 25 | tf.enable_eager_execution() 26 | 27 | 28 | def euc_dist_batched(x_i, nodes, batch_size=1000): 29 | """Batched cdist operation.""" 30 | dists = np.zeros((x_i.shape[0], nodes.shape[0]), np.float32) 31 | for i in range(0, x_i.shape[0], batch_size): 32 | logging.log_every_n_seconds(logging.INFO, 'euc_dist_batched processed %s of %s', 5, i, x_i.shape[0]) 33 | for j in range(0, nodes.shape[0], batch_size): 34 | logging.log_every_n_seconds(logging.INFO, 'euc_dist_batched processed %s of %s', 5, j, nodes.shape[0]) 35 | dists[i:(i + batch_size), j:(j + batch_size)] = squared_euclidean_cdist( 36 | x_i[i:(i + batch_size), :], nodes[j:(j + batch_size), :]).numpy() 37 | return dists 38 | 39 | 40 | def afkmc2(data, k, m=20): 41 | """Implementation of Fast and Provably Good Seedings for k-Means https://las.inf.ethz.ch/files/bachem16fast.pdf """ 42 | n = data.shape[0] 43 | c1 = np.random.randint(data.shape[0]) 44 | c1_vec = np.expand_dims(data[c1], 0) 45 | q_nom = np.squeeze(euc_dist_batched(c1_vec, data)) 46 | q_denom = np.sum(q_nom) 47 | q = 0.5 * q_nom / q_denom + 1.0 / (2.0 * n) 48 | indices = np.arange(n) 49 | c_i_minus_1 = np.zeros((k, data.shape[1]), dtype=np.float32) 50 | c_i_minus_1[0, :] = c1_vec 51 | for i in range(1, k): 52 | logging.log_every_n_seconds(logging.INFO, 'afkmc2 processed %s of %s', 5, i, k) 53 | x_ind = np.random.choice(indices, p=q) 54 | x = np.expand_dims(data[x_ind], 0) 55 | d_x = np.min(np.squeeze(euc_dist_batched(x, c_i_minus_1[:i]))) 56 | for j in range(1, m): 57 | y_ind = np.random.choice(indices, p=q) 58 | y = np.expand_dims(data[y_ind], 0) 59 | d_y = np.min(np.squeeze(euc_dist_batched(y, c_i_minus_1[:i]))) 60 | if ((d_y * q[x_ind]) / (d_x * q[y_ind])) > np.random.rand(): 61 | x = y 62 | d_x = d_y 63 | c_i_minus_1[i] = x 64 | return c_i_minus_1 65 | 66 | 67 | def init_from_rand_and_hac(data, k, scale): 68 | """Pick random points for leaves, find internals with HAC heuristic.""" 69 | centers = random_pts(data, int(k / 2), 1.0) 70 | hac_pts = init_from_hac(centers, centers.shape[0] - 1) 71 | res = np.zeros((k, data.shape[1]), dtype=np.float32) 72 | assert k % 2 == 0 73 | res[0] += scale * data[np.random.randint(data.shape[0])] 74 | res[1:centers.shape[0] + 1, :] = centers 75 | res[centers.shape[0] + 1:, :] = hac_pts 76 | res = tf.clip_by_norm(scale * res, 0.80, axes=[1]).numpy() 77 | return res 78 | 79 | 80 | def init_from_afkmc2_and_hac(data, k): 81 | """Pick leaves using afkmc2, find internals with HAC heuristic""" 82 | centers = afkmc2(data, int(k / 2)) 83 | hac_pts = init_from_hac(centers, centers.shape[0] - 1) 84 | res = np.zeros((k, data.shape[1]), dtype=np.float32) 85 | assert k % 2 == 0 86 | res[0] += 0.65 * data[np.random.randint(data.shape[0])] 87 | res[1:centers.shape[0] + 1, :] = centers 88 | res[centers.shape[0] + 1:, :] = hac_pts 89 | res = tf.clip_by_norm(0.65 * res, 0.80, axes=[1]).numpy() 90 | return res 91 | 92 | 93 | def hac_scaling_factor(n): 94 | return np.log2(n + 1 - np.arange(n)) / np.log2(n + 1) 95 | 96 | 97 | def init_from_hac(data, k): 98 | """Find internal structure using hac heuristic""" 99 | agg = AgglomerativeClustering(n_clusters=1, linkage='average') 100 | agg.fit(data) 101 | internals = np.zeros((data.shape[0] - 1, data.shape[1]), dtype=np.float32) 102 | counts = np.zeros((data.shape[0] - 1), dtype=np.float32) 103 | children = agg.children_ 104 | 105 | # find each agglomeration vector and 106 | def get_vector_for_idx(idx): 107 | if idx < data.shape[0]: 108 | return data[idx] 109 | else: 110 | return internals[idx - data.shape[0]] 111 | 112 | def get_count_for_idx(idx): 113 | if idx < data.shape[0]: 114 | return 1 115 | else: 116 | return counts[idx - data.shape[0]] 117 | 118 | for i in range(0, children.shape[0]): 119 | internals[i, :] = get_vector_for_idx(children[i, 0]) + get_vector_for_idx(children[i, 1]) 120 | counts[i] = get_count_for_idx(children[i, 0]) + get_count_for_idx(children[i, 1]) 121 | 122 | mean_internals = internals / np.expand_dims(counts, 1) 123 | normalized_internals = mean_internals / np.linalg.norm(mean_internals, axis=1, keepdims=True) 124 | selected_internals = normalized_internals[-k:, :] 125 | # print(mean_internals.shape) 126 | # print(normalized_internals.shape) 127 | # print(selected_internals.shape) 128 | # print(k) 129 | sf = hac_scaling_factor(data.shape[0])[-k:] 130 | # print(sf.shape) 131 | result = selected_internals * np.expand_dims(sf, 1) 132 | return result 133 | 134 | 135 | def random_pts(data, n, scale): 136 | """Pick random points""" 137 | x_sample = np.random.choice(data.shape[0], size=n, replace=False) 138 | return scale * data[x_sample, :] 139 | 140 | 141 | def random(data, n, scale): 142 | """Sample random points from normal(0,1)""" 143 | sample = np.random.randn(n, data.shape[1]).astype(np.float32) 144 | return scale * sample 145 | -------------------------------------------------------------------------------- /src/python/ghhc/util/io.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Authors of gHHC 3 | This file is part of "hyperbolic_hierarchical_clustering" 4 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | """ 15 | 16 | import os 17 | import errno 18 | 19 | def mkdir_p(filepath): 20 | try: 21 | os.makedirs(filepath) 22 | except OSError as exc: 23 | if exc.errno != errno.EEXIST: 24 | raise 25 | pass 26 | -------------------------------------------------------------------------------- /src/python/ghhc/util/load.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Authors of gHHC 3 | This file is part of "hyperbolic_hierarchical_clustering" 4 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | """ 15 | 16 | import numpy as np 17 | import tensorflow as tf 18 | from absl import logging 19 | 20 | tf.enable_eager_execution() 21 | 22 | def load_xcluster(filename): 23 | raw = np.loadtxt(filename,dtype=np.float32) 24 | pids = raw[:, 0].astype(np.int32) 25 | lbls = raw[:, 1].astype(np.int32) 26 | X = raw[:, 2:] 27 | return pids, lbls, X 28 | 29 | def zero_meaned(X): 30 | return X - np.mean(X, 0) 31 | 32 | def unit_normed(X, norm=1.0): 33 | un = X / np.linalg.norm(X, axis=1, keepdims=True) 34 | un = tf.clip_by_norm(un, norm, axes=[1]).numpy() 35 | return un 36 | 37 | def load(filename, config): 38 | logging.info('Loading data from filename %s' % filename) 39 | logging.info('Using xcluster format') 40 | pids, lbls, X = load_xcluster(filename) 41 | if config.zero_mean: 42 | logging.info('Zero meaning data') 43 | X = zero_meaned(X) 44 | if config.unit_norm: 45 | logging.info('Unit norming data') 46 | X = unit_normed(X, config.max_norm) 47 | return pids, lbls, X -------------------------------------------------------------------------------- /src/python/ghhc/util/sample_triples.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Authors of gHHC 3 | This file is part of "hyperbolic_hierarchical_clustering" 4 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | """ 15 | 16 | from sklearn.neighbors import NearestNeighbors 17 | 18 | import sys 19 | import numpy as np 20 | from absl import logging 21 | from ghhc.util.Config import Config 22 | from ghhc.util.load import load 23 | 24 | logging.set_verbosity(logging.INFO) 25 | 26 | def batch_find_neighbors(X,nn: NearestNeighbors,batch_size=1000): 27 | res = np.zeros((X.shape[0], nn.n_neighbors-1), dtype=np.int32) 28 | for i in range(0, X.shape[0], batch_size): 29 | logging.log_every_n_seconds(logging.INFO, 'Computed %s of %s neighbors' % (i,X.shape[0]), 5) 30 | res[i:(i + batch_size)] = nn.kneighbors(X[i:(i+batch_size), :], return_distance=False)[:,1:] 31 | logging.info('Finished batch_find_neighbors') 32 | return res 33 | 34 | def order_triple(X, i, j, k, comparison): 35 | ij = comparison(X[i, :], X[j, :]) 36 | jk = comparison(X[j, :], X[k, :]) 37 | ik = comparison(X[i, :], X[k, :]) 38 | if ij >= max(jk, ik): 39 | return np.array([i, j, k], dtype=np.int32) 40 | elif jk >= max(ij,ik): 41 | return np.array([j, k, i], dtype=np.int32) 42 | elif ik >= max(ij, jk): 43 | return np.array([i, k, j], dtype=np.int32) 44 | 45 | def sample_random(X, comparison): 46 | ijk = np.random.choice(X.shape[0],size=3,replace=False) 47 | return order_triple(X, ijk[0], ijk[1], ijk[2], comparison) 48 | 49 | def sample_nn(X, Xnn, comparison): 50 | ik = np.random.choice(Xnn.shape[0],size=2,replace=False) 51 | i = ik[0] 52 | k = ik[1] 53 | j = np.random.choice(Xnn[i,:]) 54 | while k == i or k == j: 55 | k = np.random.randint(X.shape[0],size=1)[0] 56 | return order_triple(X, i, j, k, comparison) 57 | 58 | if __name__ == "__main__": 59 | config = Config(sys.argv[1]) 60 | pids, lbls, X = load(config.sample_dataset, config) 61 | nn = NearestNeighbors(n_neighbors=config.triplet_k+1, algorithm='ball_tree').fit(X) 62 | Xnn = batch_find_neighbors(X, nn, config.nn_batch_size) 63 | samples = np.zeros((config.num_samples, 3), dtype=np.int32) 64 | def sim_fn(i, j): 65 | return 1.0 / (1.0 + np.linalg.norm(i - j)) 66 | for i in range(config.num_samples): 67 | if np.random.random() < config.percent_random: 68 | samples[i, :] = sample_random(X, sim_fn) 69 | else: 70 | samples[i, :] = sample_nn(X, Xnn, sim_fn) 71 | np.save(config.sample_outfile, samples) 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/scala/ghhc/eval/EvalDendrogramPurity.scala: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Authors of gHHC 2 | This file is part of "hyperbolic_hierarchical_clustering" 3 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | See the License for the specific language governing permissions and 12 | limitations under the License. */ 13 | 14 | package ghhc.eval 15 | 16 | import java.io.File 17 | import java.util 18 | 19 | import cc.factorie._ 20 | import cc.factorie.util.{DefaultCmdOptions, JavaHashSet, Threading} 21 | 22 | import scala.collection.JavaConverters._ 23 | import scala.collection.{GenSet, mutable} 24 | import scala.collection.mutable.ArrayBuffer 25 | import xcluster._ 26 | 27 | 28 | /** 29 | * Tree data structure used to compute dendrogram purity 30 | * @param id The unique id for this node 31 | * @param parent The parent node or None if the node is the root 32 | * @param parentId The id of the parent node or None if the node is the root 33 | * @param children The children objects of this node 34 | * @param labels The class lables of the descendant leaves of this node. 35 | */ 36 | class EvalTreeNode( 37 | val id: String, 38 | var parent: Option[EvalTreeNode], 39 | val parentId: Option[String], 40 | var children: ArrayBuffer[EvalTreeNode], var labels: ArrayBuffer[String]) extends Comparable[EvalTreeNode]{ 41 | 42 | 43 | override def compareTo(o: EvalTreeNode): Int = id.compareTo(o.id) 44 | 45 | var best = (0,0) 46 | var local = (0,0) 47 | 48 | lazy val labelCounts = labels.groupBy(identity).mapValues(_.size).toMap[String, Int] 49 | 50 | var bestClusteringRoots = ArrayBuffer[EvalTreeNode](this) 51 | var bestClustering = new ArrayBuffer[Iterable[EvalTreeNode]]() 52 | /** 53 | * Whether or not the node is a leaf 54 | * @return True/false if this is a leaf 55 | */ 56 | def isLeaf: Boolean = this.children.isEmpty 57 | 58 | 59 | var leafCache: ArrayBuffer[EvalTreeNode] = null 60 | /** 61 | * Return all of the descendant leaves of this node 62 | * @return Iterable of nodes 63 | */ 64 | def leaves(): Iterable[EvalTreeNode] = { 65 | if (leafCache == null) { 66 | leafCache = { 67 | if (this.isLeaf) 68 | ArrayBuffer(this) 69 | else { 70 | var curr_node = this 71 | val q = new mutable.Queue[EvalTreeNode]() 72 | q.enqueue(curr_node) 73 | val leaves = new ArrayBuffer[EvalTreeNode]() 74 | while (q.nonEmpty) { 75 | curr_node = q.dequeue() 76 | curr_node.children.foreach { 77 | c => 78 | if (c.isLeaf) 79 | leaves += c 80 | else 81 | q.enqueue(c) 82 | } 83 | } 84 | leaves 85 | } 86 | } 87 | } 88 | leafCache 89 | } 90 | 91 | 92 | /** 93 | * Compute the purity of this node from the cached labels 94 | * @param wrt Class label about which purity should be computed 95 | * @return Purity value for the given class 96 | */ 97 | def purity(wrt: String): Double = { 98 | // TODO: We could cache these scores 99 | // labels.count(_ == wrt).toDouble / labels.size 100 | labelCounts(wrt).toDouble / labels.size 101 | } 102 | 103 | /** 104 | * Some leaves may have missing labels. Purity strict 105 | * differs from purity by penalizing the inclusion of these 106 | * leaves with missing labels in the cluster. 107 | * @param wrt Class label about which purity should be computed 108 | * @return Purity value for the given class 109 | */ 110 | def purityStrict(wrt: String): Double = { 111 | // TODO: We could cache these scores 112 | labels.count(_ == wrt).toDouble / this.leaves().size 113 | } 114 | 115 | 116 | 117 | /** 118 | * The purity of the most frequently appearing class in this node 119 | * @return Purity value for the given class 120 | */ 121 | def purity(): Double = { 122 | val mostFreq = labels.groupBy(identity).mapValues(_.size).maxBy(_._2)._1 123 | purity(mostFreq) 124 | } 125 | 126 | 127 | def depth() = ancestors().length 128 | 129 | /** 130 | * The ancestors of this node (does not include this node). 131 | * @return An iterable of nodes 132 | */ 133 | def ancestors(): IndexedSeq[EvalTreeNode] = { 134 | val ancestors = new ArrayBuffer[EvalTreeNode]() 135 | var currNode = this 136 | while (currNode.parent.isDefined) { 137 | currNode = currNode.parent.get 138 | ancestors += currNode 139 | } 140 | ancestors 141 | } 142 | 143 | /** 144 | * The descendants of this node (does include this node) 145 | * @return The descendants of the node and this node itself 146 | */ 147 | def descendants(): IndexedSeq[EvalTreeNode] = { 148 | val ds = new ArrayBuffer[EvalTreeNode]() 149 | val q = new mutable.Queue[EvalTreeNode]() 150 | q.enqueue(this) 151 | while (q.nonEmpty) { 152 | val target = q.dequeue() 153 | ds.append(target) 154 | target.children.foreach(q.enqueue(_)) 155 | } 156 | ds.toIndexedSeq 157 | } 158 | 159 | /** 160 | * The root of the tree. 161 | * @return root 162 | */ 163 | def root():EvalTreeNode = { 164 | var currNode = this 165 | while (currNode.parent.isDefined) { 166 | currNode = currNode.parent.get 167 | } 168 | currNode 169 | } 170 | 171 | 172 | /** 173 | * The least common ancestor of this node and the given other node 174 | * @param other A node in the tree 175 | * @return lca(this,other) 176 | */ 177 | def lca(other: EvalTreeNode): EvalTreeNode = { 178 | val thisAncestors = this.ancestors() 179 | val otherAncestors = other.ancestors() 180 | var i = 0 181 | var found = false 182 | var lca = this.root() 183 | while (i < thisAncestors.length && !found) { 184 | var j = 0 185 | while(j < otherAncestors.length && !found) { 186 | if (thisAncestors(i) == otherAncestors(j)) { 187 | found = true 188 | lca = thisAncestors(i) 189 | } 190 | j += 1 191 | } 192 | i += 1 193 | } 194 | i-=1 195 | lca 196 | } 197 | 198 | } 199 | 200 | /** 201 | * Loaders for evaluation tree file format: 202 | * NodeId \t ParentId \t Label 203 | * 204 | * Parent and or label can be none or null if empty. 205 | */ 206 | object LoadEvalTree { 207 | 208 | /** 209 | * Load a serialized evaluation tree into memory and return the root of the tree 210 | * @param filename The filename 211 | */ 212 | def load(filename: String): EvalTreeNode = { 213 | val forest = loadForest(filename) 214 | assert(forest.size == 1, s"File: $filename contained a forest of trees, not one tree.") 215 | forest.head 216 | } 217 | 218 | /** 219 | * Load a forest of evaluation trees into memory returning the roots of all the trees. 220 | * @param fn 221 | * @return 222 | */ 223 | def loadForest(fn: String) = { 224 | 225 | val nodes = new java.util.HashMap[String,EvalTreeNode]().asScala 226 | 227 | new File(fn).lines("UTF-8").zipWithIndex.foreach { 228 | case (line,idx) => 229 | // if (idx % 100 == 0) 230 | // println(s"Read $idx lines of $fn") 231 | val Array(id,parent,label) = line.split("\t") 232 | val parentId = if (parent.equalsIgnoreCase("none") || parent.equalsIgnoreCase("null")) None else Some(parent) 233 | val labels = new ArrayBuffer[String]() 234 | if (!(label.equalsIgnoreCase("none") || label.equalsIgnoreCase("null"))) 235 | labels += label 236 | val node = new EvalTreeNode(id,None,parentId,new ArrayBuffer[EvalTreeNode](),labels) 237 | nodes.put(node.id,node) 238 | } 239 | nodes.values.foreach{ 240 | n => 241 | if (n.parentId.isDefined) { 242 | n.parent = nodes.get(n.parentId.get) 243 | if (n.parent.isEmpty) 244 | System.err.println(s"Missing ${n.parentId.get}") 245 | n.parent.get.children += n 246 | 247 | } 248 | } 249 | 250 | def propagateLabel(leaf: EvalTreeNode) = { 251 | val label = leaf.labels.head 252 | var currNode = leaf 253 | while (currNode.parent.isDefined) { 254 | currNode = currNode.parent.get 255 | currNode.labels += label 256 | } 257 | } 258 | val leaves = nodes.values.filter(_.isLeaf) 259 | leaves.filter(_.labels.nonEmpty).foreach(propagateLabel) 260 | nodes.values.zipWithIndex.foreach{ 261 | case (n,idx) => 262 | n.leaves() 263 | if (idx % 10000 == 0) 264 | System.err.print(s"\r[eval dp] pre-processed ${idx} nodes") 265 | } 266 | System.err.println() 267 | nodes.values.filter(_.parent.isEmpty) 268 | } 269 | 270 | 271 | } 272 | 273 | trait DendrogramPurityOpts extends DefaultCmdOptions { 274 | val input = new CmdOption[String]("input","the tree file to score") 275 | val algorithm = new CmdOption[String]("algorithm","Algorithm","STRING","the algorithm name") 276 | val dataset = new CmdOption[String]("dataset","dataset","STRING","the dataset name") 277 | val threads = new CmdOption[Int]("threads",4,"INT","number of threads to use") 278 | val print = new CmdOption[Boolean]("print",false,"BOOLEAN","print status updates for computation defaults to be false") 279 | val idFile = new CmdOption[String]("id-file","The file containing the point ids on which to evaluate dendrogram purity. Leave blank or as None to do exact dendrogram purity") 280 | val strictDP = new CmdOption[Boolean]("strict",false,"BOOLEAN","Whether to use version of purity which penalizes missing labels. ") 281 | } 282 | 283 | /** 284 | * Executable for dendrogram purity and expected 285 | * dendrogram purity. By default, exact dendrogram purity is computed 286 | * if an id-file is passed in then expected dendrogram 287 | * purity is computed on only those ids. 288 | */ 289 | object EvalDendrogramPurity { 290 | def main(args: Array[String]): Unit = { 291 | val opts = new DendrogramPurityOpts {} 292 | opts.parse(args) 293 | if (opts.idFile.wasInvoked && opts.idFile.value.toLowerCase != "none") 294 | ExpectedDendrogramPurity.run(opts) 295 | else 296 | DendrogramPurity.run(opts) 297 | } 298 | } 299 | 300 | 301 | object DendrogramPurity { 302 | 303 | /** 304 | * Find all pairs of points which have the same class label 305 | * @param root The root of the tree to evaluate 306 | * @param numThreads The number of threads to use 307 | * @return All pairs of points in dendrogram purity calculations 308 | */ 309 | def allPairsForEval(root: EvalTreeNode, numThreads: Int): ArrayBuffer[(EvalTreeNode,EvalTreeNode)] = { 310 | val leaves = root.leaves() 311 | val byClass = new util.HashMap[String,ArrayBuffer[EvalTreeNode]]().asScala 312 | leaves.filter(_.labels.nonEmpty).zipWithIndex.foreach{ 313 | case (l,idx) => 314 | // if (idx % 100 == 0) 315 | // println(s"Processed $idx leaves") 316 | // assert(l.labels.size == 1) 317 | // if (!byClass.contains(l.labels.head)) 318 | // byClass.put(l.labels.head, new ArrayBuffer[EvalTreeNode]()) 319 | // byClass(l.labels.head) += l 320 | // only include laves that have a label. 321 | if (l.labels.size == 1) { 322 | byClass.getOrElseUpdate(l.labels.head, new ArrayBuffer[EvalTreeNode]()) += l 323 | } 324 | } 325 | // println("Finding pairs.") 326 | val allPairs = new ArrayBuffer[(EvalTreeNode,EvalTreeNode)](byClass.values.map(f => f.size * f.size).sum) 327 | byClass.values.foreach{ 328 | classOnlyPoints => 329 | if (classOnlyPoints.length > 100) 330 | allPairs ++= classOnlyPoints.pairsParallel(numThreads) 331 | else 332 | allPairs ++= classOnlyPoints.pairs 333 | } 334 | allPairs 335 | } 336 | 337 | /** 338 | * Compute the dendrogram purity for the given pairs 339 | * @param pairs Pairs of points to evaluate 340 | * @param threads Number of threads to use 341 | * @param print Whether or not to print status updates 342 | * @return Dendrogram purity 343 | */ 344 | def evalPar(pairs: IndexedSeq[(EvalTreeNode,EvalTreeNode)],threads:Int,print:Boolean, strict: Boolean =false): Double = { 345 | val bufferSize = 10000 346 | val startIndexes = 0 until pairs.size by bufferSize 347 | @volatile var sum_purities = 0.0 348 | @volatile var N = 0.0 349 | Threading.parForeach(startIndexes,threads)({ 350 | start => 351 | var local_n = 0.0 352 | var local_purity = 0.0 353 | var i = start 354 | val end = math.min(start+ bufferSize,pairs.length) 355 | while (i < end) { 356 | val pair = pairs(i) 357 | if (strict) 358 | local_purity += pair._1.lca(pair._2).purityStrict(pair._1.labels.head) 359 | else 360 | local_purity += pair._1.lca(pair._2).purity(pair._1.labels.head) 361 | local_n += 1.0 362 | i += 1 363 | } 364 | synchronized{ 365 | if (print) 366 | System.err.print(s"\rThread ${Thread.currentThread().getId} Computing purities for pairs ${start} to ${end} of ${pairs.size} = ${100*end/pairs.size.toFloat}% done") 367 | N += local_n 368 | sum_purities += local_purity 369 | } 370 | }) 371 | sum_purities / N 372 | } 373 | 374 | /** 375 | * Run the main executable. 376 | * @param opts 377 | */ 378 | def run(opts: DendrogramPurityOpts): Unit = { 379 | val root = LoadEvalTree.load(opts.input.value) 380 | val pairs = allPairsForEval(root,opts.threads.value) 381 | val score = evalPar(pairs,opts.threads.value,opts.print.value,opts.strictDP.value) 382 | println(s"${opts.algorithm.value}\t${opts.dataset.value}\t${score}") 383 | } 384 | 385 | def main(args: Array[String]): Unit = { 386 | val opts = new DendrogramPurityOpts {} 387 | opts.parse(args) 388 | run(opts) 389 | } 390 | 391 | 392 | } 393 | 394 | /** 395 | * Expected dendrogram computations 396 | */ 397 | object ExpectedDendrogramPurity { 398 | 399 | def main(args: Array[String]): Unit = { 400 | val opts = new DendrogramPurityOpts {} 401 | opts.parse(args) 402 | run(opts) 403 | } 404 | 405 | 406 | 407 | 408 | def run(opts: DendrogramPurityOpts) = { 409 | val ids = io.Source.fromFile(opts.idFile.value)("UTF-8").getLines().toSet[String] 410 | val root = LoadEvalTree.load(opts.input.value) 411 | val pairs = all_pairs_for_eval(root,ids,opts.threads.value) 412 | val score = evalPar(pairs,opts.threads.value,opts.print.value,opts.strictDP.value) 413 | System.err.println() 414 | println(s"${opts.algorithm.value}\t${opts.dataset.value}\t${score}") 415 | } 416 | 417 | /** 418 | * Compute all pairs for evaluation with respect to a given set of point ids 419 | * @param root the root node 420 | * @param idSet the ids 421 | * @param numThreads number of threads 422 | * @return 423 | */ 424 | def all_pairs_for_eval(root: EvalTreeNode, idSet: Set[String],numThreads: Int): ArrayBuffer[(EvalTreeNode,EvalTreeNode)] = { 425 | val leaves = root.leaves() 426 | val byClass = new util.HashMap[String,ArrayBuffer[EvalTreeNode]]().asScala 427 | leaves.filter(l => idSet.contains(l.id)).zipWithIndex.foreach{ 428 | case (l,idx) => 429 | // if (idx % 100 == 0) 430 | // println(s"Processed $idx leaves") 431 | // if labels are empty do not include in evaluation. 432 | if (l.labels.size == 1) { 433 | byClass.getOrElseUpdate(l.labels.head, new ArrayBuffer[EvalTreeNode]()) += l 434 | } 435 | } 436 | // println("Finding pairs.") 437 | val allPairs = new ArrayBuffer[(EvalTreeNode,EvalTreeNode)](byClass.values.map(f => f.size * f.size).sum) 438 | byClass.values.foreach{ 439 | classOnlyPoints => 440 | if (classOnlyPoints.length > 100) 441 | allPairs ++= classOnlyPoints.pairsParallel(numThreads) 442 | else 443 | allPairs ++= classOnlyPoints.pairs 444 | } 445 | allPairs 446 | } 447 | 448 | /** 449 | * Evaluate expected dendrogram purity 450 | * @param pairs the pairs to evaluate on 451 | * @param threads the number of threads 452 | * @param print whether or not to print status updates 453 | * @return 454 | */ 455 | def evalPar(pairs: IndexedSeq[(EvalTreeNode,EvalTreeNode)],threads:Int,print:Boolean,strict: Boolean = false) = { 456 | val bufferSize = 1000 457 | val startIndexes = 0 until pairs.size by bufferSize 458 | @volatile var sum_purities = 0.0 459 | @volatile var N = 0.0 460 | Threading.parForeach(startIndexes,threads)({ 461 | start => 462 | var local_n = 0.0 463 | var local_purity = 0.0 464 | var i = start 465 | val end = math.min(start+ bufferSize,pairs.length) 466 | while (i < end) { 467 | val pair = pairs(i) 468 | // if the code below breaks you tried to evaluate on a pair that has no label. 469 | assert(pair._1.labels.size == 1) 470 | assert(pair._2.labels.size == 1) 471 | if (strict) 472 | local_purity += pair._1.lca(pair._2).purityStrict(pair._1.labels.head) 473 | else 474 | local_purity += pair._1.lca(pair._2).purity(pair._1.labels.head) 475 | local_n += 1.0 476 | i += 1 477 | } 478 | synchronized{ 479 | if (print) 480 | System.err.println(s"Thread ${Thread.currentThread().getId} Computing purities for pairs ${start} to ${end} of ${pairs.size} = ${100*end/pairs.size.toFloat}% done") 481 | N += local_n 482 | sum_purities += local_purity 483 | } 484 | }) 485 | sum_purities / N 486 | } 487 | 488 | 489 | } 490 | -------------------------------------------------------------------------------- /src/scala/ghhc/package.scala: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Authors of gHHC 2 | This file is part of "hyperbolic_hierarchical_clustering" 3 | http://github.com/nmonath/hyperbolic_hierarchical_clustering 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | See the License for the specific language governing permissions and 12 | limitations under the License. */ 13 | 14 | import java.io.{FileInputStream, InputStreamReader, BufferedReader, File} 15 | import java.io._ 16 | import java.util.UUID 17 | 18 | import cc.factorie.util.Threading 19 | 20 | import scala.collection.mutable.ArrayBuffer 21 | import cc.factorie._ 22 | 23 | package object xcluster { 24 | 25 | implicit class XClusterIndexedSeqExtras[T](seq: IndexedSeq[T]) { 26 | def pairsParallel(numThreads: Int): Iterable[(T,T)] = { 27 | val initSize = if (seq.size * (seq.size - 1) > 0) seq.size * (seq.size - 1) else Int.MaxValue-1000000 28 | val pairs = new ArrayBuffer[(T,T)](initSize) 29 | // println(s"[IndexedSeqExtras] ${seq.size * (seq.size - 1)} Pairs to find") 30 | Threading.parForeach(seq.indices,numThreads)(idx => { 31 | var i = idx + 1 32 | val p = new ArrayBuffer[(T,T)](seq.length - i) 33 | while (i < seq.length) { 34 | p += ((seq(idx),seq(i))) 35 | i += 1 36 | } 37 | synchronized { 38 | pairs ++= p 39 | // print(s"\r[IndexedSeqExtras] ${pairs.size} pairs found") 40 | } 41 | }) 42 | // println(s"\n[IndexedSeqExtras] Done finding pairs") 43 | pairs 44 | } 45 | } 46 | 47 | implicit class XClusterArrayDoubleExtras(arr: Array[Double]) { 48 | 49 | def += (arr2: Array[Double]): Unit = { 50 | val len = arr.length 51 | assert(arr2.length == len) 52 | var i = 0 53 | while (i < len) { 54 | arr(i) += arr2(i) 55 | i += 1 56 | } 57 | } 58 | 59 | def / (n: Double) = { 60 | val len = arr.length 61 | val newArr = new Array[Double](len) 62 | var i = 0 63 | while (i < len) { 64 | newArr(i) = arr(i) / n 65 | i += 1 66 | } 67 | newArr 68 | } 69 | } 70 | 71 | implicit class XClusterArrayFloatExtras(arr: Array[Float]) { 72 | 73 | def += (arr2: Array[Float]): Unit = { 74 | val len = arr.length 75 | assert(arr2.length == len) 76 | var i = 0 77 | while (i < len) { 78 | arr(i) += arr2(i) 79 | i += 1 80 | } 81 | } 82 | 83 | def / (n: Float) = { 84 | val len = arr.length 85 | val newArr = new Array[Float](len) 86 | var i = 0 87 | while (i < len) { 88 | newArr(i) = arr(i) / n 89 | i += 1 90 | } 91 | newArr 92 | } 93 | } 94 | 95 | 96 | implicit class XClusterFileExtras(file: File) { 97 | def lines(codec: String) = { 98 | new BufferedReader(new InputStreamReader(new FileInputStream(file),codec)).toIterator 99 | } 100 | 101 | def allFilesRecursively(filter: File => Boolean = _ => true): Iterable[File] = { 102 | if (file.isDirectory) 103 | file.listFiles().toIterable.filterNot(_.isDirectory).filter(filter) ++ 104 | file.listFiles().toIterable.filter(_.isDirectory).map( f => f.allFilesRecursively(filter)).flatten 105 | else 106 | if (filter(file)) 107 | Some(file) 108 | else 109 | None 110 | } 111 | 112 | 113 | } 114 | 115 | implicit class XClusterIterableDoubleExtras(i: Iterable[Double]) { 116 | 117 | def average = { 118 | var s = 0.0 119 | var c = 0 120 | i.foreach{ 121 | ii => 122 | s += ii 123 | c += 1 124 | } 125 | s / c 126 | } 127 | 128 | def fastSum(fn: Double => Double) = { 129 | var s = 0.0 130 | i.foreach{ 131 | ii => 132 | s += fn(ii) 133 | } 134 | s 135 | } 136 | 137 | def variance = { 138 | val avg = i.average 139 | var v = 0.0 140 | var c = 0 141 | i.foreach{ 142 | ii => 143 | val diff = ii - avg 144 | v += diff * diff 145 | c += 1 146 | } 147 | v / c 148 | } 149 | 150 | } 151 | 152 | def randomId: String = UUID.randomUUID().toString 153 | 154 | 155 | 156 | implicit class XClusterStringExtras(str: String) { 157 | 158 | def toFile(file: File,codec: String = "UTF-8"): Unit = { 159 | val pw = new PrintWriter(file,codec) 160 | pw.print(str) 161 | pw.close() 162 | } 163 | } 164 | 165 | } --------------------------------------------------------------------------------