├── .gitignore ├── MANIFEST.in ├── README.md ├── docs ├── Makefile ├── make.bat └── source │ ├── conf.py │ ├── dynamics.rst │ ├── examples.rst │ ├── imgs │ ├── heuns_tf.png │ ├── kpm_dos.png │ ├── stdog.png │ ├── stdog_logo_100.png │ ├── stdog_logo_200.png │ ├── stdog_logo_36.ico │ ├── stdog_logo_36.png │ └── stdog_logo_50.png │ ├── index.rst │ ├── install.rst │ ├── spectra.rst │ └── utils.rst ├── readthedocs.yml ├── requirements.txt ├── requirements_docs.txt ├── setup.py ├── stdog.svg ├── stdog ├── __init__.py ├── dynamics │ ├── __init__.py │ └── kuramoto │ │ ├── __init__.py │ │ ├── cuheuns.py │ │ ├── heuns.py │ │ └── tfops │ │ ├── __init__.py │ │ ├── heuns.py │ │ └── misc.py ├── spectra │ ├── __init__.py │ ├── dos.py │ └── trace_function.py └── utils │ ├── __init__.py │ ├── misc.py │ └── tfops │ ├── __init__.py │ └── misc.py ├── stdog_logo.png └── stdog_logo.svg /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # Environments 86 | .env 87 | .venv 88 | env/ 89 | venv/ 90 | ENV/ 91 | env.bak/ 92 | venv.bak/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include docs/source/imgs/kpm_dos.png 3 | include docs/source/imgs/stdog.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![](docs/source/imgs/stdog.png) 2 | # Structure and Dynamics on Graphs (Beta) 3 | 4 | The main goal of StDoG is to provide a package which can be used to study 5 | dynamical and structural properties (like spectra) on graphs with a large 6 | number of vertices. The modules of StDoG are being built by 7 | combining codes written in *Tensorflow* + *CUDA* and *C++*. 8 | 9 | ## 1 - Install 10 | 11 | ``` 12 | pip install stdog 13 | ``` 14 | 15 | ## 2 - Examples 16 | 17 | ### 2.1 - Dynamics 18 | 19 | #### 2.1.1 - Kuramoto 20 | 21 | ##### Tensorflow 22 | ```python 23 | import numpy as np 24 | import igraph as ig 25 | from stdog.utils.misc import ig2sparse #Function to convert igraph format to sparse matrix 26 | 27 | 28 | num_couplings = 40 29 | N = 20480 30 | 31 | G = ig.Graph.Erdos_Renyi(N, 3/N) 32 | adj = ig2sparse(G) 33 | 34 | omegas = np.random.normal(size= N).astype("float32") 35 | couplings = np.linspace(0.0,4.,num_couplings) 36 | phases = np.array([ 37 | np.random.uniform(-np.pi,np.pi,N) 38 | for i_l in range(num_couplings) 39 | 40 | ],dtype=np.float32) 41 | 42 | 43 | precision =32 44 | 45 | dt = 0.01 46 | num_temps = 50000 47 | total_time = dt*num_temps 48 | total_time_transient = total_time 49 | transient = False 50 | ``` 51 | 52 | ```python 53 | from stdog.dynamics.kuramoto import Heuns 54 | 55 | heuns_0 = Heuns(adj, phases, omegas, couplings, total_time, dt, 56 | device="/gpu:0", # or /cpu: 57 | precision=precision, transient=transient) 58 | 59 | heuns_0.run() 60 | heuns_0.transient = True 61 | heuns_0.total_time = total_time_transient 62 | heuns_0.run() 63 | order_parameter_list = heuns_0.order_parameter_list # (num_couplings, total_time//dt) 64 | ``` 65 | ```python 66 | import matplotlib.pyplot as plt 67 | 68 | r = np.mean(order_parameter_list, axis=1) 69 | stdr = np.std(order_parameter_list, axis=1) 70 | 71 | plt.ion() 72 | fig, ax1 = plt.subplots() 73 | ax1.plot(couplings,r,'.-') 74 | ax2 = ax1.twinx() 75 | ax2.plot(couplings,stdr,'r.-') 76 | plt.show() 77 | ``` 78 | ![](docs/source/imgs/heuns_tf.png) 79 | 80 | #### CUDA - Faster than Tensorflow implementation 81 | 82 | If CUDA is available. You can install our another package, 83 | [stdogpkg/cukuramoto](https://github.com/stdogpkg/cukuramoto) (C) 84 | ``` 85 | pip install cukuramoto 86 | ``` 87 | 88 | ```python 89 | from stdog.dynamics.kuramoto.cuheuns import CUHeuns as cuHeuns 90 | 91 | heuns_0 = cuHeuns(adj, phases, omegas, couplings, 92 | total_time, dt, block_size = 1024, transient = False) 93 | 94 | heuns_0.run() 95 | 96 | heuns_0.transient = True 97 | heuns_0.total_time = total_time_transient 98 | heuns_0.run() 99 | order_parameter_list = heuns_0.order_parameter_list # 100 | ``` 101 | ### 2.2 Spectral 102 | 103 | #### Spectral Density 104 | 105 | The Kernel Polynomial Method [1] can estimate the spectral density of large sparse Hermitan matrices with a computational cost almost linear. This method combines three key ingredients: the Chebyshev expansion + the stochastic trace estimator [2] + kernel smoothing. 106 | 107 | ```python 108 | import igraph as ig 109 | import numpy as np 110 | 111 | N = 3000 112 | G = ig.Graph.Erdos_Renyi(N, 3/N) 113 | 114 | W = np.array(G.get_adjacency().data, dtype=np.float64) 115 | vals = np.linalg.eigvalsh(W).real 116 | ``` 117 | 118 | ```python 119 | import stdog.spectra as spectra 120 | from stdog.utils.misc import ig2sparse 121 | 122 | W = ig2sparse(G) 123 | num_moments = 300 124 | num_vecs = 200 125 | extra_points = 10 126 | ek, rho = spectra.dos.kpm(W, num_moments, num_vecs, extra_points, device="/gpu:0") 127 | ``` 128 | 129 | ```python 130 | import matplotlib.pyplot as plt 131 | plt.hist(vals, density=True, bins=100, alpha=.9, color="steelblue") 132 | plt.scatter(ek, rho, c="tomato", zorder=999, alpha=0.9, marker="d") 133 | plt.ylim(0, 1) 134 | plt.show() 135 | ``` 136 | ![kpm](docs/source/imgs/kpm_dos.png) 137 | #### Trace Functions through Stochastic Lanczos Quadrature (SLQ)[3] 138 | 139 | 140 | ##### Computing custom trace functions 141 | 142 | ```python 143 | from stdog.spectra.trace_function import slq 144 | import tensorflow as tf 145 | 146 | def trace_function(eig_vals): 147 | return tf.exp(eig_vals) 148 | 149 | num_vecs = 100 150 | num_steps = 50 151 | approximated_estrada_index, _ = slq(L_sparse, num_vecs, num_steps, trace_function, device="/gpu:0") 152 | exact_estrada_index = np.sum(np.exp(vals_laplacian)) 153 | approximated_estrada_index, exact_estrada_index 154 | ``` 155 | The above code returns 156 | 157 | ``` 158 | (3058.012, 3063.16457163222) 159 | ``` 160 | ##### Entropy 161 | ```python 162 | import scipy 163 | import scipy.sparse 164 | from stdog.spectra.trace_function import entropy as slq_entropy 165 | 166 | def entropy(eig_vals): 167 | s = 0. 168 | for val in eig_vals: 169 | if val > 0: 170 | s += -val*np.log(val) 171 | return s 172 | 173 | L = np.array(G.laplacian(normalized=True), dtype=np.float64) 174 | vals_laplacian = np.linalg.eigvalsh(L).real 175 | 176 | exact_entropy = entropy(vals_laplacian) 177 | 178 | L_sparse = scipy.sparse.coo_matrix(L) 179 | 180 | num_vecs = 100 181 | num_steps = 50 182 | approximated_entropy = slq_entropy( 183 | L_sparse, num_vecs, num_steps, device="/cpu:0") 184 | 185 | approximated_entropy, exact_entropy 186 | ``` 187 | ``` 188 | (-509.46283, -512.5283224633046) 189 | ``` 190 | 191 | ## References 192 | 193 | 1 - Wang, L.W., 1994. Calculating the density of states and 194 | optical-absorption spectra of large quantum systems by the plane-wave moments 195 | method. Physical Review B, 49(15), p.10154. 196 | 197 | 2 - Hutchinson, M.F., 1990. A stochastic estimator of the trace of the 198 | influence matrix for laplacian smoothing splines. Communications in 199 | Statistics-Simulation and Computation, 19(2), pp.433-450. 200 | 201 | 3 - Ubaru, S., Chen, J., & Saad, Y. (2017). Fast Estimation of tr(f(A)) via Stochastic Lanczos Quadrature. 202 | SIAM Journal on Matrix Analysis and Applications, 38(4), 1075-1099. 203 | 204 | 205 | ## 3 - How to cite 206 | 207 | [Thomas Peron](https://tkdmperon.github.io/), [Bruno Messias](http://brunomessias.com/), Angélica S. Mata, [Francisco A. Rodrigues](http://conteudo.icmc.usp.br/pessoas/francisco/), and [Yamir Moreno](http://cosnet.bifi.es/people/yamir-moreno/). On the onset of synchronization of Kuramoto oscillators in scale-free networks. [arXiv:1905.02256](https://arxiv.org/abs/1905.02256) (2019). 208 | 209 | ## 4 - Acknowledgements 210 | 211 | This work has been supported also by FAPESP grants 11/50761-2 and 2015/22308-2. Research carriedout using the computational resources of the Center forMathematical Sciences Applied to Industry (CeMEAI)funded by FAPESP (grant 2013/07375-0). 212 | 213 | ### Responsible authors 214 | 215 | [@devmessias](https://github.com/devmessias), [@tkdmperon](https://github.com/tkdmperon) 216 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | import os 16 | import sys 17 | sys.path.insert(0, os.path.abspath('../..')) 18 | sys.path.insert(0, os.path.abspath('..')) 19 | sys.setrecursionlimit(1500) 20 | 21 | # -- Project information ----------------------------------------------------- 22 | 23 | project = 'StDoG' 24 | copyright = '2019, Bruno Messias; Thomas Peron' 25 | author = 'Bruno Messias; Thomas Peron' 26 | 27 | # The short X.Y version 28 | version = '' 29 | # The full version, including alpha/beta/rc tags 30 | release = '1.0.3' 31 | 32 | 33 | # -- General configuration --------------------------------------------------- 34 | 35 | # If your documentation needs a minimal Sphinx version, state it here. 36 | # 37 | # needs_sphinx = '1.0' 38 | 39 | # Add any Sphinx extension module names here, as strings. They can be 40 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 41 | # ones. 42 | extensions = [ 43 | 'sphinx.ext.autodoc', 44 | # 'sphinx.ext.intersphinx', 45 | 'sphinx.ext.todo', 46 | 'sphinx.ext.mathjax', 47 | 'sphinx.ext.ifconfig', 48 | 'sphinx.ext.viewcode', 49 | 'sphinx.ext.githubpages', 50 | 'sphinxcontrib.napoleon', 51 | # 'sphinx.ext.napoleon', 52 | ] 53 | napoleon_google_docstring = False 54 | 55 | napoleon_numpy_docstring = True 56 | napoleon_include_init_with_doc = True 57 | napoleon_include_private_with_doc = False 58 | napoleon_include_special_with_doc = True 59 | napoleon_use_admonition_for_examples = True 60 | napoleon_use_admonition_for_notes = True 61 | napoleon_use_admonition_for_references = True 62 | napoleon_use_ivar = True 63 | napoleon_use_param = True 64 | napoleon_use_rtype = True 65 | 66 | # Add any paths that contain templates here, relative to this directory. 67 | templates_path = ['_templates'] 68 | 69 | # The suffix(es) of source filenames. 70 | # You can specify multiple suffix as a list of string: 71 | # 72 | # source_suffix = ['.rst', '.md'] 73 | source_suffix = '.rst' 74 | 75 | # The master toctree document. 76 | master_doc = 'index' 77 | html_logo = "imgs/stdog_logo_100.png" 78 | html_favicon = "imgs/stdog_logo_36.ico" 79 | # The language for content autogenerated by Sphinx. Refer to documentation 80 | # for a list of supported languages. 81 | # 82 | # This is also used if you do content translation via gettext catalogs. 83 | # Usually you set "language" from the command line for these cases. 84 | language = None 85 | 86 | # List of patterns, relative to source directory, that match files and 87 | # directories to ignore when looking for source files. 88 | # This pattern also affects html_static_path and html_extra_path. 89 | exclude_patterns = [] 90 | 91 | # The name of the Pygments (syntax highlighting) style to use. 92 | pygments_style = None 93 | 94 | 95 | # -- Options for HTML output ------------------------------------------------- 96 | 97 | # The theme to use for HTML and HTML Help pages. See the documentation for 98 | # a list of builtin themes. 99 | # 100 | 101 | html_theme = 'sphinx_rtd_theme' 102 | 103 | 104 | # Theme options are theme-specific and customize the look and feel of a theme 105 | # further. For a list of options available for each theme, see the 106 | # documentation. 107 | # 108 | # html_theme_options = {} 109 | 110 | # Add any paths that contain custom static files (such as style sheets) here, 111 | # relative to this directory. They are copied after the builtin static files, 112 | # so a file named "default.css" will overwrite the builtin "default.css". 113 | html_static_path = ['_static'] 114 | 115 | # Custom sidebar templates, must be a dictionary that maps document names 116 | # to template names. 117 | # 118 | # The default sidebars (for documents that don't match any pattern) are 119 | # defined by theme itself. Builtin themes are using these templates by 120 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 121 | # 'searchbox.html']``. 122 | # 123 | # html_sidebars = {} 124 | 125 | 126 | # -- Options for HTMLHelp output --------------------------------------------- 127 | 128 | # Output file base name for HTML help builder. 129 | htmlhelp_basename = 'StDoGdoc' 130 | 131 | 132 | # -- Options for LaTeX output ------------------------------------------------ 133 | 134 | latex_elements = { 135 | # The paper size ('letterpaper' or 'a4paper'). 136 | # 137 | # 'papersize': 'letterpaper', 138 | 139 | # The font size ('10pt', '11pt' or '12pt'). 140 | # 141 | # 'pointsize': '10pt', 142 | 143 | # Additional stuff for the LaTeX preamble. 144 | # 145 | # 'preamble': '', 146 | 147 | # Latex figure (float) alignment 148 | # 149 | # 'figure_align': 'htbp', 150 | } 151 | 152 | # Grouping the document tree into LaTeX files. List of tuples 153 | # (source start file, target name, title, 154 | # author, documentclass [howto, manual, or own class]). 155 | latex_documents = [ 156 | (master_doc, 'StDoG.tex', 'StDoG Documentation', 157 | 'Bruno Messias; Thomas Peron', 'manual'), 158 | ] 159 | 160 | 161 | # -- Options for manual page output ------------------------------------------ 162 | 163 | # One entry per manual page. List of tuples 164 | # (source start file, name, description, authors, manual section). 165 | man_pages = [ 166 | (master_doc, 'stdog', 'StDoG Documentation', 167 | [author], 1) 168 | ] 169 | 170 | 171 | # -- Options for Texinfo output ---------------------------------------------- 172 | 173 | # Grouping the document tree into Texinfo files. List of tuples 174 | # (source start file, target name, title, author, 175 | # dir menu entry, description, category) 176 | texinfo_documents = [ 177 | (master_doc, 'StDoG', 'StDoG Documentation', 178 | author, 'StDoG', 'One line description of project.', 179 | 'Miscellaneous'), 180 | ] 181 | 182 | 183 | # -- Options for Epub output ------------------------------------------------- 184 | 185 | # Bibliographic Dublin Core info. 186 | epub_title = project 187 | 188 | # The unique identifier of the text. This can be a ISBN number 189 | # or the project homepage. 190 | # 191 | # epub_identifier = '' 192 | 193 | # A unique identification for the text. 194 | # 195 | # epub_uid = '' 196 | 197 | # A list of files that should not be packed into the epub file. 198 | epub_exclude_files = ['search.html'] 199 | 200 | 201 | # -- Extension configuration ------------------------------------------------- 202 | 203 | # -- Options for intersphinx extension --------------------------------------- 204 | 205 | # Example configuration for intersphinx: refer to the Python standard library. 206 | #intersphinx_mapping = {'https://docs.python.org/': None} 207 | 208 | # -- Options for todo extension ---------------------------------------------- 209 | 210 | # If true, `todo` and `todoList` produce output, else they produce nothing. 211 | todo_include_todos = True 212 | -------------------------------------------------------------------------------- /docs/source/dynamics.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | Dynamics 3 | ========== 4 | 5 | .. automodule:: stdog.dynamics.kuramoto.heuns 6 | :members: 7 | 8 | .. automodule:: stdog.dynamics.kuramoto.cuheuns 9 | :members: 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/source/examples.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Examples 3 | ======== 4 | 5 | Dynamics 6 | ======== 7 | 8 | 9 | 10 | Kuramoto 11 | -------- 12 | 13 | StDoG provides two implementations of Heun’s method. The 14 | first uses the TensorFlow. Therefore, it can be used with both 15 | CPU’s or GPU’s. The second implementation is a python wrapper to a 16 | CUDA code. The second (CUDA) is faster than TensorFlow implementation. 17 | However, a CUDA-compatible GPU is required 18 | 19 | 20 | 21 | Creating the data and setting the variables 22 | 23 | .. code-block:: python 24 | 25 | import numpy as np 26 | import igraph as ig 27 | from stdog.utils.misc import ig2sparse 28 | num_couplings = 40 29 | N = 20480 30 | 31 | G = ig.Graph.Erdos_Renyi(N, 3/N) 32 | adj = ig2sparse(G) 33 | 34 | omegas = np.random.normal(size= N).astype("float32") 35 | couplings = np.linspace(0.0,4.,num_couplings) 36 | phases = np.array([ 37 | np.random.uniform(-np.pi,np.pi,N) 38 | for i_l in range(num_couplings) 39 | 40 | ],dtype=np.float32) 41 | 42 | precision =32 43 | 44 | dt = 0.01 45 | num_temps = 50000 46 | total_time = dt*num_temps 47 | total_time_transient = total_time 48 | transient = False 49 | 50 | Tensorflow implementation 51 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 52 | 53 | .. code-block:: python 54 | 55 | from stdog.dynamics.kuramoto import Heuns 56 | 57 | heuns_0 = Heuns(adj, phases, omegas, couplings, total_time, dt, 58 | device="/gpu:0", # or /cpu: 59 | precision=precision, transient=transient) 60 | 61 | heuns_0.run() 62 | heuns_0.transient = True 63 | heuns_0.total_time = total_time_transient 64 | heuns_0.run() 65 | order_parameter_list = heuns_0.order_parameter_list 66 | 67 | Plotting the result 68 | 69 | .. code-block:: python 70 | 71 | import matplotlib.pyplot as plt 72 | 73 | r = np.mean(order_parameter_list, axis=1) 74 | stdr = np.std(order_parameter_list, axis=1) 75 | 76 | plt.ion() 77 | fig, ax1 = plt.subplots() 78 | ax1.plot(couplings,r,'.-') 79 | ax2 = ax1.twinx() 80 | ax2.plot(couplings,stdr,'r.-') 81 | plt.show() 82 | 83 | .. image:: imgs/heuns_tf.png 84 | 85 | 86 | CUDA implementation (faster) 87 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 88 | 89 | For that, you need to install our another package, 90 | `cukuramoto http://github.com/stdogpkg/cukuramoto` 91 | 92 | .. code-block:: bash 93 | 94 | $ pip install cukuramoto 95 | 96 | .. code-block:: python 97 | 98 | from stdog.dynamics.kuramoto.cuheuns import CUHeuns as cuHeuns 99 | 100 | heuns_0 = cuHeuns(adj, phases, omegas, couplings, 101 | total_time, dt, block_size = 1024, transient = False) 102 | 103 | heuns_0.run() 104 | 105 | heuns_0.transient = True 106 | heuns_0.total_time = total_time_transient 107 | heuns_0.run() 108 | order_parameter_list = heuns_0.order_parameter_list 109 | 110 | References 111 | ---------- 112 | 113 | [1] - Thomas Peron, Bruno Messias, Angélica S. Mata, Francisco A. Rodrigues, 114 | and Yamir Moreno. On the onset of synchronization of Kuramoto oscillators in 115 | scale-free networks. arXiv:1905.02256 (2019). 116 | 117 | 118 | 119 | Spectra 120 | ======= 121 | 122 | 123 | Spectral Density 124 | ---------------- 125 | 126 | 127 | The Kernel Polynomial Method can estimate the spectral density of large 128 | sparse Hermitan matrices with a computational cost almost linear. This method 129 | combines three key ingredients: the Chebyshev expansion + the stochastic 130 | trace estimator + kernel smoothing. 131 | 132 | 133 | .. code-block:: python 134 | 135 | import igraph as ig 136 | import numpy as np 137 | 138 | N = 3000 139 | G = ig.Graph.Erdos_Renyi(N, 3/N) 140 | 141 | W = np.array(G.get_adjacency().data, dtype=np.float64) 142 | vals = np.linalg.eigvalsh(W).real 143 | 144 | .. code-block:: python 145 | 146 | import stdog.spectra as spectra 147 | from stdog.utils.misc import ig2sparse 148 | 149 | W = ig2sparse(G) 150 | num_moments = 300 151 | num_vecs = 200 152 | extra_points = 10 153 | ek, rho = spectra.dos.kpm(W, num_moments, num_vecs, extra_points, device="/gpu:0") 154 | 155 | 156 | .. code-block:: python 157 | 158 | import matplotlib.pyplot as plt 159 | plt.hist(vals, density=True, bins=100, alpha=.9, color="steelblue") 160 | plt.scatter(ek, rho, c="tomato", zorder=999, alpha=0.9, marker="d") 161 | plt.ylim(0, 1) 162 | plt.show() 163 | 164 | 165 | .. image:: imgs/kpm_dos.png 166 | 167 | References 168 | ---------- 169 | 170 | [1] Wang, L.W., 1994. Calculating the density of states and 171 | optical-absorption spectra of large quantum systems by the plane-wave moments 172 | method. Physical Review B, 49(15), p.10154. 173 | 174 | [2] Hutchinson, M.F., 1990. A stochastic estimator of the trace of the 175 | influence matrix for laplacian smoothing splines. Communications in 176 | Statistics-Simulation and Computation, 19(2), pp.433-450. 177 | 178 | Trace Functions 179 | --------------- 180 | Given a semi-positive definite matrix :math:`A \in \mathbb R^{|V|\times|V|}`, 181 | which has the set of eigenvalues given by :math:`\{\lambda_i\}` a trace of 182 | a matrix function is given by 183 | 184 | .. math:: 185 | 186 | \mathrm{tr}(f(A)) = \sum\limits_{i=0}^{|V|} f(\lambda_i) 187 | 188 | The methods for calculating such traces functions have a 189 | cubic computational complexity lower bound, :math:`O(|V|^3)`. 190 | Therefore, it is not feasible for  large networks. One way 191 | to overcome such computational complexity it is use stochastic approximations 192 | combined with a mryiad of another methods 193 | to get the results with enough accuracy and with a small computational cost. 194 | The methods available in this module uses the Sthocastic Lanczos Quadrature, 195 | a procedure proposed in the work made by Ubaru, S. et.al. [1] (you need to cite them). 196 | 197 | 198 | Spectral Entropy 199 | ^^^^^^^^^^^^^^^^^ 200 | 201 | .. code-block:: python 202 | 203 | import scipy 204 | import scipy.sparse 205 | import igraph as ig 206 | import numpy as np 207 | 208 | N = 3000 209 | G = ig.Graph.Erdos_Renyi(N, 3/N) 210 | 211 | .. code-block:: python 212 | 213 | from stdog.spectra.trace_function import entropy as slq_entropy 214 | 215 | def entropy(eig_vals): 216 | s = 0. 217 | for val in eig_vals: 218 | if val > 0: 219 | s += -val*np.log(val) 220 | return s 221 | 222 | L = np.array(G.laplacian(normalized=True), dtype=np.float64) 223 | vals_laplacian = np.linalg.eigvalsh(L).real 224 | 225 | exact_entropy = entropy(vals_laplacian) 226 | 227 | L_sparse = scipy.sparse.coo_matrix(L) 228 | 229 | num_vecs = 100 230 | num_steps = 50 231 | approximated_entropy = slq_entropy( 232 | L_sparse, num_vecs, num_steps, device="/cpu:0") 233 | 234 | approximated_entropy, exact_entropy 235 | 236 | 237 | The above code returns 238 | 239 | .. code-block:: bash 240 | 241 | (-509.46283, -512.5283224633046) 242 | 243 | 244 | Custom Trace Function 245 | ^^^^^^^^^^^^^^^^^^^^^^ 246 | 247 | .. code-block:: python 248 | 249 | import tensorflow as tf 250 | 251 | from stdog.spectra.trace_function import slq 252 | def trace_function(eig_vals): 253 | return tf.exp(eig_vals) 254 | 255 | 256 | num_vecs = 100 257 | num_steps = 50 258 | approximated_trace_function, _ = slq(L_sparse, num_vecs, num_steps, trace_function) 259 | 260 | 261 | References 262 | ------------- 263 | 264 | 1 - Ubaru, S., Chen, J., & Saad, Y. (2017). Fast Estimation of tr(f(A)) via Stochastic Lanczos Quadrature. 265 | SIAM Journal on Matrix Analysis and Applications, 38(4), 1075-1099. 266 | 267 | 2 - Hutchinson, M. F. (1990). A stochastic estimator of the trace of the 268 | influence matrix for laplacian smoothing splines. Communications in 269 | Statistics-Simulation and Computation, 19(2), 433-450. 270 | -------------------------------------------------------------------------------- /docs/source/imgs/heuns_tf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/docs/source/imgs/heuns_tf.png -------------------------------------------------------------------------------- /docs/source/imgs/kpm_dos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/docs/source/imgs/kpm_dos.png -------------------------------------------------------------------------------- /docs/source/imgs/stdog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/docs/source/imgs/stdog.png -------------------------------------------------------------------------------- /docs/source/imgs/stdog_logo_100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/docs/source/imgs/stdog_logo_100.png -------------------------------------------------------------------------------- /docs/source/imgs/stdog_logo_200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/docs/source/imgs/stdog_logo_200.png -------------------------------------------------------------------------------- /docs/source/imgs/stdog_logo_36.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/docs/source/imgs/stdog_logo_36.ico -------------------------------------------------------------------------------- /docs/source/imgs/stdog_logo_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/docs/source/imgs/stdog_logo_36.png -------------------------------------------------------------------------------- /docs/source/imgs/stdog_logo_50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/docs/source/imgs/stdog_logo_50.png -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. meta:: 2 | :description lang=en: 3 | StDoG is a package which can be used to study 4 | dynamical and structural properties (like spectra) 5 | on/off graphs with a large number of vertices. 6 | 7 | Home 8 | ===================================== 9 | 10 | Strucutre and Dyanmics on Graphs 11 | ---------------------------------------- 12 | .. image:: imgs/stdog.png 13 | :align: center 14 | 15 | The main goal of StDoG is to provide a package which can be used to study 16 | dynamical and structural properties (like spectra) on graphs with a large 17 | number of vertices. The modules of StDoG are being built by 18 | combining codes written in *Tensorflow* + *CUDA* and *C++*. 19 | 20 | 21 | The package is available as a pypi repository 22 | 23 | .. code-block:: bash 24 | 25 | $ pip install stdog 26 | 27 | The source code is available at http://github.com/stdogpkg. 28 | 29 | .. toctree:: 30 | :hidden: 31 | 32 | self 33 | 34 | .. toctree:: 35 | :maxdepth: 2 36 | 37 | install 38 | examples 39 | 40 | .. toctree:: 41 | :maxdepth: 2 42 | :caption: Modules: 43 | 44 | dynamics 45 | spectra 46 | utils 47 | 48 | 49 | -------------------------------------------------------------------------------- /docs/source/install.rst: -------------------------------------------------------------------------------- 1 | Install 2 | ======== 3 | 4 | The package is available as as pypi repository 5 | 6 | .. code-block:: bash 7 | 8 | $ pip install stdog 9 | 10 | The source code is available at http://github.com/stdogpkg. 11 | 12 | -------------------------------------------------------------------------------- /docs/source/spectra.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | Spectra 3 | ========== 4 | 5 | 6 | The methods in this Spectra module uses our another package 7 | *eMaTe*, which is available at https://github.com/stdogpkg/emate . 8 | 9 | 10 | eMaTe is a python package implemented in tensorflow which the main goal is 11 | provide useful methods capable of estimate spectral densities and trace 12 | functions of large sparse matrices. 13 | 14 | .. automodule:: stdog.spectra.trace_function 15 | :members: 16 | 17 | .. automodule:: stdog.spectra.dos 18 | :members: 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/source/utils.rst: -------------------------------------------------------------------------------- 1 | Utils 2 | ========== 3 | 4 | .. automodule:: stdog.utils.misc 5 | :members: 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | 2 | build: 3 | image: latest 4 | 5 | python: 6 | version: 3.6 7 | requirements_file: requirements_docs.txt 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | scipy 2 | numpy 3 | tensorflow 4 | -------------------------------------------------------------------------------- /requirements_docs.txt: -------------------------------------------------------------------------------- 1 | sphinx-gallery 2 | sphinxcontrib-napoleon 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | 4 | with open("README.md", "r") as f: 5 | README_TEXT = f.read() 6 | 7 | setup( 8 | name="stdog", 9 | version="v1.0.4", 10 | packages=find_packages(exclude=["build", ]), 11 | long_description=README_TEXT, 12 | long_description_content_type="text/markdown", 13 | install_requires=["tensorflow", "scipy", "numpy", "emate"], 14 | include_package_data=True, 15 | license="MIT", 16 | description="Structure and Dynamics on Graphs", 17 | author_email="messias.physics@gmail.com", 18 | author="Bruno Messias; Thomas K. Peron", 19 | download_url="https://github.com/stdogpkg/stdog/archive/v1.0.4.tar.gz", 20 | keywords=[ 21 | "gpu", "science", "complex-networks", "graphs", "dynamics", 22 | "tensorflow", "kuramoto" 23 | ], 24 | classifiers=[ 25 | "Development Status :: 4 - Beta", 26 | "License :: OSI Approved :: MIT License", 27 | "Intended Audience :: Science/Research", 28 | "Programming Language :: Python :: 3", 29 | "Topic :: Scientific/Engineering :: Physics", 30 | "Topic :: Scientific/Engineering :: Mathematics", 31 | "Topic :: Scientific/Engineering :: Information Analysis" 32 | ], 33 | url="https://github.com/stdogpkg/stdog" 34 | ) 35 | -------------------------------------------------------------------------------- /stdog.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml 181 | 182 | 185 | 186 | 189 | 190 | 193 | 194 | 197 | 198 | 201 | 202 | 205 | 206 | 209 | 210 | 213 | 214 | 217 | 218 | 221 | 222 | 225 | 226 | 229 | 230 | 233 | 234 | 237 | 238 | 241 | 242 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | StDoG 276 | 277 | 278 | 279 | 280 | 286 | 294 | 296 | 300 | 304 | 309 | 310 | 311 | -------------------------------------------------------------------------------- /stdog/__init__.py: -------------------------------------------------------------------------------- 1 | from stdog import dynamics 2 | from stdog import spectra 3 | from stdog import utils 4 | 5 | 6 | __version__ = "1.0.4" 7 | __license__ = "MIT" 8 | __author__ = "Bruno Messias, Thomas K. Peron" 9 | __author_email__ = "messias.physics@gmail.com" 10 | __all__ = ["dynamics", "spectra", "utils"] 11 | -------------------------------------------------------------------------------- /stdog/dynamics/__init__.py: -------------------------------------------------------------------------------- 1 | from stdog.dynamics import kuramoto 2 | 3 | __all__ = ["kuramoto"] 4 | -------------------------------------------------------------------------------- /stdog/dynamics/kuramoto/__init__.py: -------------------------------------------------------------------------------- 1 | from stdog.dynamics.kuramoto import tfops 2 | from stdog.dynamics.kuramoto.heuns import Heuns 3 | from stdog.dynamics.kuramoto.cuheuns import CUHeuns 4 | 5 | __all__ = ["Heuns", "tfops", "CUHeuns"] 6 | -------------------------------------------------------------------------------- /stdog/dynamics/kuramoto/cuheuns.py: -------------------------------------------------------------------------------- 1 | """ 2 | ================================ 3 | Kuramoto: Heun's method in CUDA 4 | ================================ 5 | 6 | allow efficiently simulating phase oscillators 7 | (the Kuramoto model) on large heterogeneous networks using the 8 | Heun's method with a "pure" CUDA implementation. Should be 9 | faster than tensorflow implementation. 10 | References 11 | ---------- 12 | 13 | [1] - Thomas Peron, Bruno Messias, Angélica S. Mata, Francisco A. Rodrigues, 14 | and Yamir Moreno. On the onset of synchronization of Kuramoto oscillators in 15 | scale-free networks. arXiv:1905.02256 (2019). 16 | 17 | 18 | """ 19 | import numpy as np 20 | try: 21 | import cukuramoto 22 | except ImportError: 23 | pass 24 | 25 | 26 | class CUHeuns: 27 | """Allow efficiently simulating phase oscillators (the Kuramoto model) on 28 | large heterogeneous networks using the Heun’s method. This class uses a 29 | pure CUDA implementation of Heun’s method. Therefore, should be faster 30 | than TensorFlow implementation also provided by StDoG 31 | 32 | Attributes 33 | ---------- 34 | adjacency : coo matrix 35 | phases : np.ndarray 36 | omegas : np.ndarray 37 | couplings : np.ndarray 38 | total_time : float 39 | dt : float 40 | transient : bool 41 | order_parameter_list : np.ndarray 42 | 43 | """ 44 | 45 | def __init__( 46 | self, 47 | adjacency, 48 | phases, 49 | omegas, 50 | couplings, 51 | total_time, 52 | dt, 53 | transient=False, 54 | block_size=1024, 55 | ): 56 | 57 | self._adjacency = adjacency 58 | self._phases = phases.astype("float32") 59 | self._omegas = omegas.astype("float32") 60 | self._couplings = couplings.astype("float32") 61 | self.transient = transient 62 | self.total_time = total_time 63 | self.dt = dt 64 | 65 | self.block_size = block_size 66 | 67 | self.order_parameter_list = np.array([]) 68 | self.create_simulation() 69 | 70 | @property 71 | def num_couplings(self): 72 | return len(self.couplings) 73 | 74 | @property 75 | def num_oscilators(self): 76 | return self.adjacency.shape[0] 77 | 78 | @property 79 | def num_temps(self): 80 | return int(self.total_time/self.dt) 81 | 82 | @property 83 | def phases(self): 84 | phases = self.simulation.get_phases().reshape( 85 | (self.num_couplings, self.num_oscilators) 86 | ) 87 | self._phases = phases 88 | return phases 89 | 90 | @property 91 | def omegas(self): 92 | return self._omegas 93 | 94 | @omegas.setter 95 | def omegas(self, omegas): 96 | self._omegas = omegas.astype("float32") 97 | self.create_simulation() 98 | 99 | @property 100 | def couplings(self): 101 | return self._couplings 102 | 103 | @couplings.setter 104 | def couplings(self, couplings): 105 | self._couplings = couplings.astype("float32") 106 | self.create_simulation() 107 | 108 | @property 109 | def adjacency(self): 110 | return self._adjacency 111 | 112 | @adjacency.setter 113 | def adjacency(self, adjacency): 114 | self._adjacency = adjacency 115 | self.create_simulation() 116 | 117 | def create_simulation(self): 118 | """This method method crates the simulation. 119 | """ 120 | adj = self.adjacency.tocsr() 121 | ptr, indices = adj.indptr.astype("int32"), adj.indices.astype("int32") 122 | 123 | simulation = cukuramoto.Heuns( 124 | self.num_oscilators, self.block_size, self.omegas, 125 | self._phases.flatten(), self.couplings, indices, ptr) 126 | 127 | self.simulation = simulation 128 | 129 | def run(self): 130 | """This runs the algorithm and updates the phases. 131 | 132 | If transiet is set to True, then the order parameters is 133 | calculated and the array order_parameter_list is updated. 134 | """ 135 | 136 | if self.transient: 137 | order_parameter_list = self.simulation.get_order_parameter( 138 | self.num_temps, self.dt) 139 | self.order_parameter_list = order_parameter_list.reshape( 140 | (self.num_couplings, self.num_temps) 141 | ) 142 | else: 143 | self.simulation.heuns( 144 | self.num_temps, self.dt) 145 | 146 | __all__ = ["CUHeuns"] 147 | -------------------------------------------------------------------------------- /stdog/dynamics/kuramoto/heuns.py: -------------------------------------------------------------------------------- 1 | """ 2 | ======================================= 3 | Kuramoto: Heun's method in Tensorflow 4 | ======================================= 5 | 6 | References 7 | ---------- 8 | 9 | [1] - Thomas Peron, Bruno Messias, Angélica S. Mata, Francisco A. Rodrigues, 10 | and Yamir Moreno. On the onset of synchronization of Kuramoto oscillators in 11 | scale-free networks. arXiv:1905.02256 (2019). 12 | 13 | 14 | """ 15 | 16 | import numpy as np 17 | import tensorflow as tf 18 | 19 | from .tfops.heuns import heuns_while, heuns_step 20 | from .tfops.misc import get_order_parameter 21 | 22 | 23 | class Heuns: 24 | """This class allow efficiently simulating phase oscillators 25 | (the Kuramoto model) on large heterogeneous networks using the 26 | Heun's method implemented in TensorFlow. 27 | 28 | Attributes 29 | ---------- 30 | adjacency : coo matrix 31 | phases : np.ndarray 32 | omegas : np.ndarray 33 | couplings : np.ndarray 34 | total_time : float 35 | dt : float 36 | transient : bool 37 | frustation : bool 38 | device : str 39 | log : bool 40 | use_while : bool 41 | order_parameter_list : np.ndarray 42 | 43 | """ 44 | def __init__( 45 | self, 46 | adjacency, 47 | phases, 48 | omegas, 49 | couplings, 50 | total_time, 51 | dt, 52 | transient=False, 53 | frustration=None, 54 | precision=32, 55 | device="/gpu:0", 56 | log=None, 57 | use_while=False, 58 | ): 59 | 60 | self.device = device 61 | self.log = log 62 | self.use_while = use_while 63 | 64 | self.adjacency = adjacency 65 | self.phases = phases 66 | self.omegas = omegas 67 | self.couplings = couplings 68 | self.frustration = frustration 69 | self.transient = transient 70 | self.total_time = total_time 71 | self.dt = dt 72 | 73 | self.num_couplings = len(self.couplings) 74 | self.num_oscilators = adjacency.shape[0] 75 | 76 | if precision == 64: 77 | self.complex_np_type = np.complex128 78 | self.complex_tf_type = tf.complex128 79 | 80 | self.real_np_type = np.float64 81 | self.real_tf_type = tf.float64 82 | 83 | self.int_tf_type = tf.int64 84 | 85 | elif precision == 32: 86 | self.complex_np_type = np.complex64 87 | self.complex_tf_type = tf.complex64 88 | 89 | self.real_np_type = np.float32 90 | self.real_tf_type = tf.float32 91 | 92 | self.int_tf_type = tf.int64 93 | 94 | else: 95 | raise Exception("Valid options for precision are: 32 or 64") 96 | 97 | self.omegas = np.array( 98 | self.omegas, 99 | dtype=self.real_np_type 100 | ) 101 | self.order_parameter_list = np.array([]) 102 | self.create_tf_graph() 103 | 104 | @property 105 | def num_temps(self): 106 | return int(self.total_time/self.dt) 107 | 108 | @property 109 | def frustration(self): 110 | return self.__frustration 111 | 112 | @frustration.setter 113 | def frustration(self, frustration): 114 | 115 | not_first_call = hasattr(self, "frustration") 116 | if not_first_call: 117 | old = self.__frustration is None 118 | new = frustration is None 119 | self.__frustration = frustration 120 | 121 | if not_first_call and (old ^ new): 122 | self.create_tf_graph() 123 | else: 124 | self.__frustration = frustration 125 | 126 | @property 127 | def transient(self): 128 | return self.__transient 129 | 130 | @transient.setter 131 | def transient(self, transient): 132 | 133 | not_first_call = hasattr(self, "transient") 134 | if not_first_call: 135 | old = self.__transient 136 | self.__transient = transient 137 | 138 | if not_first_call and (old ^ transient): 139 | self.create_tf_graph() 140 | else: 141 | self.__transient = transient 142 | 143 | def create_tf_graph(self): 144 | """ 145 | This method creates the tensorflow graph 146 | 147 | """ 148 | with tf.device(self.device): 149 | self.graph = tf.Graph() 150 | 151 | with self.graph.as_default(): 152 | 153 | if self.frustration is not None: 154 | frustration = tf.placeholder( 155 | dtype=self.real_tf_type, 156 | shape=[self.num_couplings, self.num_oscilators], 157 | name="frustration" 158 | ) 159 | 160 | else: 161 | frustration = None 162 | 163 | initial_phases = tf.placeholder( 164 | dtype=self.real_tf_type, 165 | shape=[self.num_couplings, self.num_oscilators], 166 | name="initial_phases" 167 | ) 168 | omegas = tf.placeholder( 169 | shape=self.omegas.shape, 170 | dtype=self.real_tf_type, 171 | name="omegas" 172 | ) 173 | couplings = tf.placeholder( 174 | shape=self.couplings.shape, 175 | dtype=self.real_tf_type, 176 | name="couplings" 177 | ) 178 | dt = tf.placeholder(self.real_tf_type, shape=[], name="dt") 179 | sp_indices = tf.placeholder(dtype=tf.int64, name="sp_indices") 180 | sp_values = tf.placeholder( 181 | dtype=self.real_tf_type, 182 | name="sp_values" 183 | ) 184 | adjacency = tf.SparseTensor( 185 | sp_indices, 186 | sp_values, 187 | dense_shape=np.array(self.adjacency.shape, dtype=np.int32) 188 | ) 189 | 190 | pi2 = tf.constant( 191 | 2*np.pi, 192 | dtype=self.real_tf_type 193 | ) 194 | dtDiv2 = tf.divide( 195 | dt, 2. 196 | ) 197 | 198 | omegas = omegas[tf.newaxis:, ] 199 | omegasDouble = tf.multiply( 200 | 2., omegas 201 | ) 202 | couplings = couplings[:, tf.newaxis] 203 | 204 | if self.use_while: 205 | num_temps = tf.placeholder(tf.int64, name="num_temps") 206 | self.tf_phases, self.tf_order_parameters = heuns_while( 207 | initial_phases, 208 | frustration, 209 | adjacency, 210 | couplings, 211 | omegas, 212 | dt, 213 | omegasDouble, 214 | dtDiv2, 215 | pi2, 216 | self.num_couplings, 217 | num_temps, 218 | transient=self.transient, 219 | tf_float=self.real_tf_type, 220 | tf_complex=self.complex_tf_type 221 | ) 222 | else: 223 | phases = tf.Variable( 224 | np.zeros_like(self.phases), 225 | dtype=self.real_tf_type, 226 | name="phases" 227 | ) 228 | assign_initial_phases = tf.assign( 229 | phases, initial_phases, name="assign_initial_phases") 230 | 231 | new_phases = heuns_step( 232 | phases, frustration, adjacency, couplings, 233 | omegas, dt, omegasDouble, dtDiv2, pi2) 234 | 235 | assign_new_phases = tf.assign( 236 | phases, new_phases, name="assign_new_phases") 237 | 238 | if self.transient: 239 | with tf.control_dependencies([assign_new_phases]): 240 | new_order_parameter = get_order_parameter( 241 | phases, 242 | tf_complex=self.complex_tf_type 243 | ) 244 | new_order_parameter = tf.reshape( 245 | new_order_parameter, ( 246 | self.num_couplings, 1), 247 | name="new_order_parameter" 248 | ) 249 | 250 | def run(self): 251 | """This runs the algorithm and updates the phases. 252 | 253 | If transiet is set to True, then the order parameters is 254 | calculated and the array order_parameter_list is updated. 255 | """ 256 | coo = self.adjacency.tocoo() 257 | 258 | sp_values = np.array(coo.data, dtype=self.real_np_type) 259 | sp_indices = np.mat([coo.row, coo.col], dtype=np.int64).transpose() 260 | 261 | with tf.Session(graph=self.graph) as sess: 262 | sess.run(tf.global_variables_initializer()) 263 | 264 | if self.log is not None: 265 | tf.summary.FileWriter(self.log, sess.graph) 266 | 267 | if self.use_while: 268 | feed_dict = { 269 | "sp_values:0": sp_values, 270 | "sp_indices:0": sp_indices, 271 | "initial_phases:0": self.phases, 272 | "omegas:0": self.omegas, 273 | "couplings:0": self.couplings, 274 | "dt:0": self.dt, 275 | "num_temps:0": self.num_temps, 276 | } 277 | 278 | if self.frustration is not None: 279 | feed_dict["frustration:0"] = self.frustration 280 | 281 | phases, order_parameters = sess.run( 282 | [self.tf_phases, self.tf_order_parameters], 283 | feed_dict 284 | ) 285 | self.phases = phases 286 | if self.transient: 287 | order_parameters = np.delete( 288 | order_parameters, (0), axis=1) 289 | self.order_parameter_list = order_parameters 290 | else: 291 | sess.run( 292 | "assign_initial_phases:0", 293 | feed_dict={"initial_phases:0": self.phases}) 294 | 295 | feed_dict = { 296 | "sp_values:0": sp_values, 297 | "sp_indices:0": sp_indices, 298 | "omegas:0": self.omegas, 299 | "couplings:0": self.couplings, 300 | "dt:0": self.dt, 301 | } 302 | if self.frustration is not None: 303 | feed_dict["frustration:0"] = self.frustration 304 | 305 | for i_temp in range(self.num_temps): 306 | if self.transient: 307 | order_parameter = sess.run( 308 | "new_order_parameter:0", feed_dict) 309 | if self.order_parameter_list.shape[0] > 0: 310 | self.order_parameter_list = np.concatenate([ 311 | self.order_parameter_list, order_parameter 312 | ], axis=1) 313 | else: 314 | self.order_parameter_list = order_parameter 315 | 316 | else: 317 | sess.run("assign_new_phases:0", feed_dict) 318 | 319 | self.phases = sess.run("phases:0") 320 | 321 | 322 | __all__ = ["Heuns"] 323 | -------------------------------------------------------------------------------- /stdog/dynamics/kuramoto/tfops/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/stdog/dynamics/kuramoto/tfops/__init__.py -------------------------------------------------------------------------------- /stdog/dynamics/kuramoto/tfops/heuns.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | 4 | from stdog.utils.tfops.misc import tfmod 5 | from .misc import get_order_parameter 6 | 7 | 8 | def heuns_evolve_vec(a, b, adjacency): 9 | with tf.name_scope("heuns_evolve_vec"): 10 | c = tf.sparse_tensor_dense_matmul( 11 | adjacency, 12 | tf.transpose(a), 13 | ) 14 | c = tf.multiply( 15 | b, 16 | tf.transpose(c) 17 | ) 18 | 19 | return c 20 | 21 | 22 | def heuns_evolve_m(phases, frustration, adjacency, couplings): 23 | with tf.name_scope("heuns_evolve_m"): 24 | if frustration is not None: 25 | phases = tf.add(phases, frustration) 26 | 27 | vs = tf.sin(phases) 28 | vc = tf.cos(phases) 29 | 30 | Ms = heuns_evolve_vec(vs, vc, adjacency) 31 | Mc = heuns_evolve_vec(vc, vs, adjacency) 32 | 33 | M = tf.multiply( 34 | tf.subtract(Ms, Mc), 35 | couplings 36 | ) 37 | 38 | return M 39 | 40 | 41 | def update_phases(phases, dt, M, omegas): 42 | return tf.add( 43 | phases, 44 | tf.multiply( 45 | dt, 46 | tf.add(omegas, M) 47 | ) 48 | ) 49 | 50 | 51 | def heuns_step( 52 | phases, frustration, adjacency, couplings, omegas, dt, omegasDouble, 53 | dtDiv2, pi2): 54 | 55 | with tf.name_scope("heuns_step"): 56 | M = heuns_evolve_m(phases, frustration, adjacency, couplings) 57 | 58 | temporary_phases = update_phases(phases, dt, M, omegas) 59 | 60 | M2 = heuns_evolve_m( 61 | temporary_phases, frustration, adjacency, couplings) 62 | 63 | M = tf.add(M2, M) 64 | 65 | new_phases = update_phases(phases, dtDiv2, M, omegasDouble) 66 | 67 | return new_phases 68 | 69 | 70 | def heuns_while( 71 | phases, frustration, adjacency, couplings, omegas, dt, 72 | omegasDouble, dtDiv2, pi2, 73 | num_couplings, num_temps, transient=False, tf_float=tf.float32, 74 | tf_complex=tf.complex64): 75 | with tf.name_scope("heuns"): 76 | with tf.name_scope("init"): 77 | i_dt = tf.constant(0, dtype=tf.int64) 78 | 79 | order_parameters = tf.zeros( 80 | (num_couplings, 1), 81 | dtype=tf_float 82 | ) 83 | 84 | def cond(phases, order_parameters, dt, i_dt, num_temps): 85 | return tf.less(i_dt, num_temps) 86 | 87 | def body(phases, order_parameters, dt, i_dt, num_temps): 88 | new_phases = heuns_step( 89 | phases, frustration, adjacency, couplings, 90 | omegas, dt, omegasDouble, dtDiv2, pi2) 91 | 92 | if transient: 93 | new_order_parameter = get_order_parameter( 94 | phases, 95 | tf_complex=tf_complex 96 | ) 97 | new_order_parameter = tf.reshape( 98 | new_order_parameter, (num_couplings, 1) 99 | ) 100 | 101 | order_parameters = tf.concat( 102 | [ 103 | order_parameters, new_order_parameter 104 | ], 105 | axis=1 106 | ) 107 | return [ 108 | new_phases, 109 | order_parameters, 110 | dt, 111 | tf.add(i_dt, 1), 112 | num_temps 113 | ] 114 | 115 | phases, order_parameters, dt, i_dt, num_temps = tf.while_loop( 116 | cond, 117 | body, 118 | [ 119 | phases, 120 | order_parameters, 121 | dt, 122 | i_dt, 123 | num_temps 124 | ], 125 | shape_invariants=[ 126 | phases.get_shape(), 127 | tf.TensorShape([num_couplings, None]), 128 | dt.get_shape(), 129 | i_dt.get_shape(), 130 | num_temps.get_shape() 131 | ] 132 | ) 133 | 134 | return phases, order_parameters 135 | 136 | 137 | __all__ = [ 138 | "heuns_evolve_vec", "heuns_evolve_m", "heuns_step", "heuns_while"] 139 | -------------------------------------------------------------------------------- /stdog/dynamics/kuramoto/tfops/misc.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | 4 | def get_order_parameter(phases, tf_complex=tf.complex64): 5 | with tf.name_scope("get_order_parameter"): 6 | order_parameter = tf.exp(1j*tf.cast( 7 | phases, 8 | tf_complex 9 | ) 10 | ) 11 | order_parameter = tf.reduce_mean( 12 | order_parameter, 13 | axis=1 14 | ) 15 | 16 | order_parameter = tf.abs( 17 | order_parameter, 18 | ) 19 | 20 | return order_parameter 21 | 22 | 23 | __all__ = ["get_order_parameter"] 24 | -------------------------------------------------------------------------------- /stdog/spectra/__init__.py: -------------------------------------------------------------------------------- 1 | from stdog.spectra import dos 2 | from stdog.spectra import trace_function 3 | 4 | __all__ = ["dos", "trace_function"] 5 | 6 | -------------------------------------------------------------------------------- /stdog/spectra/dos.py: -------------------------------------------------------------------------------- 1 | """ 2 | Spectral Density 3 | ================ 4 | 5 | The Kernel Polynomial Method can estimate the spectral density of large 6 | sparse Hermitan matrices with a computational cost almost linear. This method 7 | combines three key ingredients: the Chebyshev expansion + the stochastic 8 | trace estimator + kernel smoothing. 9 | 10 | """ 11 | from emate.hermitian.kpm import pykpm as kpm 12 | 13 | __all__ = ["kpm"] -------------------------------------------------------------------------------- /stdog/spectra/trace_function.py: -------------------------------------------------------------------------------- 1 | """ 2 | Trace Functions 3 | ============================== 4 | 5 | The core module responsible to calc trace functions. 6 | 7 | 8 | Given a semi-positive definite matrix :math:`A \in \mathbb R^{|V|\\times|V|}`, 9 | which has the set of eigenvalues given by :math:`\{\lambda_i\}` a trace of 10 | a matrix function is given by 11 | 12 | .. math:: 13 | 14 | \mathrm{tr}(f(A)) = \sum\limits_{i=0}^{|V|} f(\lambda_i) 15 | 16 | The methods for calculating such traces functions have a 17 | cubic computational complexity lower bound, :math:`O(|V|^3)`. 18 | Therefore, it is not feasible for  large networks. One way 19 | to overcome such computational complexity it is use stochastic approximations 20 | combined with a mryiad of another methods 21 | to get the results with enough accuracy and with a small computational cost. 22 | The methods available in this module uses the Sthocastic Lanczos Quadrature, 23 | a procedure proposed in the work made by Ubaru, S. et.al. [1] (you need to cite them). 24 | 25 | References 26 | ----------- 27 | 28 | [1] Ubaru, S., Chen, J., & Saad, Y. (2017). Fast Estimation of tr(f(A)) via 29 | Stochastic Lanczos Quadrature. SIAM Journal on Matrix Analysis and 30 | Applications, 38(4), 1075-1099. 31 | 32 | [2] Hutchinson, M. F. (1990). A stochastic estimator of the trace of the 33 | influence matrix for laplacian smoothing splines. Communications in 34 | Statistics-Simulation and Computation, 19(2), 433-450. 35 | """ 36 | import tensorflow as tf 37 | import numpy as np 38 | 39 | from emate.symmetric.slq import pyslq as slq 40 | 41 | 42 | def estrada_index(L, num_vecs=100, num_steps=50, device="/gpu:0"): 43 | """ Given the Laplacian matrix :math:`L \in \mathbb R^{|V|\\times |V|}` s.t. for all :math:`v \in \mathbb R^{|V|}` we have :math:`v^T L v > 0` the Estrada Index 44 | is given by 45 | 46 | .. math:: 47 | 48 | \mathrm{tr}\exp(L) = \sum\limits_{i=0}^{|V|} e^{\lambda_i} 49 | 50 | 51 | Parameters 52 | ---------- 53 | L: sparse matrix 54 | num_vecs: int 55 | Number of random vectors used to approximate the trace 56 | using the Hutchison's trick [1] 57 | num_steps: int 58 | Number of Lanczos steps or Chebyschev's moments 59 | device: str 60 | "/cpu:int" our "/gpu:int" 61 | 62 | Returns 63 | ------- 64 | approximated_estrada_index: float 65 | 66 | References 67 | ---------- 68 | 69 | 1 - Ubaru, S., Chen, J., & Saad, Y. (2017). Fast Estimation of tr(f(A)) via 70 | Stochastic Lanczos Quadrature. SIAM Journal on Matrix Analysis and Applications, 71 | 38(4), 1075-1099. 72 | 73 | 2 - Hutchinson, M. F. (1990). A stochastic estimator of the trace of the 74 | influence matrix for laplacian smoothing splines. Communications in 75 | Statistics-Simulation and Computation, 19(2), 433-450. 76 | """ 77 | def trace_function(eig_vals): 78 | return tf.exp(eig_vals) 79 | 80 | approximated_estrada_index, _ = slq( 81 | L, num_vecs, num_steps, trace_function, device=device) 82 | 83 | return approximated_estrada_index 84 | 85 | 86 | def entropy(L_sparse, num_vecs=100, num_steps=50, device="/gpu:0"): 87 | """Compute the spectral entropy 88 | 89 | .. math:: 90 | 91 | \sum\limits_{i=0}^{|V|} f(\lambda_i) 92 | 93 | f(\lambda) = \\begin{cases} 94 | -\lambda \log_2\lambda \ \ if \ \lambda > 0; \\newline 95 | 0,\ \ otherwise 96 | \end{cases} 97 | 98 | Parameters 99 | ---------- 100 | L: sparse matrix 101 | num_vecs: int 102 | Number of random vectors used to approximate the trace 103 | using the Hutchison's trick [1] 104 | num_steps: int 105 | Number of Lanczos steps or Chebyschev's moments 106 | device: str 107 | "/cpu:int" our "/gpu:int" 108 | 109 | Returns 110 | ------- 111 | approximated_spectral_entropy: float 112 | 113 | References 114 | ---------- 115 | 116 | 1 - Ubaru, S., Chen, J., & Saad, Y. (2017). Fast Estimation of tr(f(A)) via 117 | Stochastic Lanczos Quadrature. SIAM Journal on Matrix Analysis and Applications, 118 | 38(4), 1075-1099. 119 | 120 | 2 - Hutchinson, M. F. (1990). A stochastic estimator of the trace of the 121 | influence matrix for laplacian smoothing splines. Communications in 122 | Statistics-Simulation and Computation, 19(2), 433-450. 123 | """ 124 | 125 | def trace_function(eig_vals): 126 | return tf.map_fn( 127 | lambda val: tf.cond( 128 | val > 0, 129 | lambda: -val*tf.log(val), 130 | lambda: 0.), 131 | eig_vals) 132 | 133 | approximated_entropy, _ = slq( 134 | L_sparse, num_vecs, num_steps, trace_function, device=device) 135 | 136 | return approximated_entropy 137 | 138 | 139 | __all__ = ["slq", "entropy", "estrada_index"] 140 | -------------------------------------------------------------------------------- /stdog/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/stdog/utils/__init__.py -------------------------------------------------------------------------------- /stdog/utils/misc.py: -------------------------------------------------------------------------------- 1 | """ 2 | Misc 3 | ====== 4 | 5 | Contains tools to help some boring tasks 6 | """ 7 | import numpy as np 8 | from scipy.sparse import coo_matrix 9 | 10 | 11 | def ig2sparse(G, transpose=False, attr=None, precision=32): 12 | """Given an igraph instance returns the sparse adjacency matrix 13 | in COO format. 14 | 15 | Parameters 16 | ---------- 17 | G: igraph instance 18 | transpose : bool 19 | If the adjacency matrix should be transposed or not 20 | attr : str 21 | The name of weight attribute 22 | precision : int 23 | The precision used to store the weight attributes 24 | 25 | Returns 26 | -------- 27 | L : COO Sparse matrix 28 | 29 | 30 | """ 31 | 32 | if attr: 33 | source, target, data = zip(*[ 34 | (e.source, e.target, e[attr]) 35 | for e in G.es if not np.isnan(e[attr]) 36 | ]) 37 | else: 38 | source, target = zip(*[ 39 | (e.source, e.target) 40 | for e in G.es 41 | ]) 42 | data = np.ones(len(source)).astype('int').tolist() 43 | 44 | if not G.is_directed(): 45 | source, target = source + target, target + source 46 | data = data + data 47 | 48 | if precision == 64: 49 | np_type = np.float64 50 | elif precision == 32: 51 | np_type = np.float32 52 | 53 | data = np.array(data, dtype=np_type) 54 | if transpose: 55 | L = coo_matrix( 56 | (data, (target, source)), 57 | shape=[G.vcount(), G.vcount()] 58 | ) 59 | else: 60 | L = coo_matrix( 61 | (data, (source, target)), 62 | shape=[G.vcount(), G.vcount()] 63 | ) 64 | 65 | return L 66 | 67 | 68 | __all__ = ["ig2sparse"] 69 | -------------------------------------------------------------------------------- /stdog/utils/tfops/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /stdog/utils/tfops/misc.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | 4 | def tfmod(vals, mod_int): 5 | with tf.name_scope("tfmod"): 6 | mod_vals = tf.subtract( 7 | vals, tf.multiply(tf.floordiv(vals, mod_int), mod_int) 8 | ) 9 | return mod_vals 10 | 11 | 12 | __all__ = ["tfmod"] 13 | -------------------------------------------------------------------------------- /stdog_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stdogpkg/stdog/775153945442c3941948ba07d3e791b92a8a904a/stdog_logo.png -------------------------------------------------------------------------------- /stdog_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml 117 | 118 | 119 | 120 | 145 | 146 | 149 | 150 | 153 | 154 | 157 | 158 | 161 | 162 | 165 | 166 | 169 | 170 | 173 | 174 | 177 | 178 | 181 | 182 | 185 | 186 | 189 | 190 | 193 | 194 | 197 | 198 | 201 | 202 | 205 | 206 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 230 | 240 | 248 | 259 | 263 | --------------------------------------------------------------------------------