├── .gitignore ├── LICENSE ├── README.md ├── documentation ├── biblist.bib ├── bipartite_motifs.eps ├── pymfinder_manual.pdf ├── pymfinder_manual.tex └── unipartite_motifs.eps ├── pymfinder ├── __init__.py ├── data │ ├── bipartite-2-test.net │ ├── bipartite-3-test.net │ ├── bipartite-4-test.net │ ├── bipartite-5-test.net │ ├── bipartite-6-test.net │ ├── bipartite-test.net │ ├── unipartite-2-test.net │ └── unipartite-3-test.net ├── datatypes.py ├── mfinder │ ├── .gitignore │ ├── README │ ├── __init__.py │ ├── bits.h │ ├── clustering.c │ ├── clustering.h │ ├── common.h │ ├── globals.c │ ├── globals.h │ ├── grassberger.c │ ├── grassberger.h │ ├── hash.c │ ├── hash.h │ ├── list.c │ ├── list.h │ ├── main.c │ ├── mat.c │ ├── mat.h │ ├── metropolis.c │ ├── metropolis.h │ ├── mfinder-manual.pdf │ ├── mfinder-motif-dictionary.pdf │ ├── mfinder.i │ ├── mfinder.py │ ├── mfinder_wrap.c │ ├── motif_ids.c │ ├── motif_ids.h │ ├── output.c │ ├── output.h │ ├── permutation.c │ ├── prob.c │ ├── prob.h │ ├── random.c │ ├── random.h │ ├── results.c │ ├── results.h │ ├── role.c │ ├── role.h │ ├── stubs.c │ ├── stubs.h │ ├── switches.c │ ├── switches.h │ ├── wrapper.c │ └── wrapper.h ├── pymfinder.py └── roles.py ├── setup.py └── tests ├── __init__.py └── test_pymfinder.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # OS generated files # 3 | ###################### 4 | .DS_Store 5 | .DS_Store? 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | Icon? 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | # Editor generated files # 14 | ########################## 15 | *~ 16 | *.swp 17 | 18 | # Compiled source # 19 | ################### 20 | *.pyc 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Bernat Bramon Mora 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pymfinder [![](https://badgen.net/badge/DOI/10.1101%2F364703/blue)](https://doi.org/10.1101/364703) 2 | 3 | **pymfinder** is Python package with which to find network motifs in complex networks and to analyze a growing list of network-motif related *stuff*. 4 | 5 | At its core, pymfinder is a Python library that combines Python methods for network-motif analysis. pymfinder will require you to have the Python modules Numpy and Setuptools installed in your machine. In addition, some of the engine underneath is a modified version of _original_ mfinder version 1.2 written in C and available on [Uri Alon's website](http://www.weizmann.ac.il/mcb/UriAlon/). mfinder is a software tool for network-motif detection developed by [Nadav Kashtan](mailto:nadav.kashtan@gmail.com), and it was originally written in C and made available solely as an executable. We use mfinder within pymfinder for its underlying efficiency. The mfinder code has been both included and modified here with the explicit consent of Nadav Kashtan, the author of mfinder 1.2. 6 | 7 | If you use pymfinder or the ideas presented in it, please remember to cite [Bramon Mora, et. al. 2018](https://www.biorxiv.org/content/early/2018/07/07/364703). 8 | 9 | ## Installation instructions 10 | 11 | 12 | Installation should be relatively straightforward using the included `setup.py`. In fact, it should be as simple as navigating to the directory where you cloned the git repository ('pymfinder/') and running 13 | 14 | python setup.py install 15 | 16 | If you receive an error about 'Permission denied' or something similar, you most likely don't have permission to install pymfinder in the global Python site-packages or dist-packages directory. In that case, you can install it locally by adding the `--user` option 17 | 18 | python setup.py install --user 19 | 20 | If you still cannot install pymfinder, please check [the issues page](https://github.com/stoufferlab/pymfinder/issues/) and, if your problem isn't listed, create a new one. 21 | 22 | If you prefer to use Python 3, you can also switch to the branch pymfinder-python3. 23 | 24 | #### Checking the installation 25 | 26 | Assuming that the package installs properly, it is strongly recommended that you run the test suite to make sure that nothing fishy is going on. Doing so is as simple as running 27 | 28 | python setup.py test 29 | -------------------------------------------------------------------------------- /documentation/biblist.bib: -------------------------------------------------------------------------------- 1 | % This file was created with JabRef 2.10. 2 | % Encoding: UTF-8 3 | 4 | 5 | @Other{Alonwebsite, 6 | Title = {Uri Alon Lab: Design principles in biology}, 7 | Author = {Alon, Uri}, 8 | Publication = {Weizmann Institute of Science}, 9 | Url = {http://www.weizmann.ac.il/mcb/UriAlon/}, 10 | Year = {2018} 11 | } 12 | 13 | @Article{BramonMora364703, 14 | Title = {pymfinder: a tool for the motif analysis of binary and quantitative complex networks}, 15 | Author = {Bramon Mora, Bernat and Cirtwill, Alyssa R and Stouffer, Daniel B}, 16 | Journal = {bioRxiv}, 17 | Year = {2018}, 18 | 19 | Abstract = {We developed pymfinder, a new software to analyze multiple aspects of the so-called network motifs---distinct n-node patterns of interaction---for any directed, undirected, unipartite or bipartite network. Unlike existing software for the study of network motifs, pymfinder allows the computation of node- and link-specific motif profiles as well as the analysis of weighted motifs. Beyond the overall characterization of networks, the tools presented in this work therefore allow for the comparison of the "roles" of either nodes or links of a network. Examples include the study of the roles of different species and/or their trophic/mutualistic interactions in ecological networks or the roles of specific proteins and/or their activation/inhibition relationships in protein-protein interaction networks. Here, we show how to apply the main tools from pymfinder using a predator-prey interaction network from a marine food web. pymfinder is open source software that can be freely and anonymously downloaded from https://github.com/stoufferlab/pymfinder, distributed under the MIT License (2018).}, 20 | Doi = {10.1101/364703}, 21 | Eprint = {https://www.biorxiv.org/content/early/2018/07/07/364703.full.pdf}, 22 | Owner = {bernat}, 23 | Publisher = {Cold Spring Harbor Laboratory}, 24 | Timestamp = {2018.07.09}, 25 | Url = {https://www.biorxiv.org/content/early/2018/07/07/364703} 26 | } 27 | 28 | @Article{Stouffer2007, 29 | Title = {{Evidence for the existence of a robust pattern of prey selection in food webs.}}, 30 | Author = {Stouffer, Daniel B and Camacho, Juan and Jiang, Wenxin and Amaral, Lu\'{\i}s A. Nunes}, 31 | Journal = {Proceedings of the Royal Society B: Biological Sciences}, 32 | Year = {2007}, 33 | 34 | Month = aug, 35 | Number = {1621}, 36 | Pages = {1931--1940}, 37 | Volume = {274}, 38 | 39 | Doi = {10.1098/rspb.2007.0571}, 40 | File = {:home/arc136/Desktop/Papers/Stouffer et al. - 2007 - Proceedings of the Royal Society of London B.pdf:pdf}, 41 | Keywords = {Animals,Biological,Ecosystem,Food Chain,Models,Predatory Behavior}, 42 | Pmid = {17567558} 43 | } 44 | 45 | -------------------------------------------------------------------------------- /documentation/pymfinder_manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/documentation/pymfinder_manual.pdf -------------------------------------------------------------------------------- /documentation/pymfinder_manual.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | 3 | \usepackage[utf8]{inputenc} 4 | \usepackage{authblk} 5 | \usepackage{titlesec} 6 | 7 | % Figures 8 | \usepackage{graphicx} 9 | \usepackage{caption} 10 | \usepackage{subcaption} 11 | \usepackage{epstopdf} 12 | 13 | \usepackage{multirow} 14 | \usepackage{geometry} 15 | %\usepackage{pdflscape} 16 | %\usepackage{epstopdf} 17 | \usepackage[labelfont=bf]{caption} 18 | \usepackage{setspace} 19 | \usepackage[running]{lineno} 20 | 21 | \usepackage[numbers,round]{natbib} 22 | \bibliographystyle{plainnat} 23 | \PassOptionsToPackage{hyphens}{url}\usepackage[colorlinks=true,linkcolor=magenta, citecolor=magenta]{hyperref} 24 | \usepackage{url} 25 | 26 | \newcommand\tab[1][1cm]{\hspace*{#1}} 27 | 28 | 29 | %Code 30 | \usepackage{listings} 31 | \usepackage{color} 32 | 33 | \definecolor{dkgreen}{rgb}{0,0.6,0} 34 | \definecolor{gray}{rgb}{0.5,0.5,0.5} 35 | \definecolor{mauve}{rgb}{0.58,0,0.82} 36 | 37 | \lstset{frame=tb, 38 | language=Python, 39 | aboveskip=3mm, 40 | belowskip=3mm, 41 | showstringspaces=false, 42 | columns=flexible, 43 | basicstyle={\small\ttfamily}, 44 | numbers=none, 45 | numberstyle=\tiny\color{gray}, 46 | keywordstyle=\color{magenta}, 47 | commentstyle=\color{dkgreen}, 48 | stringstyle=\color{mauve}, 49 | breaklines=true, 50 | breakatwhitespace=true, 51 | tabsize=3 52 | } 53 | 54 | 55 | \usepackage{array} 56 | 57 | \newcommand{\methods}{\textit{Materials \& Methods}} 58 | \newcommand{\SI}{\textit{Appendix}~} 59 | 60 | \topmargin -1.5cm % 0.0cm 61 | \oddsidemargin 0.0cm % 0.2cm 62 | \textwidth 6.5in 63 | \textheight 9.0in % 21cm 64 | \footskip 1.0cm % 1.0cm 65 | 66 | \usepackage{authblk} 67 | 68 | \title{\emph{pymfinder}: Tool Guide} 69 | 70 | \author{Bernat Bramon Mora$^{1}$, Alyssa R. Cirtwill$^{2}$, Daniel B. Stouffer $^{1}$} 71 | \date{\small 72 | $^1$Centre for Integrative Ecology, School of Biological Sciences, University of Canterbury, Christchurch, New Zealand\\ 73 | \medskip 74 | $^2$Department of Physics, Chemistry, and Biology (IFM), Link\"{o}ping University, Link\"{o}ping, Sweden\\ } 75 | 76 | \renewcommand\Authands{ and } 77 | 78 | \begin{document} 79 | \maketitle 80 | \raggedright 81 | \setlength{\parindent}{15pt} 82 | 83 | \newpage 84 | 85 | \setlength{\parindent}{0cm} 86 | \setlength{\parskip}{1em} 87 | 88 | \section{General information} 89 | \textbf{Description:} \textit{pymfinder} is a Python package designed to detect motifs in complex networks and define the roles of nodes and links using these motifs. Both weighted and binary networks can be analyzed. At its core, \emph{pymfinder} is a combination of Python methods for network-motif analysis as well as a Python wrapper for the original \emph{mfinder} version 1.2 written in C and available at \url{http://www.weizmann.ac.il/mcb/UriAlon/}. This code has been included and modified here with the explicit consent of Nadav Kashtan, the author of mfinder 1.2.\\ 90 | \textbf{License:} MIT License (2018)\\ 91 | \textbf{Version info:} v1.0\\ 92 | \textbf{Availability:} \url{https://github.com/stoufferlab/pymfinder}\\ 93 | \textbf{Platforms:} Windows, Linux, Mac OSX. \textit{pymfinder} will require you to have the Python modules Numpy and Setuptools installed in your machine. Following recommendations for mfinder, large and dense networks (\textgreater10 000 nodes) require a computer with at least 512 Mbyte RAM in order to calculate motif frequencies. Calculating node or link roles will require greater resources. The analysis of motifs bigger then 8 nodes is not recommended. 94 | 95 | \section{How to use \emph{pymfinder}} 96 | \subsection{Download and installation} 97 | \subsubsection{Download} 98 | \emph{pymfinder} can be downloaded from \url{https://github.com/stoufferlab/pymfinder}. Please make sure you cite Bramon Mora et.\ al.\ \citep{BramonMora364703} if you decide to use \emph{pymfinder}. 99 | \subsubsection{Installation} 100 | Installation within a command-line terminal should be straightforward using the function `setup.py' included in the \emph{pymfinder} package. After navigating to the directory containing the package, run: 101 | 102 | \tab\texttt{python setup.py install} 103 | 104 | If an error message of `Permission denied' or similar is returned, run: 105 | 106 | \tab\texttt{python setup.py install --user} 107 | 108 | This will install \emph{pymfinder} locally rather than in the global Python site-packages or dist-packages directory. 109 | 110 | If you are using Python 3, you should switch to the branch pymfinder-python3 of the Github repository. 111 | 112 | % If the mac is being stupid, can install with python setup.py install --user --prefix="" 113 | \subsubsection{Checking installation} 114 | After installation, running the included test suite is strongly encouraged. This may be accomplished by running: 115 | 116 | \tab\texttt{python setup.py test} 117 | 118 | \subsection{Basic usage} 119 | \subsection{Input file format} 120 | Input network file format should be in simple `.txt' format. Species names may be given as text or integers but should \textbf{not} include spaces. Each edge should be represented by a line of the following format:\\ 121 | \texttt{\textless source node\textgreater \textless target node\textgreater} 122 | 123 | Example: 124 | \begin{lstlisting} 125 | 1 2 126 | 3 1 127 | Salmo_trutta midge 128 | Corvus_corax Salmo_trutta 129 | \end{lstlisting} 130 | 131 | If interaction strengths are known, they can be passed to \emph{pymfinder} in the input file. In this case, each edge should be represented by a line with the format:\\ 132 | \texttt{\textless source node\textgreater \textless target node\textgreater \textless interaction strength\textgreater} 133 | 134 | Example: 135 | \begin{lstlisting} 136 | 1 2 1 137 | 3 1 2.5 138 | Salmo_trutta midge 0.005 139 | Corvus_corax Salmo_trutta 3 140 | \end{lstlisting} 141 | 142 | \subsubsection{Function call and arguments} 143 | All of the functions within \emph{pymfinder} can be called using the same framework. Within a Python environment, first import the \emph{pymfinder} package using, for example: 144 | 145 | \begin{lstlisting} 146 | import pymfinder as py 147 | \end{lstlisting} 148 | 149 | The motif structure, motif participation, and motif roles for the network can then be calculated simultaneously using: 150 | 151 | \begin{lstlisting} 152 | results = py.pymfinder(network, 153 | links=False, 154 | motifsize = 3, 155 | stoufferIDs = None, 156 | allmotifs = False, 157 | nrandomizations = 0, 158 | randomize = False, 159 | usemetropolis = False, 160 | networktype = "unipartite") 161 | \end{lstlisting} 162 | 163 | The \emph{pymfinder} function call includes the following arguments: 164 | \begin{itemize} 165 | \item \textbf{network}: This can be a path to a network file, a list of interactions or a NetworkStats object. No default given (see the description in the article presenting the software). 166 | \item \textbf{links}: Determines whether or not to calculate statistics for links as well as nodes. If \textbf{links=True}, link participation and roles will be calculated. Defaults to \textbf{links=False}. 167 | \item \textbf{motifsize}: Size of motifs to be calculated. Defaults to \textbf{motifsize=3}. There are 13 possible three-species motifs for unipartite networks (Fig.~\ref{fig:3sp_unipartite}). For bipartite networks, there are only four three-species motifs (Fig.~\ref{bipartite_motifs}) and a larger motif size may be necessary. If one needs to analyze the motif structure or the motif participation of motifs $>3$ nodes in unipartite networks or $>6$ nodes in bipartite networks, `motif\_structure' and `motif\_participation' need to be run independently. 168 | \item \textbf{stoufferIDs}: Determines whether to label motifs following~\citet{Stouffer2007} or based on the representation of the adjacency matrix of the motif as a binary integer, following the original \emph{mfinder} (see list\_motifs() and print\_motifs() to identify motifs based on motif ID). If \textbf{stoufferIDs=True}, labels will be as in~\citet{Stouffer2007} when printing the pymfinder output. Defaults to \textbf{stoufferIDs=False}. 169 | \item \textbf{allmotifs}: If true, displays results for all possible motifs regardless of whether all have been observed. If false, displays only results for motifs observed in the network. Defaults to \textbf{allmotifs=False}. 170 | \item \textbf{nrandomizations}: Number of random networks with which to compare the observed network. Defaults to 0 (no randomizations performed). 171 | \item \textbf{randomize}: Determines whether or not to randomize the network before analyzing the participation and roles of the nodes and links in the network. If false, no randomization will be applied to the network. Defaults to \textbf{randomize=False}. 172 | \item \textbf{usemetropolis}: If randomizations are to be performed, determines whether to use the Metropolis algorithm. If Metropolis is not used, \emph{pymfinder} uses an MCMC algorithm to shuffle the original network while preserving in- and out-degrees of nodes. Defaults to \textbf{usemetropolis=False} (MCMC-based randomizations). 173 | \item \textbf{networktype}: Indicates whether the network is unipartite (all species may interact with all other species) or bipartite (species are divided into two groups and may interact between groups but not within a group). Defaults to \textbf{networktype=``unipartite''}. 174 | \item \textbf{weighted}: If true, the motif analysis will account for the weight of the interactions. Defaults to \textbf{weighted=False}. 175 | \end{itemize} 176 | 177 | \subsubsection{Functions} 178 | The \emph{pymfinder} function call references three subordinate functions: \emph{motif\_structure}, \emph{motif\_participation}, and \emph{motif\_roles}. Each subordinate function may also be called independently if the full output from \emph{pymfinder} is not required. When \emph{pymfinder} is called, the subordinate functions are run in order (\emph{motif\_structure} then \emph{motif\_participation} then \emph{motif\_roles}). If a subordinate function is called directly, any preceding function will also be called. That is, calling \emph{motif\_structure} returns only the motif structure output but calling \emph{motif\_participation} returns the motif participation and motif structure output. Note that the three functions differ in the way in which they handle interaction weights. 179 | 180 | \emph{motif\_structure} calculates the motif profile of the network. Arguments passable to \emph{motif\_structure} are the same as those for \emph{pymfinder}, except that the \textbf{links} argument is not relevant. The same motif profile will be returned whether or not \textbf{links=True}. If \textbf{weighted=True}, the weight of all interactions forming each motif will also be considered (see the description in the article presenting the software). The characterization of the weight of a motif can be changed using the functional argument \textbf{fweight}. Such function \textbf{fweight} needs to take a Python list as input and return a value. The default \textbf{fweight} is the arithmetic mean. 181 | 182 | \emph{motif\_participation} calculates the motif participation for each node (and each link, if \textbf{links=True}). All arguments passable to \emph{motif\_participation} are the same as those passed to \emph{pymfinder}. If \textbf{weighted=True}, the weight of all interactions forming each motif will also be considered (see the description in the article presenting the software). The characterization of the weight of a motif can be changed using the functional argument \textbf{fweight}. Such function \textbf{fweight} needs to take a Python list as input and return a value. The default \textbf{fweight} is the arithmetic mean. 183 | 184 | \emph{motif\_roles} calculates the role of each node (and each link, if \textbf{links=True}). All arguments passable to \emph{motif\_roles} are the same as those passed to \emph{pymfinder}. Only defined for 2$\leq$motifsize$\leq$3 for unipartite networks and 2$\leq$motifsize$\leq$6 for bipartite networks. If \textbf{weighted=True}, the weight of all interactions forming each motif will also be considered (see the description in the article presenting the software). The characterization of the weight of a motif can be changed using the functional argument \textbf{fweight}. Such function \textbf{fweight} needs to take a Python list as input and return a value. The default \textbf{fweight} is the arithmetic mean. 185 | 186 | \emph{list\_motifs} returns all the motif IDs for a given motif size. The only arguments passable to \emph{list\_motifs} is the motif size \textbf{motifsize}. 187 | 188 | \emph{print\_motifs} print out all network motifs and motif IDs for any given motif size. The first arguments passed to \emph{list\_motifs} is the motif size \textbf{motifsize}. Other arguments passable to the function are \textbf{motifID} to print a specific motif, \textbf{outFile} to save the output in a file, and \textbf{links} to print the links forming each motif. We do not recommended using this function for \textbf{motifsize}$>$6. 189 | 190 | \subsubsection{Output} 191 | The object `results' returned by \emph{pymfinder} is a NetworkStats object containing dictionaries of motifs, nodes, and links. The value for each motif in the .motifs dictionary is an Motif object containing the motif profile for that motif. Similarly, the value for each node or link in the .nodes or .links dictionaries is a NodeLink object containing the motif participation or role of that node or link. 192 | 193 | These results can be collected into text-formatted tables and may be seen using: 194 | \begin{lstlisting} 195 | print results 196 | \end{lstlisting} 197 | 198 | or written to a file using: 199 | \begin{lstlisting} 200 | f=open(`filename',`w') 201 | f.write(str(results)) 202 | f.close() 203 | \end{lstlisting} 204 | 205 | If \textbf{links=False}, the results include three tables. The first presents the motif profile of the network. Each row gives a motif ID (see list\_motifs() and print\_motifs() to identify motifs based on ID), the count of that motif in the observed network, the mean and standard deviation of the count of that motif in the randomized networks, and the $Z$-score comparing the real network to the randomized networks. If \textbf{randomizations=False}, the random mean and standard deviations will be reported as 0.000 and the $Z$-score will be given as 888888.000. 206 | 207 | The second table presents the motif participation for each node in the network. Each row gives a node ID and the number of times the node appears in each motif. Motif ID's are given in the first row. 208 | 209 | The third table presents the role for each node in the network. Each row gives a node ID and the number of times the node appears in each position in each motif. Node positions are labeled using the following notation: (motif ID, number of predators/out links, number of prey/in links). 210 | 211 | If \textbf{links=True}, the results will also contain tables presenting links' motif participation and roles. Links' motif participation follows nodes' motif participation and link roles follow node roles. In both cases, the format of the output table echoes that of the node tables. The only notable difference is in the labeling of link positions. Rather than (motif ID, number of out links, number of in links), link positions are labeled (motif ID, (out links for node 1, in links for node 1), (out links for node 2, in links for node 2)) where nodes 1 and 2 are the two species connected by link (1,2). 212 | 213 | \clearpage 214 | 215 | \section{Figures} 216 | 217 | \begin{figure}[ht] 218 | \centering 219 | \includegraphics*[width=0.9\textwidth]{unipartite_motifs.eps} 220 | \caption{The thirteen three-species motifs in unipartite networks. The 30 unique positions are numbered. Note also that some motifs contain three unique positions (e.g., positions 5, 6, and 7) while other motifs contain only one or two unique positions.} 221 | \label{fig:3sp_unipartite} 222 | \end{figure} 223 | 224 | 225 | \begin{figure}[ht] 226 | \centering 227 | \includegraphics*[width=0.9\textwidth]{bipartite_motifs.eps} 228 | \vspace{0.5cm} 229 | \caption{The singe two-species motif, two three-species motifs, four four-species motifs, 10 five-species motifs, and 27 six-species motifs that can be found in bipartite networks. Unique positions are numbered. If the identity of particular motifs and/or positions is important, be sure to note the motif number and position information provided in the output file.} 230 | \label{bipartite_motifs} 231 | \end{figure} 232 | 233 | \clearpage 234 | 235 | 236 | \bibliography{biblist} 237 | 238 | \clearpage 239 | \end{document} 240 | 241 | -------------------------------------------------------------------------------- /pymfinder/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __all__ = [ 4 | 'list_motifs', 5 | 'print_motifs', 6 | 'random_network', 7 | 'motif_structure', 8 | 'motif_participation', 9 | 'motif_roles', 10 | 'pymfinder', 11 | ] 12 | 13 | from pymfinder import list_motifs, print_motifs 14 | from pymfinder import random_network 15 | from pymfinder import motif_structure 16 | from pymfinder import motif_participation 17 | from pymfinder import motif_roles 18 | from pymfinder import pymfinder 19 | -------------------------------------------------------------------------------- /pymfinder/data/bipartite-2-test.net: -------------------------------------------------------------------------------- 1 | A2.1 B1.1 2 | -------------------------------------------------------------------------------- /pymfinder/data/bipartite-3-test.net: -------------------------------------------------------------------------------- 1 | A4.1 B3.1 2 | A4.1 B3.2 3 | A6.1 B5.1 4 | A6.2 B5.1 5 | -------------------------------------------------------------------------------- /pymfinder/data/bipartite-4-test.net: -------------------------------------------------------------------------------- 1 | A08.1 B07.1 2 | A08.2 B07.1 3 | A08.3 B07.1 4 | A12.1 B09.1 5 | A12.1 B10.1 6 | A11.1 B10.1 7 | A14.1 B13.1 8 | A14.2 B13.1 9 | A14.1 B13.2 10 | A14.2 B13.2 11 | A16.1 B15.1 12 | A16.1 B15.2 13 | A16.1 B15.3 14 | -------------------------------------------------------------------------------- /pymfinder/data/bipartite-5-test.net: -------------------------------------------------------------------------------- 1 | A18.1 B17.1 2 | A18.2 B17.1 3 | A18.3 B17.1 4 | A18.4 B17.1 5 | A21.1 B20.1 6 | A21.2 B20.1 7 | A22.1 B20.1 8 | A22.1 B19.1 9 | A24.1 B23.1 10 | A25.1 B23.1 11 | A25.1 B23.2 12 | A24.2 B23.2 13 | A28.1 B27.1 14 | A29.1 B27.1 15 | A29.2 B27.1 16 | A29.1 B26.1 17 | A29.2 B26.1 18 | A31.1 B30.1 19 | A31.2 B30.1 20 | A31.3 B30.1 21 | A31.1 B30.2 22 | A31.2 B30.2 23 | A31.3 B30.2 24 | A34.1 B33.1 25 | A35.1 B33.1 26 | A35.1 B32.1 27 | A35.1 B32.2 28 | A38.1 B36.1 29 | A38.2 B37.1 30 | A38.1 B37.1 31 | A38.2 B36.2 32 | A41.1 B40.1 33 | A42.1 B40.1 34 | A42.1 B40.2 35 | A41.1 B40.2 36 | A42.1 B39.1 37 | A44.1 B43.1 38 | A44.2 B43.1 39 | A44.2 B43.2 40 | A44.1 B43.2 41 | A44.2 B43.3 42 | A44.1 B43.3 43 | A46.1 B45.1 44 | A46.1 B45.2 45 | A46.1 B45.3 46 | A46.1 B45.4 47 | -------------------------------------------------------------------------------- /pymfinder/data/bipartite-6-test.net: -------------------------------------------------------------------------------- 1 | A048.1 B047.1 2 | A048.2 B047.1 3 | A048.3 B047.1 4 | A048.4 B047.1 5 | A048.5 B047.1 6 | A052.1 B049.1 7 | A052.1 B050.1 8 | A051.1 B050.1 9 | A051.2 B050.1 10 | A051.3 B050.1 11 | A055.1 B053.1 12 | A057.1 B053.1 13 | A057.1 B054.1 14 | A056.1 B054.1 15 | A056.2 B054.1 16 | A060.1 B059.1 17 | A060.2 B059.1 18 | A061.1 B059.1 19 | A061.1 B058.1 20 | A061.2 B059.1 21 | A061.2 B058.1 22 | A063.1 B062.1 23 | A064.1 B062.1 24 | A064.2 B062.1 25 | A064.1 B062.2 26 | A064.2 B062.2 27 | A063.2 B062.2 28 | A068.1 B065.1 29 | A068.2 B065.1 30 | A068.3 B065.1 31 | A068.1 B066.1 32 | A068.2 B066.1 33 | A068.3 B066.1 34 | A067.1 B066.1 35 | A070.1 B069.1 36 | A070.2 B069.1 37 | A070.3 B069.1 38 | A070.4 B069.1 39 | A070.1 B069.2 40 | A070.2 B069.2 41 | A070.3 B069.2 42 | A070.4 B069.2 43 | A073.1 B072.1 44 | A073.2 B072.1 45 | A074.1 B072.1 46 | A074.1 B071.1 47 | A074.1 B071.2 48 | A078.1 B075.1 49 | A077.1 B075.1 50 | A077.1 B076.1 51 | A077.1 B075.2 52 | A078.2 B075.2 53 | A081.1 B080.1 54 | A081.1 B079.1 55 | A082.1 B079.1 56 | A081.2 B079.1 57 | A081.2 B080.2 58 | A087.1 B083.1 59 | A087.1 B085.1 60 | A088.1 B085.1 61 | A088.1 B084.1 62 | A086.1 B084.1 63 | A092.1 B091.1 64 | A093.1 B091.1 65 | A094.1 B091.1 66 | A093.1 B090.1 67 | A094.1 B090.1 68 | A094.1 B089.1 69 | A098.1 B095.1 70 | A098.1 B097.1 71 | A099.1 B097.1 72 | A099.2 B097.1 73 | A099.1 B096.1 74 | A099.2 B096.1 75 | A103.1 B100.1 76 | A103.1 B101.1 77 | A102.1 B101.1 78 | A102.2 B101.1 79 | A103.1 B101.2 80 | A102.1 B101.2 81 | A102.2 B101.2 82 | A107.1 B105.1 83 | A108.1 B105.1 84 | A107.1 B105.2 85 | A108.1 B105.2 86 | A108.1 B104.1 87 | A106.1 B104.1 88 | A111.1 B110.1 89 | A112.1 B110.1 90 | A112.2 B110.1 91 | A112.1 B109.1 92 | A112.2 B109.1 93 | A112.1 B109.2 94 | A112.2 B109.2 95 | A114.1 B113.1 96 | A114.2 B113.1 97 | A114.2 B113.2 98 | A114.3 B113.2 99 | A114.1 B113.3 100 | A114.3 B113.3 101 | A117.1 B115.1 102 | A118.1 B115.1 103 | A117.1 B116.1 104 | A118.1 B116.1 105 | A117.2 B116.1 106 | A118.1 B115.2 107 | A117.2 B115.2 108 | A122.1 B119.1 109 | A122.2 B119.1 110 | A122.1 B120.1 111 | A122.2 B120.1 112 | A121.1 B120.1 113 | A122.1 B120.2 114 | A122.2 B120.2 115 | A121.1 B120.2 116 | A124.1 B123.1 117 | A124.2 B123.1 118 | A124.3 B123.1 119 | A124.1 B123.2 120 | A124.2 B123.2 121 | A124.3 B123.2 122 | A124.1 B123.3 123 | A124.2 B123.3 124 | A124.3 B123.3 125 | A127.1 B126.1 126 | A128.1 B126.1 127 | A128.1 B125.1 128 | A128.1 B125.2 129 | A128.1 B125.3 130 | A132.1 B129.1 131 | A132.1 B131.1 132 | A133.1 B131.1 133 | A133.1 B130.1 134 | A133.1 B130.2 135 | A136.1 B135.1 136 | A137.1 B135.1 137 | A136.1 B135.2 138 | A137.1 B135.2 139 | A137.1 B134.1 140 | A137.1 B134.2 141 | A140.1 B138.1 142 | A140.1 B139.1 143 | A140.2 B139.1 144 | A140.1 B139.2 145 | A140.2 B139.2 146 | A140.2 B138.2 147 | A143.1 B142.1 148 | A144.1 B142.1 149 | A143.1 B142.2 150 | A144.1 B142.2 151 | A143.1 B142.3 152 | A144.1 B142.3 153 | A144.1 B141.1 154 | A146.1 B145.1 155 | A146.2 B145.1 156 | A146.1 B145.2 157 | A146.2 B145.2 158 | A146.1 B145.3 159 | A146.2 B145.3 160 | A146.1 B145.4 161 | A146.2 B145.4 162 | A148.1 B147.1 163 | A148.1 B147.2 164 | A148.1 B147.3 165 | A148.1 B147.4 166 | A148.1 B147.5 167 | -------------------------------------------------------------------------------- /pymfinder/data/bipartite-test.net: -------------------------------------------------------------------------------- 1 | A1 B13 2 | A1 B15 3 | A1 B17 4 | A1 B20 5 | A1 B21 6 | A1 B22 7 | A1 B25 8 | A1 B26 9 | A1 B27 10 | A1 B40 11 | A2 B13 12 | A2 B14 13 | A2 B16 14 | A2 B17 15 | A2 B18 16 | A2 B19 17 | A2 B20 18 | A2 B21 19 | A2 B22 20 | A2 B23 21 | A2 B24 22 | A2 B25 23 | A2 B26 24 | A2 B27 25 | A2 B28 26 | A2 B30 27 | A2 B31 28 | A2 B33 29 | A2 B36 30 | A2 B38 31 | A2 B39 32 | A3 B13 33 | A3 B14 34 | A3 B21 35 | A3 B28 36 | A3 B30 37 | A3 B34 38 | A4 B13 39 | A4 B14 40 | A4 B17 41 | A4 B27 42 | A5 B11 43 | A5 B13 44 | A5 B14 45 | A5 B17 46 | A5 B18 47 | A5 B20 48 | A5 B21 49 | A5 B26 50 | A5 B27 51 | A5 B30 52 | A5 B32 53 | A5 B36 54 | A6 B10 55 | A6 B13 56 | A6 B14 57 | A6 B16 58 | A6 B17 59 | A6 B18 60 | A6 B20 61 | A6 B21 62 | A6 B23 63 | A6 B26 64 | A6 B27 65 | A6 B28 66 | A6 B30 67 | A6 B31 68 | A6 B34 69 | A6 B36 70 | A6 B37 71 | A6 B38 72 | A7 B12 73 | A7 B13 74 | A7 B14 75 | A7 B15 76 | A7 B16 77 | A7 B17 78 | A7 B18 79 | A7 B20 80 | A7 B21 81 | A7 B22 82 | A7 B25 83 | A7 B26 84 | A7 B28 85 | A7 B29 86 | A7 B30 87 | A7 B31 88 | A7 B32 89 | A7 B34 90 | A7 B35 91 | A7 B36 92 | A7 B40 93 | A8 B10 94 | A8 B13 95 | A8 B14 96 | A8 B16 97 | A8 B17 98 | A8 B18 99 | A8 B20 100 | A8 B21 101 | A8 B26 102 | A8 B27 103 | A8 B28 104 | A8 B30 105 | A8 B31 106 | A8 B32 107 | A8 B36 108 | A8 B38 109 | A9 B13 110 | A9 B14 111 | A9 B20 112 | A9 B23 113 | A9 B26 114 | A9 B27 115 | A9 B28 116 | A9 B30 117 | A9 B32 118 | A9 B34 119 | A9 B40 120 | A10 B6 121 | A10 B8 122 | A11 B5 123 | A12 B7 124 | A13 B1 125 | A13 B2 126 | A13 B3 127 | A13 B4 128 | A13 B5 129 | A13 B6 130 | A13 B7 131 | A13 B8 132 | A13 B9 133 | A14 B2 134 | A14 B3 135 | A14 B4 136 | A14 B5 137 | A14 B6 138 | A14 B7 139 | A14 B8 140 | A14 B9 141 | A15 B1 142 | A15 B7 143 | A16 B2 144 | A16 B6 145 | A16 B7 146 | A16 B8 147 | A17 B1 148 | A17 B2 149 | A17 B4 150 | A17 B5 151 | A17 B6 152 | A17 B7 153 | A17 B8 154 | A18 B2 155 | A18 B5 156 | A18 B6 157 | A18 B7 158 | A18 B8 159 | A19 B2 160 | A20 B1 161 | A20 B2 162 | A20 B5 163 | A20 B6 164 | A20 B7 165 | A20 B8 166 | A20 B9 167 | A21 B1 168 | A21 B2 169 | A21 B3 170 | A21 B5 171 | A21 B6 172 | A21 B7 173 | A21 B8 174 | A22 B1 175 | A22 B2 176 | A22 B7 177 | A23 B2 178 | A23 B6 179 | A23 B9 180 | A24 B2 181 | A25 B1 182 | A25 B2 183 | A25 B7 184 | A26 B1 185 | A26 B2 186 | A26 B5 187 | A26 B6 188 | A26 B7 189 | A26 B8 190 | A26 B9 191 | A27 B1 192 | A27 B2 193 | A27 B4 194 | A27 B5 195 | A27 B6 196 | A27 B8 197 | A27 B9 198 | A28 B2 199 | A28 B3 200 | A28 B6 201 | A28 B7 202 | A28 B8 203 | A28 B9 204 | A29 B7 205 | A30 B2 206 | A30 B3 207 | A30 B5 208 | A30 B6 209 | A30 B7 210 | A30 B8 211 | A30 B9 212 | A31 B2 213 | A31 B6 214 | A31 B7 215 | A31 B8 216 | A32 B5 217 | A32 B7 218 | A32 B8 219 | A32 B9 220 | A33 B2 221 | A34 B3 222 | A34 B6 223 | A34 B7 224 | A34 B9 225 | A35 B7 226 | A36 B2 227 | A36 B5 228 | A36 B6 229 | A36 B7 230 | A36 B8 231 | A37 B6 232 | A38 B2 233 | A38 B6 234 | A38 B8 235 | A39 B2 236 | A40 B1 237 | A40 B7 238 | A40 B9 239 | -------------------------------------------------------------------------------- /pymfinder/data/unipartite-2-test.net: -------------------------------------------------------------------------------- 1 | 2A 2B 2.1 2 | 6A 6B 6.1 3 | 6B 6A 6.2 4 | -------------------------------------------------------------------------------- /pymfinder/data/unipartite-3-test.net: -------------------------------------------------------------------------------- 1 | 108A 108B 108.1 2 | 108B 108A 108.2 3 | 108C 108A 108.3 4 | 108C 108B 108.4 5 | 46A 46B 46.1 6 | 46C 46B 46.2 7 | 46A 46C 46.3 8 | 46C 46A 46.4 9 | 74A 74B 74.1 10 | 74B 74A 74.2 11 | 74C 74B 74.3 12 | 14A 14B 14.1 13 | 14A 14C 14.2 14 | 14C 14A 14.3 15 | 102A 102B 102.1 16 | 102B 102C 102.2 17 | 102C 102B 102.3 18 | 102C 102A 102.4 19 | 238A 238B 238.1 20 | 238B 238A 238.2 21 | 238B 238C 238.3 22 | 238C 238B 238.4 23 | 238C 238A 238.5 24 | 238A 238C 238.6 25 | 110A 110B 110.1 26 | 110B 110A 110.2 27 | 110A 110C 110.3 28 | 110C 110A 110.4 29 | 110C 110B 110.5 30 | 78A 78B 78.1 31 | 78B 78A 78.2 32 | 78C 78B 78.3 33 | 78B 78C 78.4 34 | 12A 12B 12.1 35 | 12B 12C 12.2 36 | 38A 38B 38.1 37 | 38A 38C 38.2 38 | 38C 38B 38.3 39 | 98A 98B 98.1 40 | 98B 98C 98.2 41 | 98C 98A 98.3 42 | 6A 6B 6.1 43 | 6A 6C 6.2 44 | 36A 36B 36.1 45 | 36C 36B 36.2 46 | -------------------------------------------------------------------------------- /pymfinder/datatypes.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | ############################################################## 5 | ############################################################## 6 | # What is a motif? 7 | ############################################################## 8 | ############################################################## 9 | 10 | class Motif(object): 11 | """Motif info class""" 12 | 13 | def __init__(self,motif_id=None): 14 | self.id = motif_id 15 | self.real = None 16 | self.all_members = set() 17 | self.random = list() 18 | self.random_m = None 19 | self.random_sd = None 20 | self.real_z = None 21 | self.mean_weight = None 22 | self.sd_weight = None 23 | self.median_weight = None 24 | self.thirdq_weight = None 25 | self.firstq_weight = None 26 | 27 | # def __rep__(self): 28 | # return(str(self.id)) 29 | 30 | 31 | ############################################################## 32 | ############################################################## 33 | # What is a node or a link? 34 | ############################################################## 35 | ############################################################## 36 | 37 | class NodeLink(object): 38 | """NodeLink info class""" 39 | 40 | def __init__(self,nodelink_id=None): 41 | self.id = nodelink_id 42 | self.motifs = dict() 43 | self.roles = dict() 44 | self.weighted_roles = dict() 45 | self.weighted_motifs = dict() 46 | 47 | 48 | ############################################################## 49 | ############################################################## 50 | # What is a network stats? 51 | ############################################################## 52 | ############################################################## 53 | 54 | class NetworkStats(object): 55 | """NetworkStats summary info class""" 56 | 57 | def __init__(self, motifsize = None, networktype = None, weighted = None, stoufferIDs = None): 58 | self.motifs = dict() 59 | self.nodes = dict() 60 | self.links = dict() 61 | self.networktype = networktype 62 | self.motifsize = motifsize 63 | self.weighted = weighted 64 | self.stoufferIDs = stoufferIDs 65 | 66 | def add_motif(self,motif_id): 67 | if motif_id in self.motifs: 68 | sys.stderr.write("You're trying to add a motif more than once. According to the developers, this is classified as highly unusual.\n") 69 | else: 70 | self.motifs[motif_id] = Motif(motif_id) 71 | 72 | def add_node(self, node_id, node_name=None): 73 | if node_id in self.nodes: 74 | sys.stderr.write("You're trying to add a node more than once. According to the developers, this is classified as highly unusual.\n") 75 | else: 76 | self.nodes[node_id] = NodeLink(node_name) 77 | 78 | def add_link(self, link_id, link_name=None): 79 | if link_id in self.links: 80 | sys.stderr.write("You're trying to add a link more than once. According to the developers, this is classified as highly unusual.\n") 81 | else: 82 | self.links[link_id] = NodeLink(link_name) 83 | 84 | # DEBUG: it would be nice to be able to turn the header on and off 85 | def __str__(self): 86 | 87 | from roles import STOUFFER_MOTIF_IDS 88 | 89 | if self.stoufferIDs: 90 | ineligible_ids = [motif_id for motif_id in self.motifs if motif_id not in STOUFFER_MOTIF_IDS] 91 | else: 92 | ineligible_ids = [1,2,3] 93 | 94 | output = "" 95 | 96 | if self.motifs != dict(): 97 | output = output + " ".join(['motif', 98 | 'real', 99 | 'rand', 100 | 'srand', 101 | 'zscore', 102 | 'weight-mean', 103 | 'weight-sd',]) + '\n' 104 | 105 | # set up the data itself 106 | for m in sorted(self.motifs.keys()): 107 | 108 | if len(ineligible_ids) == 0: 109 | motifname = STOUFFER_MOTIF_IDS[m] 110 | else: 111 | motifname = m 112 | 113 | output = output + " ".join(["%s" % str(motifname), 114 | "%i" % self.motifs[m].real, 115 | "%.3f" % self.motifs[m].random_m, 116 | "%.3f" % self.motifs[m].random_sd, 117 | "%.3f" % self.motifs[m].real_z, 118 | "%.3f" % self.motifs[m].mean_weight, 119 | "%.3f" % self.motifs[m].sd_weight, 120 | ]) + '\n' 121 | output = output + '\n' 122 | 123 | if self.nodes[self.nodes.keys()[0]].motifs != dict(): 124 | # set up a header 125 | if len(ineligible_ids) == 0: 126 | output = output + " ".join(["node"]+list(map(str, [STOUFFER_MOTIF_IDS[mid] for mid in sorted(self.nodes[self.nodes.keys()[0]].motifs.keys())]))) 127 | else: 128 | output = output + " ".join(["node"]+list(map(str,sorted(self.nodes[self.nodes.keys()[0]].motifs.keys())))) 129 | 130 | output = output + '\n' 131 | 132 | # set up the data itself 133 | if self.weighted: 134 | for m in sorted(self.nodes.keys()): 135 | output = output + " ".join([str(self.nodes[m].id)] + list(map(str,[j for i,j in sorted(self.nodes[m].weighted_motifs.items())]))) + '\n' 136 | output = output + '\n' 137 | else: 138 | for m in sorted(self.nodes.keys()): 139 | output = output + " ".join([str(self.nodes[m].id)] + list(map(str,[j for i,j in sorted(self.nodes[m].motifs.items())]))) + '\n' 140 | output = output + '\n' 141 | 142 | if self.links[self.links.keys()[0]].motifs != dict(): 143 | # set up a header 144 | output = output + " ".join(["link"]+list(map(str,sorted(self.links[self.links.keys()[0]].motifs.keys())))) 145 | output = output + '\n' 146 | 147 | if self.weighted: 148 | # set up the data itself 149 | for m in sorted(self.links.keys()): 150 | output = output + " ".join([str(self.links[m].id)] + list(map(str,[j for i,j in sorted(self.links[m].weighted_motifs.items())]))) + '\n' 151 | output = output + '\n' 152 | else: 153 | # set up the data itself 154 | for m in sorted(self.links.keys()): 155 | output = output + " ".join([str(self.links[m].id)] + list(map(str,[j for i,j in sorted(self.links[m].motifs.items())]))) + '\n' 156 | output = output + '\n' 157 | 158 | 159 | if self.nodes[self.nodes.keys()[0]].roles != dict(): 160 | # set up a header 161 | output = output+" ".join(["node"]+list(map(str,[role for role in sorted(self.nodes[self.nodes.keys()[0]].roles.keys())]))) 162 | output = output + '\n' 163 | 164 | if self.weighted: 165 | for m in sorted(self.nodes.keys()): 166 | output = output + " ".join([str(self.nodes[m].id)] + list(map(str,[j for i,j in sorted(self.nodes[m].weighted_roles.items())]))) + '\n' 167 | output = output + '\n' 168 | else: 169 | for m in sorted(self.nodes.keys()): 170 | output = output + " ".join([str(self.nodes[m].id)] + list(map(str,[j for i,j in sorted(self.nodes[m].roles.items())]))) + '\n' 171 | output = output + '\n' 172 | 173 | 174 | if self.links[self.links.keys()[0]].roles != dict(): 175 | # set up a header 176 | output = output + " ".join(["link"]+list(map(str,sorted(self.links[self.links.keys()[0]].roles.keys())))) 177 | output = output + '\n' 178 | 179 | if self.weighted: 180 | # set up the data itself 181 | for m in sorted(self.links.keys()): 182 | output = output + " ".join([str(self.links[m].id)] + list(map(str,[j for i,j in sorted(self.links[m].weighted_roles.items())]))) + '\n' 183 | output = output + '\n' 184 | else: 185 | # set up the data itself 186 | for m in sorted(self.links.keys()): 187 | output = output + " ".join([str(self.links[m].id)] + list(map(str,[j for i,j in sorted(self.links[m].roles.items())]))) + '\n' 188 | output = output + '\n' 189 | 190 | 191 | # return this ghastly beast 192 | return(output) 193 | 194 | 195 | -------------------------------------------------------------------------------- /pymfinder/mfinder/.gitignore: -------------------------------------------------------------------------------- 1 | ################### 2 | # Compiled source # 3 | ################### 4 | *.o 5 | -------------------------------------------------------------------------------- /pymfinder/mfinder/README: -------------------------------------------------------------------------------- 1 | The original code for mfinder version 1.2 can be found on Uri Alon's website (http://www.weizmann.ac.il/mcb/UriAlon/). 2 | 3 | This code has been included here and modified with the explicit consent of the author of mfinder, Nadav Kashtan (nadav.kashtan@gmail.com). 4 | -------------------------------------------------------------------------------- /pymfinder/mfinder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/__init__.py -------------------------------------------------------------------------------- /pymfinder/mfinder/bits.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/bits.h -------------------------------------------------------------------------------- /pymfinder/mfinder/clustering.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/clustering.c -------------------------------------------------------------------------------- /pymfinder/mfinder/clustering.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/clustering.h -------------------------------------------------------------------------------- /pymfinder/mfinder/common.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/common.h -------------------------------------------------------------------------------- /pymfinder/mfinder/globals.c: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | * 3 | * copied out of globals.h because I've changed the original functions 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | *************************************************************************/ 11 | #include "common.h" 12 | #include "wrapper.h" 13 | 14 | /*************************** Global variables ****************************/ 15 | 16 | 17 | /******************************* Externs *********************************/ 18 | 19 | extern int DEBUG_LEVEL; 20 | extern Gnrl_st GNRL_ST; 21 | 22 | /******************************* Functions *******************************/ 23 | 24 | // free Network structure related allocated memory 25 | void 26 | free_network_mem(Network *N) 27 | { 28 | int i; 29 | 30 | if(N!=NULL) { 31 | if(N->mat !=NULL){ 32 | MatFree(N->mat); 33 | free(N->mat); 34 | } 35 | if(N->e_arr!=NULL) 36 | free(N->e_arr); 37 | if(N->e_arr_sin!=NULL) 38 | free(N->e_arr_sin); 39 | if(N->e_arr_dbl!=NULL) 40 | free(N->e_arr_dbl); 41 | if(N->e_arr_self!=NULL) 42 | free(N->e_arr_self); 43 | if(N->indeg!=NULL) 44 | free(N->indeg); 45 | if(N->outdeg!=NULL) 46 | free(N->outdeg); 47 | if(N->doubledeg!=NULL) 48 | free(N->doubledeg); 49 | if(N->cluster_degree!=NULL) 50 | free(N->cluster_degree); 51 | if(N->roles_vec!=NULL) { 52 | for(i=1;ivertices_num;i++) 53 | free(N->roles_vec[i]); 54 | free(N->roles_vec); 55 | } 56 | if(GNRL_ST.efc_prob) { 57 | if(N->e_map!=NULL){ 58 | MatFree(N->e_map); 59 | free(N->e_map); 60 | } 61 | if(N->hub_edges_indices!=NULL) 62 | free(N->hub_edges_indices); 63 | if(N->hub_edges_vec!=NULL) 64 | free(N->hub_edges_vec); 65 | } 66 | if(GNRL_ST.r_conserve_layers){ 67 | free(N->layer_edges_num); 68 | free(N->layer_node_num); 69 | } 70 | } 71 | } 72 | 73 | /* 74 | * function : load_network 75 | * Load network form input file 76 | * arguments: 77 | * N_p - reference to network structure 78 | * network_fname - network file name 79 | * 80 | * return values: 81 | * RC_OK - if not error occured 82 | * RC_ERR - if error occured 83 | */ 84 | int 85 | load_network(Network **N_p, char* network_fname) 86 | { 87 | int rc=RC_OK,s,t,i,j,weight; 88 | list *e_list, *e_self_list; 89 | list_item *l_e; 90 | int max_node=0; 91 | Edge *e; 92 | FILE *fp; 93 | Network *N; 94 | int e_idx; 95 | int self_edge_exists=FALSE; 96 | int matVal = 0; 97 | 98 | fp = fopen(network_fname,"rt"); 99 | if(fp==NULL) { 100 | printf("\nError: Cannot open input file : %s\n\tF input file name and path\n",network_fname); 101 | at_exit(-1); 102 | } 103 | N=(Network*)calloc(1,sizeof(Network)); 104 | N->name=network_fname; 105 | N->edges_num = 0; 106 | N->e_self_num = 0; 107 | 108 | //build edge array 109 | list_init(&e_list); 110 | list_init(&e_self_list); 111 | 112 | //SRC->TRG format 113 | if(GNRL_ST.input_net_format==SRC_TRG_FORMAT) { 114 | if(GNRL_ST.quiet_mode==FALSE) 115 | fprintf(stdout,"\tReading Network file in Format\n"); 116 | //read all edges one by one and insert each edge to edge list 117 | while ( (rc = fscanf( fp,"%d %d %d\n", &s, &t, &weight) != EOF) ) { 118 | //insert edge to edge list 119 | e=(Edge*)calloc(1,sizeof(Edge)); 120 | e->s=s; 121 | e->t=t; 122 | if(GNRL_ST.calc_weights == TRUE) 123 | { 124 | e->weight=weight; 125 | } 126 | else 127 | { 128 | e->weight=1; 129 | } 130 | 131 | if(s == t) 132 | { 133 | N->e_self_num++; 134 | list_insert(e_self_list,0,(void*)e); 135 | if(GNRL_ST.calc_self_edges == TRUE){ 136 | list_insert(e_list,0,(void*)e); 137 | if (s>max_node) max_node=s; 138 | if (t>max_node) max_node=t; 139 | N->edges_num++; 140 | } 141 | } 142 | else 143 | { 144 | list_insert(e_list,0,(void*)e); 145 | if (s>max_node) max_node=s; 146 | if (t>max_node) max_node=t; 147 | N->edges_num++; 148 | } 149 | } 150 | } else { 151 | //TRG->SRC fvormat 152 | if(GNRL_ST.quiet_mode==FALSE) 153 | fprintf(stdout,"\tReading Network file in Format\n"); 154 | //read all edges one by one and insert each edge to edge list 155 | while ( (rc = fscanf( fp,"%d %d %d\n", &t, &s, &weight) != EOF) ) { 156 | //insert edge to edge list 157 | e=(Edge*)calloc(1,sizeof(Edge)); 158 | e->s=s; 159 | e->t=t; 160 | if(GNRL_ST.calc_weights == TRUE) 161 | { 162 | e->weight=weight; 163 | } 164 | else 165 | { 166 | e->weight=1; 167 | } 168 | 169 | if(s == t) 170 | { 171 | N->e_self_num++; 172 | list_insert(e_self_list,0,(void*)e); 173 | if(GNRL_ST.calc_self_edges == TRUE){ 174 | list_insert(e_list,0,(void*)e); 175 | if (s>max_node) max_node=s; 176 | if (t>max_node) max_node=t; 177 | N->edges_num++; 178 | } 179 | } 180 | else 181 | { 182 | list_insert(e_list,0,(void*)e); 183 | if (s>max_node) max_node=s; 184 | if (t>max_node) max_node=t; 185 | N->edges_num++; 186 | } 187 | } 188 | } 189 | fclose(fp); 190 | 191 | //directed graph 192 | if(GNRL_ST.undirected_flag==FALSE) { 193 | //allocate e_arr fill it according to e_list and free e_list 194 | N->e_arr=(Edge*)calloc(N->edges_num+1,sizeof(Edge)); 195 | 196 | for(i=N->edges_num,l_e=list_get_next(e_list,NULL);i>0;i--,l_e=list_get_next(e_list,l_e)){ 197 | N->e_arr[i].s=((Edge*)(l_e->p))->s; 198 | N->e_arr[i].t=((Edge*)(l_e->p))->t; 199 | N->e_arr[i].weight=((Edge*)(l_e->p))->weight; 200 | } 201 | } 202 | //undirected graph 203 | else { 204 | N->edges_num = N->edges_num*2 - N->e_self_num; 205 | N->e_arr=(Edge*)calloc((N->edges_num+1),sizeof(Edge)); 206 | 207 | for(i=N->edges_num,l_e=list_get_next(e_list,NULL);i>0;i--,l_e=list_get_next(e_list,l_e)) 208 | { 209 | N->e_arr[i].s=((Edge*)(l_e->p))->s; 210 | N->e_arr[i].t=((Edge*)(l_e->p))->t; 211 | N->e_arr[i].weight=((Edge*)(l_e->p))->weight; 212 | if(((Edge*)(l_e->p))->s != ((Edge*)(l_e->p))->t) // not a self edge 213 | { 214 | i--; 215 | N->e_arr[i].s=((Edge*)(l_e->p))->t; 216 | N->e_arr[i].t=((Edge*)(l_e->p))->s; 217 | N->e_arr[i].weight=((Edge*)(l_e->p))->weight; 218 | } 219 | } 220 | } 221 | list_free_mem(e_list); 222 | 223 | //self edges 224 | //allocate e_arr_self and fill it according to e_self_list and free e_self_list 225 | N->e_arr_self=(Edge*)calloc(N->e_self_num+1,sizeof(Edge)); 226 | for(i=N->e_self_num,l_e=list_get_next(e_self_list,NULL);i>0;i--,l_e=list_get_next(e_self_list,l_e)){ 227 | N->e_arr_self[i].s=((Edge*)(l_e->p))->s; 228 | N->e_arr_self[i].t=((Edge*)(l_e->p))->t; 229 | N->e_arr_self[i].weight=((Edge*)(l_e->p))->weight; 230 | } 231 | list_free_mem(e_self_list); 232 | 233 | N->vertices_num=max_node; 234 | 235 | rc |= MatInit(&N->mat,N->vertices_num,SPARSE); 236 | if(rc == RC_ERR) { 237 | printf("Error : Memory allocation failure\n"); 238 | at_exit(-1); 239 | } 240 | 241 | //assign matrix entries according to edges 242 | for(i=1; i<=N->edges_num; i++) { 243 | if(GNRL_ST.calc_weights == TRUE) { 244 | MatAsgn(N->mat,N->e_arr[i].s,N->e_arr[i].t,N->e_arr[i].weight); 245 | }else{ 246 | if(MatGet(N->mat,N->e_arr[i].s,N->e_arr[i].t) != 0) { 247 | printf("Error : Duplicate appearance of the edge (%d,%d) \n\tfound in the Network\n ", 248 | N->e_arr[i].s,N->e_arr[i].t); 249 | at_exit(-1); 250 | }else{ 251 | MatAsgn(N->mat,N->e_arr[i].s,N->e_arr[i].t,1); 252 | } 253 | } 254 | } 255 | //if efc_prob app then 256 | //create e_map matrix mapping of edges [s,t] to their index in e_arr 257 | if(GNRL_ST.efc_prob){ 258 | rc |= MatInit(&N->e_map,N->vertices_num,SPARSE); 259 | if(rc == RC_ERR) { 260 | printf("Error : Memory allocation failure\n"); 261 | at_exit(-1); 262 | } 263 | for(i=1; i<=N->edges_num; i++) 264 | 265 | MatAsgn(N->e_map,N->e_arr[i].s,N->e_arr[i].t,i); 266 | } 267 | //check there are no Self edges- if there are any then output them to screen and stop 268 | if(GNRL_ST.calc_self_edges == FALSE){ 269 | for(i=1; i<=N->vertices_num; i++) { 270 | if(MatGet(N->mat,i,i)==1) { 271 | fprintf(stdout,"Self edges exist in Input Network!!!\n"); 272 | fprintf(stdout,"Self Edges : (%d,%d)\t",i,i); 273 | self_edge_exists=TRUE; 274 | } 275 | } 276 | if(self_edge_exists==TRUE) 277 | at_exit(-1); 278 | } 279 | 280 | //allocate and fill arrays of single edges and double edges 281 | N->e_arr_sin=(Edge*)calloc(N->edges_num+1,sizeof(Edge)); 282 | N->e_arr_dbl=(Edge*)calloc((N->edges_num+1),sizeof(Edge)); 283 | N->e_sin_num=0; 284 | N->e_dbl_num=0; 285 | N->roots_num=0; 286 | N->leafs_num=0; 287 | //allocate indeg and out deg arrays 288 | N->indeg=(int*)calloc(N->vertices_num+2,sizeof(int)); 289 | N->outdeg=(int*)calloc(N->vertices_num+2,sizeof(int)); 290 | N->doubledeg=(int*)calloc(N->vertices_num+2,sizeof(int)); 291 | if(GNRL_ST.calc_self_edges == TRUE){ 292 | N->self_edge=(int*)calloc(N->vertices_num+2,sizeof(int)); 293 | } 294 | //actually matrix is sparse anyway now 295 | if(N->mat->type == SPARSE) { 296 | for(i=1;i<=N->vertices_num;i++) { 297 | for(j=1;j<=N->vertices_num;j++) { 298 | if( (matVal = MatGet(N->mat,i,j))) { 299 | //if an edge and is not self edge 300 | if(i != j){ 301 | //if the twin edge exists 302 | if(MatGet(N->mat,j,i)){ 303 | //not inserted yet 304 | if(j>i) { 305 | //double edge- this way always the twin pair has indexes 2x-1,2x 306 | N->e_arr_dbl[++N->e_dbl_num].s=i; 307 | N->e_arr_dbl[N->e_dbl_num].t=j; 308 | N->e_arr_dbl[N->e_dbl_num].weight=matVal; 309 | N->e_arr_dbl[++N->e_dbl_num].s=j; 310 | N->e_arr_dbl[N->e_dbl_num].t=i; 311 | N->e_arr_dbl[N->e_dbl_num].weight=matVal; 312 | } 313 | } 314 | else { 315 | //single edge 316 | N->e_arr_sin[++N->e_sin_num].s=i; 317 | N->e_arr_sin[N->e_sin_num].t=j; 318 | N->e_arr_sin[N->e_sin_num].weight=matVal; 319 | } 320 | } 321 | else //self edge 322 | { 323 | N->e_arr_sin[++N->e_sin_num].s=i; 324 | N->e_arr_sin[N->e_sin_num].t=j; 325 | N->e_arr_sin[N->e_sin_num].weight=matVal; 326 | } 327 | } 328 | } 329 | } 330 | 331 | //fill in deg and out deg arrays 332 | for(i=0;i<=N->vertices_num;i++) { 333 | N->indeg[i]=0; 334 | N->outdeg[i]=0; 335 | if(GNRL_ST.calc_self_edges == TRUE) 336 | { 337 | N->self_edge[i]=FALSE; 338 | } 339 | } 340 | for (i=1; i<=N->vertices_num;i++){ 341 | if(N->mat->spr->m[i].to==NULL) 342 | N->outdeg[i]=0; 343 | else 344 | N->outdeg[i]=N->mat->spr->m[i].to->size; 345 | if(N->mat->spr->m[i].from==NULL) 346 | N->indeg[i]=0; 347 | else 348 | N->indeg[i]=N->mat->spr->m[i].from->size; 349 | if((N->mat->spr->m[i].self_edge == 1) && (GNRL_ST.calc_self_edges == TRUE)) 350 | { 351 | N->self_edge[i] = TRUE; 352 | } 353 | } 354 | } 355 | 356 | //statistics and global info about the network 357 | N->con_vertices_num=0; 358 | N->hub_deg=0; 359 | N->hub=0; 360 | N->in_hub_deg=0; 361 | N->in_hub=0; 362 | N->out_hub_deg=0; 363 | N->out_hub=0; 364 | //calc total num of connected vertices 365 | //and find hub preferenced 366 | for(i=1; i<=N->vertices_num;i++){ 367 | if( (N->indeg[i]!=0) || (N->outdeg[i]!=0) ) 368 | N->con_vertices_num++; 369 | if( ((N->indeg[i] + N->outdeg[i]) > N->hub_deg) ){ 370 | N->hub_deg=N->indeg[i] + N->outdeg[i]; 371 | N->hub=i; 372 | } 373 | if( N->indeg[i] > N->in_hub_deg){ 374 | N->in_hub_deg=N->indeg[i]; 375 | N->in_hub=i; 376 | } 377 | if( N->outdeg[i] > N->out_hub_deg){ 378 | N->out_hub_deg=N->outdeg[i]; 379 | N->out_hub=i; 380 | } 381 | } 382 | 383 | //if calc roles then init array or roles vector for all nodes 384 | if(GNRL_ST.calc_roles==TRUE && GNRL_ST.mtf_sz==3) { 385 | if( (N->roles_vec=(char**)calloc(N->vertices_num+1,sizeof(char*))) ==NULL) 386 | return RC_ERR; 387 | for(i=1;i<=N->vertices_num;i++) 388 | if( (N->roles_vec[i]=(char*)calloc(TOTAL_ROLES_3_NUM+1,sizeof(char))) ==NULL) 389 | return RC_ERR; 390 | } 391 | //if use clusterring in random network genereation 392 | if(GNRL_ST.use_clustering){ 393 | N->cluster_degree=(double*)calloc(N->vertices_num+2,sizeof(double)); 394 | for(i=0;i<=N->vertices_num;i++) { 395 | N->cluster_degree[i]=0.0; 396 | } 397 | //fill clustering series 398 | clustering_series(N,NULL); 399 | } 400 | //if efc prob approach then init hub_edges_vec and hub_edges_indices 401 | if(GNRL_ST.efc_prob){ 402 | N->hub_edges_vec=(int*)calloc(N->edges_num+1,sizeof(int)); 403 | N->hub_edges_indices=(int*)calloc(N->hub_deg+1,sizeof(int)); 404 | 405 | //fill hub vector and hub indices 406 | i=0; 407 | for(l_e=list_get_next(N->e_map->spr->m[N->hub].to,NULL);l_e!=NULL; 408 | l_e=list_get_next(N->e_map->spr->m[N->hub].to,l_e)) { 409 | e_idx=*(int*)l_e->p; 410 | N->hub_edges_indices[++i]=e_idx; 411 | N->hub_edges_vec[e_idx]=i; 412 | } 413 | for(l_e=list_get_next(N->e_map->spr->m[N->hub].from,NULL);l_e!=NULL; 414 | l_e=list_get_next(N->e_map->spr->m[N->hub].from,l_e)) { 415 | e_idx=*(int*)l_e->p; 416 | N->hub_edges_indices[++i]=e_idx; 417 | N->hub_edges_vec[e_idx]=i; 418 | } 419 | if(i!=N->hub_deg) 420 | printf("Error in Hub degree\n"); 421 | } 422 | //if conserve layers in random netowrks 423 | if(GNRL_ST.r_conserve_layers==TRUE){ 424 | N->num_of_layers=GNRL_ST.r_layers_num; 425 | N->layer_node_num=(int*)calloc(N->num_of_layers+1,sizeof(int)); 426 | N->layer_edges_num=(int*)calloc(N->num_of_layers+1,sizeof(int)); 427 | //copy num of nodes in each layer 428 | for(i=1;i<=N->num_of_layers;i++) 429 | N->layer_node_num[i]=GNRL_ST.r_layer_sz[i]; 430 | //run through e_arr and fill N->layer_edges_num 431 | //this is required for the randomizing process - in order to swtich edges 432 | //between nodes in the same layers only 433 | max_node=0; 434 | j=1; 435 | for(i=1;i<=N->num_of_layers;i++){ 436 | max_node+=N->layer_node_num[i]; 437 | while( (N->e_arr[j].s<=max_node) && (j<=N->edges_num) ){ 438 | N->layer_edges_num[i]++; 439 | j++; 440 | } 441 | } 442 | //sanity check - that num of edges in layers sum to total num of edges 443 | j=0; 444 | for(i=1;i<=N->num_of_layers;i++) 445 | j+=N->layer_edges_num[i]; 446 | if(j!=N->edges_num){ 447 | printf("\nERROR: in '-rcl' flag, check layers info\n"); 448 | at_exit(-1); 449 | } 450 | } 451 | if(DEBUG_LEVEL>11) 452 | dump_network(stdout,N); 453 | *N_p=N; 454 | return rc; 455 | } 456 | 457 | /******************************************************** 458 | * function : duplicate_network 459 | * Duplicate 460 | * arguments: 461 | * SRC - network source 462 | * TRG - netowrk target 463 | * network_fname - target network name 464 | * 465 | * return values: 466 | * RC_OK - if not error occured 467 | * RC_ERR - if error occured 468 | *********************************************************/ 469 | int 470 | duplicate_network(Network *SRC, Network **TRG_p, char *trg_name) 471 | { 472 | int i,j,rc=RC_OK; 473 | Network *TRG; 474 | list_item *l_e; 475 | TRG=(Network*)calloc(1,sizeof(Network)); 476 | TRG->name=trg_name; 477 | TRG->vertices_num = SRC->vertices_num; 478 | TRG->edges_num = SRC->edges_num; 479 | TRG->e_self_num = SRC->e_self_num; 480 | MatInit(&TRG->mat, TRG->vertices_num,SPARSE); 481 | //FULL: TRG->m = (char*)malloc(TRG->vertices_num*TRG->vertices_num*sizeof(char)); 482 | //init matrix according to input network 483 | if(SRC->mat->type==FULL) { 484 | for (i=1; i<=TRG->vertices_num; i++) 485 | for (j=1; j<=TRG->vertices_num; j++) 486 | MatAsgn(TRG->mat,i,j,MatGet(SRC->mat,i,j)); 487 | } else { 488 | //sparse 489 | for (i=1; i<=TRG->vertices_num; i++) { 490 | for(l_e=list_get_next(SRC->mat->spr->m[i].to,NULL);l_e!=NULL; 491 | l_e=list_get_next(SRC->mat->spr->m[i].to,l_e)) 492 | MatAsgn(TRG->mat,i,l_e->val,*(int*)l_e->p); 493 | TRG->mat->spr->m[i].self_edge = SRC->mat->spr->m[i].self_edge; 494 | } 495 | } 496 | 497 | //copy edge arr from source network 498 | TRG->e_arr=(Edge*)calloc(TRG->edges_num+1,sizeof(Edge)); 499 | 500 | for(i=1;i<=TRG->edges_num;i++) { 501 | TRG->e_arr[i].s=SRC->e_arr[i].s; 502 | TRG->e_arr[i].t=SRC->e_arr[i].t; 503 | TRG->e_arr[i].weight=SRC->e_arr[i].weight; 504 | } 505 | //copy e_arr_sin and e_arr_dup 506 | TRG->e_sin_num=SRC->e_sin_num; 507 | TRG->e_dbl_num=SRC->e_dbl_num; 508 | TRG->e_arr_sin=(Edge*)calloc((unsigned int)TRG->e_sin_num+1,sizeof(Edge)); 509 | TRG->e_arr_dbl=(Edge*)calloc((unsigned int)TRG->e_dbl_num+1,sizeof(Edge)); 510 | 511 | for(i=1;i<=TRG->e_sin_num;i++) { 512 | TRG->e_arr_sin[i].s=SRC->e_arr_sin[i].s; 513 | TRG->e_arr_sin[i].t=SRC->e_arr_sin[i].t; 514 | TRG->e_arr_sin[i].weight=SRC->e_arr_sin[i].weight; 515 | } 516 | for(i=1;i<=TRG->e_dbl_num;i++) { 517 | TRG->e_arr_dbl[i].s=SRC->e_arr_dbl[i].s; 518 | TRG->e_arr_dbl[i].t=SRC->e_arr_dbl[i].t; 519 | TRG->e_arr_dbl[i].weight=SRC->e_arr_dbl[i].weight; 520 | } 521 | 522 | //copy e_arr_self 523 | TRG->e_arr_self=(Edge*)calloc(TRG->e_self_num+1,sizeof(Edge)); 524 | for(i=1;i<=TRG->e_self_num;i++) { 525 | TRG->e_arr_self[i].s=SRC->e_arr_self[i].s; 526 | TRG->e_arr_self[i].t=SRC->e_arr_self[i].t; 527 | TRG->e_arr_self[i].weight=SRC->e_arr_self[i].weight; 528 | } 529 | 530 | TRG->indeg=(int*)calloc((unsigned int)TRG->vertices_num+2,sizeof(int)); 531 | TRG->outdeg=(int*)calloc((unsigned int)TRG->vertices_num+2,sizeof(int)); 532 | TRG->doubledeg=(int*)calloc((unsigned int)TRG->vertices_num+2,sizeof(int)); 533 | for(i=1;i<=TRG->vertices_num+1;i++) { 534 | TRG->indeg[i]=SRC->indeg[i]; 535 | TRG->outdeg[i]=SRC->outdeg[i]; 536 | TRG->doubledeg[i]=SRC->doubledeg[i]; 537 | } 538 | if(GNRL_ST.use_clustering){ 539 | TRG->cluster_degree=(double*)calloc(TRG->vertices_num+2,sizeof(double)); 540 | for(i=1;i<=TRG->vertices_num+1;i++) { 541 | TRG->cluster_degree[i]=SRC->cluster_degree[i]; 542 | } 543 | } 544 | 545 | //if calc roles then init array or roles vector for all nodes 546 | if(GNRL_ST.calc_roles==TRUE && GNRL_ST.mtf_sz==3) { 547 | if( (TRG->roles_vec=(char**)calloc(TRG->vertices_num+1,sizeof(char*))) ==NULL) 548 | return RC_ERR; 549 | for(i=1;i<=TRG->vertices_num;i++) 550 | if( (TRG->roles_vec[i]=(char*)calloc(TOTAL_ROLES_3_NUM+1,sizeof(char))) ==NULL) 551 | return RC_ERR; 552 | } 553 | 554 | //copy hub params 555 | TRG->con_vertices_num=SRC->con_vertices_num; 556 | TRG->hub_deg=SRC->hub_deg; 557 | TRG->hub=SRC->hub; 558 | if(GNRL_ST.efc_prob){ 559 | rc |= MatInit(&TRG->e_map,TRG->vertices_num,SPARSE); 560 | for(i=1; i<=TRG->edges_num; i++) 561 | MatAsgn(TRG->e_map,TRG->e_arr[i].s,TRG->e_arr[i].t,i); 562 | 563 | //if efc prob approach then allocate hub_edges_vec and hub_edges_indices 564 | TRG->hub_edges_vec=(int*)calloc(TRG->edges_num+1,sizeof(int)); 565 | TRG->hub_edges_indices=(int*)calloc(TRG->hub_deg+1,sizeof(int)); 566 | memcpy(TRG->hub_edges_vec,SRC->hub_edges_vec,(TRG->edges_num+1)*sizeof(int)); 567 | memcpy(TRG->hub_edges_indices,SRC->hub_edges_indices,(TRG->hub_deg+1)*sizeof(int)); 568 | 569 | } 570 | 571 | //if conserve layers mode then copy layers info 572 | if(GNRL_ST.r_conserve_layers==TRUE){ 573 | TRG->num_of_layers=SRC->num_of_layers; 574 | TRG->layers_range=SRC->layers_range; 575 | 576 | TRG->layer_node_num=(int*)calloc(TRG->num_of_layers+1,sizeof(int)); 577 | TRG->layer_edges_num=(int*)calloc(TRG->num_of_layers+1,sizeof(int)); 578 | for(i=1;i<=TRG->num_of_layers;i++){ 579 | TRG->layer_node_num[i]=SRC->layer_node_num[i]; 580 | TRG->layer_edges_num[i]=SRC->layer_edges_num[i]; 581 | } 582 | } 583 | 584 | //dump_network(TRG); 585 | *TRG_p=TRG; 586 | return RC_OK; 587 | } 588 | 589 | -------------------------------------------------------------------------------- /pymfinder/mfinder/grassberger.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/grassberger.c -------------------------------------------------------------------------------- /pymfinder/mfinder/grassberger.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/grassberger.h -------------------------------------------------------------------------------- /pymfinder/mfinder/hash.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/hash.c -------------------------------------------------------------------------------- /pymfinder/mfinder/hash.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/hash.h -------------------------------------------------------------------------------- /pymfinder/mfinder/list.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/list.c -------------------------------------------------------------------------------- /pymfinder/mfinder/list.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/list.h -------------------------------------------------------------------------------- /pymfinder/mfinder/main.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/main.c -------------------------------------------------------------------------------- /pymfinder/mfinder/mat.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/mat.c -------------------------------------------------------------------------------- /pymfinder/mfinder/mat.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/mat.h -------------------------------------------------------------------------------- /pymfinder/mfinder/metropolis.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/metropolis.c -------------------------------------------------------------------------------- /pymfinder/mfinder/metropolis.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/metropolis.h -------------------------------------------------------------------------------- /pymfinder/mfinder/mfinder-manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/mfinder-manual.pdf -------------------------------------------------------------------------------- /pymfinder/mfinder/mfinder-motif-dictionary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/mfinder-motif-dictionary.pdf -------------------------------------------------------------------------------- /pymfinder/mfinder/mfinder.i: -------------------------------------------------------------------------------- 1 | /* mfinder.i */ 2 | 3 | /******************************* SWIGS **********************************/ 4 | 5 | %include 6 | %array_class(int, intArray); 7 | 8 | %module mfinder 9 | %{ 10 | #include "common.h" 11 | #include "wrapper.h" 12 | extern list64* list_motifs(int mtf_sz); 13 | extern list* motif_edges(int64 id, int mtf_sz); 14 | extern list* random_network(mfinder_input mfinderi); 15 | extern list64* motif_structure(mfinder_input mfinderi); 16 | extern list64* motif_participation(mfinder_input mfinderi); 17 | %} 18 | 19 | /******************************* Externs ********************************/ 20 | 21 | extern list64* list_motifs(int mtf_sz); 22 | extern list* motif_edges(int64 id, int mtf_sz); 23 | extern list* random_network(mfinder_input mfinderi); 24 | extern list64* motif_structure(mfinder_input mfinderi); 25 | extern list64* motif_participation(mfinder_input mfinderi); 26 | 27 | extern void list_free_mem(list64 *L); 28 | extern void list64_free_mem(list64 *L); 29 | extern void res_tbl_mem_free_single(list64 *L); 30 | 31 | /************************ Stouffer Typedefs *******************************/ 32 | 33 | typedef struct { 34 | char* Filename; 35 | int* Edges; 36 | unsigned int NumEdges; 37 | unsigned int MotifSize; 38 | int NRandomizations; 39 | int MaxMembersListSz; 40 | int Randomize; 41 | int UseMetropolis; 42 | } mfinder_input; 43 | 44 | /******************************* Typedefs *******************************/ 45 | 46 | typedef long long int64; 47 | 48 | typedef struct _list_item{ 49 | int val; 50 | void *p; 51 | struct _list_item *next; 52 | } list_item; 53 | 54 | typedef struct{ 55 | int size; 56 | list_item *l; 57 | } list; 58 | 59 | typedef struct _list64_item{ 60 | int64 val; 61 | void *p; 62 | struct _list64_item *next; 63 | } list64_item; 64 | 65 | typedef struct{ 66 | int size; 67 | list64_item *l; 68 | } list64; 69 | 70 | // Statistics results about each subgraph 71 | typedef struct { 72 | int64 id; 73 | int size; 74 | double real_count; 75 | double real_pval; 76 | double real_zscore; 77 | int hits_num; 78 | double conc_real; 79 | double conc_real_pval; 80 | double conc_real_zscore; 81 | //Neff_st *eff_arr; 82 | int64 unique_appear; 83 | double rand_mean; 84 | double rand_std_dev; 85 | double conc_rand_mean; 86 | double conc_rand_std_dev; 87 | list *all_members; 88 | int *all_rand_counts; 89 | double conv_grade; 90 | int dangling; 91 | } Motif_res; 92 | 93 | //Member info structure 94 | typedef struct { 95 | int node; 96 | unsigned char role; 97 | } Member; 98 | 99 | //Motif info (Subgraph info) structure 100 | typedef struct { 101 | int64 id; 102 | double count; 103 | double prob_count; 104 | double conc; 105 | int hits; 106 | list *members; 107 | list *all_members; 108 | int numberOfSelfEdges; 109 | double conv_grade; 110 | } Motif; 111 | 112 | // Edge structure 113 | typedef struct { 114 | int s; 115 | int t; 116 | int weight; 117 | } Edge; 118 | 119 | /******************************* Functions *******************************/ 120 | 121 | %inline %{ 122 | Edge* get_edge(void* p){ 123 | return (Edge*) p; 124 | } 125 | 126 | Motif_res* get_motif_result(void* p){ 127 | return (Motif_res*) p; 128 | } 129 | 130 | Motif* get_motif(void* p){ 131 | return (Motif*) p; 132 | } 133 | 134 | void get_motif_members(void* p,int* vals,int mtf_sz){ 135 | unsigned int i; 136 | Member* members = (Member*) p; 137 | for(i=0;i= (2,6,0): 11 | def swig_import_helper(): 12 | from os.path import dirname 13 | import imp 14 | fp = None 15 | try: 16 | fp, pathname, description = imp.find_module('_mfinder', [dirname(__file__)]) 17 | except ImportError: 18 | import _mfinder 19 | return _mfinder 20 | if fp is not None: 21 | try: 22 | _mod = imp.load_module('_mfinder', fp, pathname, description) 23 | finally: 24 | fp.close() 25 | return _mod 26 | _mfinder = swig_import_helper() 27 | del swig_import_helper 28 | else: 29 | import _mfinder 30 | del version_info 31 | try: 32 | _swig_property = property 33 | except NameError: 34 | pass # Python < 2.2 doesn't have 'property'. 35 | def _swig_setattr_nondynamic(self,class_type,name,value,static=1): 36 | if (name == "thisown"): return self.this.own(value) 37 | if (name == "this"): 38 | if type(value).__name__ == 'SwigPyObject': 39 | self.__dict__[name] = value 40 | return 41 | method = class_type.__swig_setmethods__.get(name,None) 42 | if method: return method(self,value) 43 | if (not static): 44 | self.__dict__[name] = value 45 | else: 46 | raise AttributeError("You cannot add attributes to %s" % self) 47 | 48 | def _swig_setattr(self,class_type,name,value): 49 | return _swig_setattr_nondynamic(self,class_type,name,value,0) 50 | 51 | def _swig_getattr(self,class_type,name): 52 | if (name == "thisown"): return self.this.own() 53 | method = class_type.__swig_getmethods__.get(name,None) 54 | if method: return method(self) 55 | raise AttributeError(name) 56 | 57 | def _swig_repr(self): 58 | try: strthis = "proxy of " + self.this.__repr__() 59 | except: strthis = "" 60 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 61 | 62 | try: 63 | _object = object 64 | _newclass = 1 65 | except AttributeError: 66 | class _object : pass 67 | _newclass = 0 68 | 69 | 70 | class intArray(_object): 71 | __swig_setmethods__ = {} 72 | __setattr__ = lambda self, name, value: _swig_setattr(self, intArray, name, value) 73 | __swig_getmethods__ = {} 74 | __getattr__ = lambda self, name: _swig_getattr(self, intArray, name) 75 | __repr__ = _swig_repr 76 | def __init__(self, *args): 77 | this = _mfinder.new_intArray(*args) 78 | try: self.this.append(this) 79 | except: self.this = this 80 | __swig_destroy__ = _mfinder.delete_intArray 81 | __del__ = lambda self : None; 82 | def __getitem__(self, *args): return _mfinder.intArray___getitem__(self, *args) 83 | def __setitem__(self, *args): return _mfinder.intArray___setitem__(self, *args) 84 | def cast(self): return _mfinder.intArray_cast(self) 85 | __swig_getmethods__["frompointer"] = lambda x: _mfinder.intArray_frompointer 86 | if _newclass:frompointer = staticmethod(_mfinder.intArray_frompointer) 87 | intArray_swigregister = _mfinder.intArray_swigregister 88 | intArray_swigregister(intArray) 89 | 90 | def intArray_frompointer(*args): 91 | return _mfinder.intArray_frompointer(*args) 92 | intArray_frompointer = _mfinder.intArray_frompointer 93 | 94 | 95 | def list_motifs(*args): 96 | return _mfinder.list_motifs(*args) 97 | list_motifs = _mfinder.list_motifs 98 | 99 | def motif_edges(*args): 100 | return _mfinder.motif_edges(*args) 101 | motif_edges = _mfinder.motif_edges 102 | 103 | def random_network(*args): 104 | return _mfinder.random_network(*args) 105 | random_network = _mfinder.random_network 106 | 107 | def motif_structure(*args): 108 | return _mfinder.motif_structure(*args) 109 | motif_structure = _mfinder.motif_structure 110 | 111 | def motif_participation(*args): 112 | return _mfinder.motif_participation(*args) 113 | motif_participation = _mfinder.motif_participation 114 | 115 | def list_free_mem(*args): 116 | return _mfinder.list_free_mem(*args) 117 | list_free_mem = _mfinder.list_free_mem 118 | 119 | def list64_free_mem(*args): 120 | return _mfinder.list64_free_mem(*args) 121 | list64_free_mem = _mfinder.list64_free_mem 122 | 123 | def res_tbl_mem_free_single(*args): 124 | return _mfinder.res_tbl_mem_free_single(*args) 125 | res_tbl_mem_free_single = _mfinder.res_tbl_mem_free_single 126 | class mfinder_input(_object): 127 | __swig_setmethods__ = {} 128 | __setattr__ = lambda self, name, value: _swig_setattr(self, mfinder_input, name, value) 129 | __swig_getmethods__ = {} 130 | __getattr__ = lambda self, name: _swig_getattr(self, mfinder_input, name) 131 | __repr__ = _swig_repr 132 | __swig_setmethods__["Filename"] = _mfinder.mfinder_input_Filename_set 133 | __swig_getmethods__["Filename"] = _mfinder.mfinder_input_Filename_get 134 | if _newclass:Filename = _swig_property(_mfinder.mfinder_input_Filename_get, _mfinder.mfinder_input_Filename_set) 135 | __swig_setmethods__["Edges"] = _mfinder.mfinder_input_Edges_set 136 | __swig_getmethods__["Edges"] = _mfinder.mfinder_input_Edges_get 137 | if _newclass:Edges = _swig_property(_mfinder.mfinder_input_Edges_get, _mfinder.mfinder_input_Edges_set) 138 | __swig_setmethods__["NumEdges"] = _mfinder.mfinder_input_NumEdges_set 139 | __swig_getmethods__["NumEdges"] = _mfinder.mfinder_input_NumEdges_get 140 | if _newclass:NumEdges = _swig_property(_mfinder.mfinder_input_NumEdges_get, _mfinder.mfinder_input_NumEdges_set) 141 | __swig_setmethods__["MotifSize"] = _mfinder.mfinder_input_MotifSize_set 142 | __swig_getmethods__["MotifSize"] = _mfinder.mfinder_input_MotifSize_get 143 | if _newclass:MotifSize = _swig_property(_mfinder.mfinder_input_MotifSize_get, _mfinder.mfinder_input_MotifSize_set) 144 | __swig_setmethods__["NRandomizations"] = _mfinder.mfinder_input_NRandomizations_set 145 | __swig_getmethods__["NRandomizations"] = _mfinder.mfinder_input_NRandomizations_get 146 | if _newclass:NRandomizations = _swig_property(_mfinder.mfinder_input_NRandomizations_get, _mfinder.mfinder_input_NRandomizations_set) 147 | __swig_setmethods__["MaxMembersListSz"] = _mfinder.mfinder_input_MaxMembersListSz_set 148 | __swig_getmethods__["MaxMembersListSz"] = _mfinder.mfinder_input_MaxMembersListSz_get 149 | if _newclass:MaxMembersListSz = _swig_property(_mfinder.mfinder_input_MaxMembersListSz_get, _mfinder.mfinder_input_MaxMembersListSz_set) 150 | __swig_setmethods__["Randomize"] = _mfinder.mfinder_input_Randomize_set 151 | __swig_getmethods__["Randomize"] = _mfinder.mfinder_input_Randomize_get 152 | if _newclass:Randomize = _swig_property(_mfinder.mfinder_input_Randomize_get, _mfinder.mfinder_input_Randomize_set) 153 | __swig_setmethods__["UseMetropolis"] = _mfinder.mfinder_input_UseMetropolis_set 154 | __swig_getmethods__["UseMetropolis"] = _mfinder.mfinder_input_UseMetropolis_get 155 | if _newclass:UseMetropolis = _swig_property(_mfinder.mfinder_input_UseMetropolis_get, _mfinder.mfinder_input_UseMetropolis_set) 156 | def __init__(self): 157 | this = _mfinder.new_mfinder_input() 158 | try: self.this.append(this) 159 | except: self.this = this 160 | __swig_destroy__ = _mfinder.delete_mfinder_input 161 | __del__ = lambda self : None; 162 | mfinder_input_swigregister = _mfinder.mfinder_input_swigregister 163 | mfinder_input_swigregister(mfinder_input) 164 | 165 | class list_item(_object): 166 | __swig_setmethods__ = {} 167 | __setattr__ = lambda self, name, value: _swig_setattr(self, list_item, name, value) 168 | __swig_getmethods__ = {} 169 | __getattr__ = lambda self, name: _swig_getattr(self, list_item, name) 170 | __repr__ = _swig_repr 171 | __swig_setmethods__["val"] = _mfinder.list_item_val_set 172 | __swig_getmethods__["val"] = _mfinder.list_item_val_get 173 | if _newclass:val = _swig_property(_mfinder.list_item_val_get, _mfinder.list_item_val_set) 174 | __swig_setmethods__["p"] = _mfinder.list_item_p_set 175 | __swig_getmethods__["p"] = _mfinder.list_item_p_get 176 | if _newclass:p = _swig_property(_mfinder.list_item_p_get, _mfinder.list_item_p_set) 177 | __swig_setmethods__["next"] = _mfinder.list_item_next_set 178 | __swig_getmethods__["next"] = _mfinder.list_item_next_get 179 | if _newclass:next = _swig_property(_mfinder.list_item_next_get, _mfinder.list_item_next_set) 180 | def __init__(self): 181 | this = _mfinder.new_list_item() 182 | try: self.this.append(this) 183 | except: self.this = this 184 | __swig_destroy__ = _mfinder.delete_list_item 185 | __del__ = lambda self : None; 186 | list_item_swigregister = _mfinder.list_item_swigregister 187 | list_item_swigregister(list_item) 188 | 189 | class list(_object): 190 | __swig_setmethods__ = {} 191 | __setattr__ = lambda self, name, value: _swig_setattr(self, list, name, value) 192 | __swig_getmethods__ = {} 193 | __getattr__ = lambda self, name: _swig_getattr(self, list, name) 194 | __repr__ = _swig_repr 195 | __swig_setmethods__["size"] = _mfinder.list_size_set 196 | __swig_getmethods__["size"] = _mfinder.list_size_get 197 | if _newclass:size = _swig_property(_mfinder.list_size_get, _mfinder.list_size_set) 198 | __swig_setmethods__["l"] = _mfinder.list_l_set 199 | __swig_getmethods__["l"] = _mfinder.list_l_get 200 | if _newclass:l = _swig_property(_mfinder.list_l_get, _mfinder.list_l_set) 201 | def __init__(self): 202 | this = _mfinder.new_list() 203 | try: self.this.append(this) 204 | except: self.this = this 205 | __swig_destroy__ = _mfinder.delete_list 206 | __del__ = lambda self : None; 207 | list_swigregister = _mfinder.list_swigregister 208 | list_swigregister(list) 209 | 210 | class list64_item(_object): 211 | __swig_setmethods__ = {} 212 | __setattr__ = lambda self, name, value: _swig_setattr(self, list64_item, name, value) 213 | __swig_getmethods__ = {} 214 | __getattr__ = lambda self, name: _swig_getattr(self, list64_item, name) 215 | __repr__ = _swig_repr 216 | __swig_setmethods__["val"] = _mfinder.list64_item_val_set 217 | __swig_getmethods__["val"] = _mfinder.list64_item_val_get 218 | if _newclass:val = _swig_property(_mfinder.list64_item_val_get, _mfinder.list64_item_val_set) 219 | __swig_setmethods__["p"] = _mfinder.list64_item_p_set 220 | __swig_getmethods__["p"] = _mfinder.list64_item_p_get 221 | if _newclass:p = _swig_property(_mfinder.list64_item_p_get, _mfinder.list64_item_p_set) 222 | __swig_setmethods__["next"] = _mfinder.list64_item_next_set 223 | __swig_getmethods__["next"] = _mfinder.list64_item_next_get 224 | if _newclass:next = _swig_property(_mfinder.list64_item_next_get, _mfinder.list64_item_next_set) 225 | def __init__(self): 226 | this = _mfinder.new_list64_item() 227 | try: self.this.append(this) 228 | except: self.this = this 229 | __swig_destroy__ = _mfinder.delete_list64_item 230 | __del__ = lambda self : None; 231 | list64_item_swigregister = _mfinder.list64_item_swigregister 232 | list64_item_swigregister(list64_item) 233 | 234 | class list64(_object): 235 | __swig_setmethods__ = {} 236 | __setattr__ = lambda self, name, value: _swig_setattr(self, list64, name, value) 237 | __swig_getmethods__ = {} 238 | __getattr__ = lambda self, name: _swig_getattr(self, list64, name) 239 | __repr__ = _swig_repr 240 | __swig_setmethods__["size"] = _mfinder.list64_size_set 241 | __swig_getmethods__["size"] = _mfinder.list64_size_get 242 | if _newclass:size = _swig_property(_mfinder.list64_size_get, _mfinder.list64_size_set) 243 | __swig_setmethods__["l"] = _mfinder.list64_l_set 244 | __swig_getmethods__["l"] = _mfinder.list64_l_get 245 | if _newclass:l = _swig_property(_mfinder.list64_l_get, _mfinder.list64_l_set) 246 | def __init__(self): 247 | this = _mfinder.new_list64() 248 | try: self.this.append(this) 249 | except: self.this = this 250 | __swig_destroy__ = _mfinder.delete_list64 251 | __del__ = lambda self : None; 252 | list64_swigregister = _mfinder.list64_swigregister 253 | list64_swigregister(list64) 254 | 255 | class Motif_res(_object): 256 | __swig_setmethods__ = {} 257 | __setattr__ = lambda self, name, value: _swig_setattr(self, Motif_res, name, value) 258 | __swig_getmethods__ = {} 259 | __getattr__ = lambda self, name: _swig_getattr(self, Motif_res, name) 260 | __repr__ = _swig_repr 261 | __swig_setmethods__["id"] = _mfinder.Motif_res_id_set 262 | __swig_getmethods__["id"] = _mfinder.Motif_res_id_get 263 | if _newclass:id = _swig_property(_mfinder.Motif_res_id_get, _mfinder.Motif_res_id_set) 264 | __swig_setmethods__["size"] = _mfinder.Motif_res_size_set 265 | __swig_getmethods__["size"] = _mfinder.Motif_res_size_get 266 | if _newclass:size = _swig_property(_mfinder.Motif_res_size_get, _mfinder.Motif_res_size_set) 267 | __swig_setmethods__["real_count"] = _mfinder.Motif_res_real_count_set 268 | __swig_getmethods__["real_count"] = _mfinder.Motif_res_real_count_get 269 | if _newclass:real_count = _swig_property(_mfinder.Motif_res_real_count_get, _mfinder.Motif_res_real_count_set) 270 | __swig_setmethods__["real_pval"] = _mfinder.Motif_res_real_pval_set 271 | __swig_getmethods__["real_pval"] = _mfinder.Motif_res_real_pval_get 272 | if _newclass:real_pval = _swig_property(_mfinder.Motif_res_real_pval_get, _mfinder.Motif_res_real_pval_set) 273 | __swig_setmethods__["real_zscore"] = _mfinder.Motif_res_real_zscore_set 274 | __swig_getmethods__["real_zscore"] = _mfinder.Motif_res_real_zscore_get 275 | if _newclass:real_zscore = _swig_property(_mfinder.Motif_res_real_zscore_get, _mfinder.Motif_res_real_zscore_set) 276 | __swig_setmethods__["hits_num"] = _mfinder.Motif_res_hits_num_set 277 | __swig_getmethods__["hits_num"] = _mfinder.Motif_res_hits_num_get 278 | if _newclass:hits_num = _swig_property(_mfinder.Motif_res_hits_num_get, _mfinder.Motif_res_hits_num_set) 279 | __swig_setmethods__["conc_real"] = _mfinder.Motif_res_conc_real_set 280 | __swig_getmethods__["conc_real"] = _mfinder.Motif_res_conc_real_get 281 | if _newclass:conc_real = _swig_property(_mfinder.Motif_res_conc_real_get, _mfinder.Motif_res_conc_real_set) 282 | __swig_setmethods__["conc_real_pval"] = _mfinder.Motif_res_conc_real_pval_set 283 | __swig_getmethods__["conc_real_pval"] = _mfinder.Motif_res_conc_real_pval_get 284 | if _newclass:conc_real_pval = _swig_property(_mfinder.Motif_res_conc_real_pval_get, _mfinder.Motif_res_conc_real_pval_set) 285 | __swig_setmethods__["conc_real_zscore"] = _mfinder.Motif_res_conc_real_zscore_set 286 | __swig_getmethods__["conc_real_zscore"] = _mfinder.Motif_res_conc_real_zscore_get 287 | if _newclass:conc_real_zscore = _swig_property(_mfinder.Motif_res_conc_real_zscore_get, _mfinder.Motif_res_conc_real_zscore_set) 288 | __swig_setmethods__["unique_appear"] = _mfinder.Motif_res_unique_appear_set 289 | __swig_getmethods__["unique_appear"] = _mfinder.Motif_res_unique_appear_get 290 | if _newclass:unique_appear = _swig_property(_mfinder.Motif_res_unique_appear_get, _mfinder.Motif_res_unique_appear_set) 291 | __swig_setmethods__["rand_mean"] = _mfinder.Motif_res_rand_mean_set 292 | __swig_getmethods__["rand_mean"] = _mfinder.Motif_res_rand_mean_get 293 | if _newclass:rand_mean = _swig_property(_mfinder.Motif_res_rand_mean_get, _mfinder.Motif_res_rand_mean_set) 294 | __swig_setmethods__["rand_std_dev"] = _mfinder.Motif_res_rand_std_dev_set 295 | __swig_getmethods__["rand_std_dev"] = _mfinder.Motif_res_rand_std_dev_get 296 | if _newclass:rand_std_dev = _swig_property(_mfinder.Motif_res_rand_std_dev_get, _mfinder.Motif_res_rand_std_dev_set) 297 | __swig_setmethods__["conc_rand_mean"] = _mfinder.Motif_res_conc_rand_mean_set 298 | __swig_getmethods__["conc_rand_mean"] = _mfinder.Motif_res_conc_rand_mean_get 299 | if _newclass:conc_rand_mean = _swig_property(_mfinder.Motif_res_conc_rand_mean_get, _mfinder.Motif_res_conc_rand_mean_set) 300 | __swig_setmethods__["conc_rand_std_dev"] = _mfinder.Motif_res_conc_rand_std_dev_set 301 | __swig_getmethods__["conc_rand_std_dev"] = _mfinder.Motif_res_conc_rand_std_dev_get 302 | if _newclass:conc_rand_std_dev = _swig_property(_mfinder.Motif_res_conc_rand_std_dev_get, _mfinder.Motif_res_conc_rand_std_dev_set) 303 | __swig_setmethods__["all_members"] = _mfinder.Motif_res_all_members_set 304 | __swig_getmethods__["all_members"] = _mfinder.Motif_res_all_members_get 305 | if _newclass:all_members = _swig_property(_mfinder.Motif_res_all_members_get, _mfinder.Motif_res_all_members_set) 306 | __swig_setmethods__["all_rand_counts"] = _mfinder.Motif_res_all_rand_counts_set 307 | __swig_getmethods__["all_rand_counts"] = _mfinder.Motif_res_all_rand_counts_get 308 | if _newclass:all_rand_counts = _swig_property(_mfinder.Motif_res_all_rand_counts_get, _mfinder.Motif_res_all_rand_counts_set) 309 | __swig_setmethods__["conv_grade"] = _mfinder.Motif_res_conv_grade_set 310 | __swig_getmethods__["conv_grade"] = _mfinder.Motif_res_conv_grade_get 311 | if _newclass:conv_grade = _swig_property(_mfinder.Motif_res_conv_grade_get, _mfinder.Motif_res_conv_grade_set) 312 | __swig_setmethods__["dangling"] = _mfinder.Motif_res_dangling_set 313 | __swig_getmethods__["dangling"] = _mfinder.Motif_res_dangling_get 314 | if _newclass:dangling = _swig_property(_mfinder.Motif_res_dangling_get, _mfinder.Motif_res_dangling_set) 315 | def __init__(self): 316 | this = _mfinder.new_Motif_res() 317 | try: self.this.append(this) 318 | except: self.this = this 319 | __swig_destroy__ = _mfinder.delete_Motif_res 320 | __del__ = lambda self : None; 321 | Motif_res_swigregister = _mfinder.Motif_res_swigregister 322 | Motif_res_swigregister(Motif_res) 323 | 324 | class Member(_object): 325 | __swig_setmethods__ = {} 326 | __setattr__ = lambda self, name, value: _swig_setattr(self, Member, name, value) 327 | __swig_getmethods__ = {} 328 | __getattr__ = lambda self, name: _swig_getattr(self, Member, name) 329 | __repr__ = _swig_repr 330 | __swig_setmethods__["node"] = _mfinder.Member_node_set 331 | __swig_getmethods__["node"] = _mfinder.Member_node_get 332 | if _newclass:node = _swig_property(_mfinder.Member_node_get, _mfinder.Member_node_set) 333 | __swig_setmethods__["role"] = _mfinder.Member_role_set 334 | __swig_getmethods__["role"] = _mfinder.Member_role_get 335 | if _newclass:role = _swig_property(_mfinder.Member_role_get, _mfinder.Member_role_set) 336 | def __init__(self): 337 | this = _mfinder.new_Member() 338 | try: self.this.append(this) 339 | except: self.this = this 340 | __swig_destroy__ = _mfinder.delete_Member 341 | __del__ = lambda self : None; 342 | Member_swigregister = _mfinder.Member_swigregister 343 | Member_swigregister(Member) 344 | 345 | class Motif(_object): 346 | __swig_setmethods__ = {} 347 | __setattr__ = lambda self, name, value: _swig_setattr(self, Motif, name, value) 348 | __swig_getmethods__ = {} 349 | __getattr__ = lambda self, name: _swig_getattr(self, Motif, name) 350 | __repr__ = _swig_repr 351 | __swig_setmethods__["id"] = _mfinder.Motif_id_set 352 | __swig_getmethods__["id"] = _mfinder.Motif_id_get 353 | if _newclass:id = _swig_property(_mfinder.Motif_id_get, _mfinder.Motif_id_set) 354 | __swig_setmethods__["count"] = _mfinder.Motif_count_set 355 | __swig_getmethods__["count"] = _mfinder.Motif_count_get 356 | if _newclass:count = _swig_property(_mfinder.Motif_count_get, _mfinder.Motif_count_set) 357 | __swig_setmethods__["prob_count"] = _mfinder.Motif_prob_count_set 358 | __swig_getmethods__["prob_count"] = _mfinder.Motif_prob_count_get 359 | if _newclass:prob_count = _swig_property(_mfinder.Motif_prob_count_get, _mfinder.Motif_prob_count_set) 360 | __swig_setmethods__["conc"] = _mfinder.Motif_conc_set 361 | __swig_getmethods__["conc"] = _mfinder.Motif_conc_get 362 | if _newclass:conc = _swig_property(_mfinder.Motif_conc_get, _mfinder.Motif_conc_set) 363 | __swig_setmethods__["hits"] = _mfinder.Motif_hits_set 364 | __swig_getmethods__["hits"] = _mfinder.Motif_hits_get 365 | if _newclass:hits = _swig_property(_mfinder.Motif_hits_get, _mfinder.Motif_hits_set) 366 | __swig_setmethods__["members"] = _mfinder.Motif_members_set 367 | __swig_getmethods__["members"] = _mfinder.Motif_members_get 368 | if _newclass:members = _swig_property(_mfinder.Motif_members_get, _mfinder.Motif_members_set) 369 | __swig_setmethods__["all_members"] = _mfinder.Motif_all_members_set 370 | __swig_getmethods__["all_members"] = _mfinder.Motif_all_members_get 371 | if _newclass:all_members = _swig_property(_mfinder.Motif_all_members_get, _mfinder.Motif_all_members_set) 372 | __swig_setmethods__["numberOfSelfEdges"] = _mfinder.Motif_numberOfSelfEdges_set 373 | __swig_getmethods__["numberOfSelfEdges"] = _mfinder.Motif_numberOfSelfEdges_get 374 | if _newclass:numberOfSelfEdges = _swig_property(_mfinder.Motif_numberOfSelfEdges_get, _mfinder.Motif_numberOfSelfEdges_set) 375 | __swig_setmethods__["conv_grade"] = _mfinder.Motif_conv_grade_set 376 | __swig_getmethods__["conv_grade"] = _mfinder.Motif_conv_grade_get 377 | if _newclass:conv_grade = _swig_property(_mfinder.Motif_conv_grade_get, _mfinder.Motif_conv_grade_set) 378 | def __init__(self): 379 | this = _mfinder.new_Motif() 380 | try: self.this.append(this) 381 | except: self.this = this 382 | __swig_destroy__ = _mfinder.delete_Motif 383 | __del__ = lambda self : None; 384 | Motif_swigregister = _mfinder.Motif_swigregister 385 | Motif_swigregister(Motif) 386 | 387 | class Edge(_object): 388 | __swig_setmethods__ = {} 389 | __setattr__ = lambda self, name, value: _swig_setattr(self, Edge, name, value) 390 | __swig_getmethods__ = {} 391 | __getattr__ = lambda self, name: _swig_getattr(self, Edge, name) 392 | __repr__ = _swig_repr 393 | __swig_setmethods__["s"] = _mfinder.Edge_s_set 394 | __swig_getmethods__["s"] = _mfinder.Edge_s_get 395 | if _newclass:s = _swig_property(_mfinder.Edge_s_get, _mfinder.Edge_s_set) 396 | __swig_setmethods__["t"] = _mfinder.Edge_t_set 397 | __swig_getmethods__["t"] = _mfinder.Edge_t_get 398 | if _newclass:t = _swig_property(_mfinder.Edge_t_get, _mfinder.Edge_t_set) 399 | __swig_setmethods__["weight"] = _mfinder.Edge_weight_set 400 | __swig_getmethods__["weight"] = _mfinder.Edge_weight_get 401 | if _newclass:weight = _swig_property(_mfinder.Edge_weight_get, _mfinder.Edge_weight_set) 402 | def __init__(self): 403 | this = _mfinder.new_Edge() 404 | try: self.this.append(this) 405 | except: self.this = this 406 | __swig_destroy__ = _mfinder.delete_Edge 407 | __del__ = lambda self : None; 408 | Edge_swigregister = _mfinder.Edge_swigregister 409 | Edge_swigregister(Edge) 410 | 411 | 412 | def get_edge(*args): 413 | return _mfinder.get_edge(*args) 414 | get_edge = _mfinder.get_edge 415 | 416 | def get_motif_result(*args): 417 | return _mfinder.get_motif_result(*args) 418 | get_motif_result = _mfinder.get_motif_result 419 | 420 | def get_motif(*args): 421 | return _mfinder.get_motif(*args) 422 | get_motif = _mfinder.get_motif 423 | 424 | def get_motif_members(*args): 425 | return _mfinder.get_motif_members(*args) 426 | get_motif_members = _mfinder.get_motif_members 427 | # This file is compatible with both classic and new-style classes. 428 | 429 | 430 | -------------------------------------------------------------------------------- /pymfinder/mfinder/motif_ids.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/motif_ids.c -------------------------------------------------------------------------------- /pymfinder/mfinder/motif_ids.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/motif_ids.h -------------------------------------------------------------------------------- /pymfinder/mfinder/output.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/output.c -------------------------------------------------------------------------------- /pymfinder/mfinder/output.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/output.h -------------------------------------------------------------------------------- /pymfinder/mfinder/permutation.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/permutation.c -------------------------------------------------------------------------------- /pymfinder/mfinder/prob.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/prob.c -------------------------------------------------------------------------------- /pymfinder/mfinder/prob.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/prob.h -------------------------------------------------------------------------------- /pymfinder/mfinder/random.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/random.c -------------------------------------------------------------------------------- /pymfinder/mfinder/random.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/random.h -------------------------------------------------------------------------------- /pymfinder/mfinder/results.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/results.c -------------------------------------------------------------------------------- /pymfinder/mfinder/results.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/results.h -------------------------------------------------------------------------------- /pymfinder/mfinder/role.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/role.c -------------------------------------------------------------------------------- /pymfinder/mfinder/role.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/role.h -------------------------------------------------------------------------------- /pymfinder/mfinder/stubs.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/stubs.c -------------------------------------------------------------------------------- /pymfinder/mfinder/stubs.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/stubs.h -------------------------------------------------------------------------------- /pymfinder/mfinder/switches.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/switches.c -------------------------------------------------------------------------------- /pymfinder/mfinder/switches.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/pymfinder/mfinder/switches.h -------------------------------------------------------------------------------- /pymfinder/mfinder/wrapper.c: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | * 3 | * 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | *************************************************************************/ 11 | 12 | #include "globals.h" 13 | #include "mat.h" 14 | #include "motif_ids.h" 15 | #include "wrapper.h" 16 | 17 | /*************************** Global variables ***************************/ 18 | 19 | /******************************* Externs ********************************/ 20 | // input file name 21 | extern char *input_network_fname; 22 | 23 | // crazy wicked wild "general program info and flags" 24 | extern Gnrl_st GNRL_ST; 25 | 26 | // confusing as hell result table 27 | extern Res_tbl RES_TBL; 28 | 29 | // a somewhat pared-down version of the results 30 | extern list64 *final_res, *final_res_all; 31 | 32 | // from the globals in main.c 33 | extern int DEBUG_LEVEL; 34 | 35 | // we need the network as an extern 36 | extern Network *G_N; 37 | 38 | /************************************************************************/ 39 | 40 | void set_default_options(){ 41 | //copied from process_input_args in main.c 42 | GNRL_ST.mtf_sz=DEFAULT_MTF_SZ; 43 | GNRL_ST.rnd_net_num=DEFAULT_RAND_NETWORK_NUM; 44 | GNRL_ST.t_init=T0; 45 | GNRL_ST.iteration_factor=ITERATION_F; 46 | GNRL_ST.e_thresh=ETHRESH; 47 | GNRL_ST.use_stubs_method=FALSE; 48 | GNRL_ST.long_out_flag=FALSE; 49 | GNRL_ST.calc_unique_flag=TRUE; 50 | GNRL_ST.calc_roles=FALSE; 51 | GNRL_ST.input_net_format=SRC_TRG_FORMAT; 52 | GNRL_ST.undirected_flag=FALSE; 53 | GNRL_ST.calc_self_edges=FALSE; 54 | GNRL_ST.calc_weights=FALSE; 55 | GNRL_ST.run_prob_app=FALSE; 56 | GNRL_ST.prob_base_samples_num=0; 57 | GNRL_ST.prob_converge_mode=FALSE; 58 | GNRL_ST.prob_conv_diff=CONVERGNESS_DIFF_CONST; 59 | GNRL_ST.prob_conv_conc_th=CONC_THRESHOLD; 60 | GNRL_ST.unique_th=UNIQUE_TH; 61 | GNRL_ST.force_unique_th=FALSE; 62 | GNRL_ST.mfactor_th=MFACTOR_TH; 63 | GNRL_ST.zfactor_th=ZSCORE_TH; 64 | GNRL_ST.pval_th=PVAL_TH; 65 | GNRL_ST.max_members_list_sz=1000; 66 | GNRL_ST.top_motifs_list_sz=TOP_MOTIF_LIST_SZ; 67 | GNRL_ST.out_log_flag=FALSE; 68 | GNRL_ST.out_s_mat_flag=FALSE; 69 | GNRL_ST.out_l_mat_flag=FALSE; 70 | GNRL_ST.out_s_c_mat_flag=FALSE; 71 | GNRL_ST.out_members=FALSE; 72 | GNRL_ST.out_rand_mat_flag=FALSE; 73 | GNRL_ST.out_roles=FALSE; 74 | GNRL_ST.out_clustering=FALSE; 75 | GNRL_ST.quiet_mode=FALSE; 76 | GNRL_ST.use_metropolis=FALSE; 77 | GNRL_ST.use_clustering=FALSE; 78 | GNRL_ST.dont_search_real=FALSE; 79 | GNRL_ST.out_intermediate=FALSE; 80 | GNRL_ST.out_non_dangling_motifs=FALSE; 81 | GNRL_ST.r_switch_factor=(double)R_SWITCH_FACTOR; 82 | GNRL_ST.r_global_switch_mode=FALSE; 83 | GNRL_ST.list_members=FALSE; 84 | GNRL_ST.specific_subgraph_members=0; //no specific subgraph members 85 | GNRL_ST.efc_prob=FALSE; 86 | GNRL_ST.out_all_rand_networks=FALSE; 87 | GNRL_ST.r_grassberger=FALSE; 88 | GNRL_ST.r_grass_colony_sz=0; 89 | GNRL_ST.r_grass_colony_max_population=MAX_COLONY_SZ_RATIO; 90 | GNRL_ST.r_dont_conserve_mutuals=FALSE; 91 | GNRL_ST.dont_die=FALSE; 92 | GNRL_ST.r_conserve_layers=FALSE; 93 | GNRL_ST.r_layers_num=0; 94 | } 95 | 96 | int 97 | load_network_from_array(Network **N_p, int* edges, int edges_num) 98 | { 99 | int rc=RC_OK,s,t,i,j,k,weight; 100 | list_item *l_e; 101 | int max_node=0; 102 | //FILE *fp; 103 | Network *N; 104 | int e_idx; 105 | int self_edge_exists=FALSE; 106 | int matVal = 0; 107 | 108 | N=(Network*)calloc(1,sizeof(Network)); 109 | N->name="I came from an array, sucka!"; 110 | N->edges_num = 0; 111 | N->e_self_num = 0; 112 | 113 | for(i=1;i<=edges_num;i++){ 114 | s = edges[3*(i-1)+1]; 115 | t = edges[3*(i-1)+2]; 116 | if (s==t){ 117 | N->e_self_num += 1; 118 | if (GNRL_ST.calc_self_edges == TRUE) 119 | N->edges_num += 1; 120 | }else 121 | N->edges_num += 1; 122 | } 123 | 124 | N->e_arr=(Edge*)calloc(N->edges_num+1,sizeof(Edge)); 125 | N->e_arr_self=(Edge*)calloc(N->e_self_num+1,sizeof(Edge)); 126 | j = k = 0; 127 | for(i=1;i<=edges_num;i++){ 128 | //SRC->TRG format 129 | if(GNRL_ST.input_net_format==SRC_TRG_FORMAT){ 130 | s = edges[3*(i-1)+1]; 131 | t = edges[3*(i-1)+2]; 132 | weight = edges[3*(i-1)+3]; 133 | } 134 | //TRG->SRC format 135 | else{ 136 | t = edges[3*(i-1)+1]; 137 | s = edges[3*(i-1)+2]; 138 | weight = edges[3*(i-1)+3]; 139 | } 140 | 141 | if (s==t){ 142 | N->e_arr_self[++j].s=s; 143 | N->e_arr_self[j].t=t; 144 | N->e_arr_self[j].weight=weight; 145 | 146 | if(GNRL_ST.calc_self_edges == TRUE){ 147 | N->e_arr[++k].s=s; 148 | N->e_arr[k].t=t; 149 | N->e_arr[k].weight=weight; 150 | 151 | if (s>max_node) max_node=s; 152 | if (t>max_node) max_node=t; 153 | } 154 | }else{ 155 | N->e_arr[++k].s=s; 156 | N->e_arr[k].t=t; 157 | N->e_arr[k].weight=weight; 158 | 159 | if (s>max_node) max_node=s; 160 | if (t>max_node) max_node=t; 161 | } 162 | } 163 | 164 | /////////////////////////////////////////////////////////////////// 165 | // ALL OF THE ITEMS BELOW ARE COPIED FROM load_network IN GLOBALS.H 166 | /////////////////////////////////////////////////////////////////// 167 | 168 | N->vertices_num=max_node; 169 | 170 | rc |= MatInit(&N->mat,N->vertices_num,SPARSE); 171 | if(rc == RC_ERR) { 172 | printf("Error : Memory allocation failure\n"); 173 | at_exit(-1); 174 | } 175 | 176 | //assign matrix entries according to edges 177 | for(i=1; i<=N->edges_num; i++) { 178 | if(GNRL_ST.calc_weights == TRUE) { 179 | MatAsgn(N->mat,N->e_arr[i].s,N->e_arr[i].t,N->e_arr[i].weight); 180 | }else{ 181 | if(MatGet(N->mat,N->e_arr[i].s,N->e_arr[i].t) != 0) { 182 | printf("Error : Duplicate appearance of the edge (%d,%d) \n\tfound in the Network\n ", 183 | N->e_arr[i].s,N->e_arr[i].t); 184 | at_exit(-1); 185 | }else{ 186 | MatAsgn(N->mat,N->e_arr[i].s,N->e_arr[i].t,1); 187 | } 188 | } 189 | } 190 | 191 | //if efc_prob app then 192 | //create e_map matrix mapping of edges [s,t] to their index in e_arr 193 | if(GNRL_ST.efc_prob){ 194 | rc |= MatInit(&N->e_map,N->vertices_num,SPARSE); 195 | if(rc == RC_ERR) { 196 | printf("Error : Memory allocation failure\n"); 197 | at_exit(-1); 198 | } 199 | for(i=1; i<=N->edges_num; i++) 200 | 201 | MatAsgn(N->e_map,N->e_arr[i].s,N->e_arr[i].t,i); 202 | } 203 | 204 | //check there are no Self edges- if there are any then output them to screen and stop 205 | if(GNRL_ST.calc_self_edges == FALSE){ 206 | for(i=1; i<=N->vertices_num; i++) { 207 | if(MatGet(N->mat,i,i)==1) { 208 | fprintf(stdout,"Self edges exist in Input Network!!!\n"); 209 | fprintf(stdout,"Self Edges : (%d,%d)\t",i,i); 210 | self_edge_exists=TRUE; 211 | } 212 | } 213 | if(self_edge_exists==TRUE) 214 | at_exit(-1); 215 | } 216 | 217 | //allocate and fill arrays of single edges and double edges 218 | N->e_arr_sin=(Edge*)calloc(N->edges_num+1,sizeof(Edge)); 219 | N->e_arr_dbl=(Edge*)calloc((N->edges_num+1),sizeof(Edge)); 220 | N->e_sin_num=0; 221 | N->e_dbl_num=0; 222 | N->roots_num=0; 223 | N->leafs_num=0; 224 | //allocate indeg and out deg arrays 225 | N->indeg=(int*)calloc(N->vertices_num+2,sizeof(int)); 226 | N->outdeg=(int*)calloc(N->vertices_num+2,sizeof(int)); 227 | N->doubledeg=(int*)calloc(N->vertices_num+2,sizeof(int)); 228 | if(GNRL_ST.calc_self_edges == TRUE){ 229 | N->self_edge=(int*)calloc(N->vertices_num+2,sizeof(int)); 230 | } 231 | //actually matrix is sparse anyway now 232 | if(N->mat->type == SPARSE) { 233 | for(i=1;i<=N->vertices_num;i++) { 234 | for(j=1;j<=N->vertices_num;j++) { 235 | if( (matVal = MatGet(N->mat,i,j))) { 236 | //if an edge and is not self edge 237 | if(i != j){ 238 | //if the twin edge exists 239 | if(MatGet(N->mat,j,i)){ 240 | //not inserted yet 241 | if(j>i) { 242 | //double edge- this way always the twin pair has indexes 2x-1,2x 243 | N->e_arr_dbl[++N->e_dbl_num].s=i; 244 | N->e_arr_dbl[N->e_dbl_num].t=j; 245 | N->e_arr_dbl[N->e_dbl_num].weight=matVal; 246 | N->e_arr_dbl[++N->e_dbl_num].s=j; 247 | N->e_arr_dbl[N->e_dbl_num].t=i; 248 | N->e_arr_dbl[N->e_dbl_num].weight=matVal; 249 | } 250 | } 251 | else { 252 | //single edge 253 | N->e_arr_sin[++N->e_sin_num].s=i; 254 | N->e_arr_sin[N->e_sin_num].t=j; 255 | N->e_arr_sin[N->e_sin_num].weight=matVal; 256 | } 257 | } 258 | else //self edge 259 | { 260 | N->e_arr_sin[++N->e_sin_num].s=i; 261 | N->e_arr_sin[N->e_sin_num].t=j; 262 | N->e_arr_sin[N->e_sin_num].weight=matVal; 263 | } 264 | } 265 | } 266 | } 267 | 268 | //fill in deg and out deg arrays 269 | for(i=0;i<=N->vertices_num;i++) { 270 | N->indeg[i]=0; 271 | N->outdeg[i]=0; 272 | if(GNRL_ST.calc_self_edges == TRUE) 273 | { 274 | N->self_edge[i]=FALSE; 275 | } 276 | } 277 | for (i=1; i<=N->vertices_num;i++){ 278 | if(N->mat->spr->m[i].to==NULL) 279 | N->outdeg[i]=0; 280 | else 281 | N->outdeg[i]=N->mat->spr->m[i].to->size; 282 | if(N->mat->spr->m[i].from==NULL) 283 | N->indeg[i]=0; 284 | else 285 | N->indeg[i]=N->mat->spr->m[i].from->size; 286 | if((N->mat->spr->m[i].self_edge == 1) && (GNRL_ST.calc_self_edges == TRUE)) 287 | { 288 | N->self_edge[i] = TRUE; 289 | } 290 | } 291 | } 292 | 293 | //statistics and global info about the network 294 | N->con_vertices_num=0; 295 | N->hub_deg=0; 296 | N->hub=0; 297 | N->in_hub_deg=0; 298 | N->in_hub=0; 299 | N->out_hub_deg=0; 300 | N->out_hub=0; 301 | //calc total num of connected vertices 302 | //and find hub preferenced 303 | for(i=1; i<=N->vertices_num;i++){ 304 | if( (N->indeg[i]!=0) || (N->outdeg[i]!=0) ) 305 | N->con_vertices_num++; 306 | if( ((N->indeg[i] + N->outdeg[i]) > N->hub_deg) ){ 307 | N->hub_deg=N->indeg[i] + N->outdeg[i]; 308 | N->hub=i; 309 | } 310 | if( N->indeg[i] > N->in_hub_deg){ 311 | N->in_hub_deg=N->indeg[i]; 312 | N->in_hub=i; 313 | } 314 | if( N->outdeg[i] > N->out_hub_deg){ 315 | N->out_hub_deg=N->outdeg[i]; 316 | N->out_hub=i; 317 | } 318 | } 319 | 320 | //if calc roles then init array or roles vector for all nodes 321 | if(GNRL_ST.calc_roles==TRUE && GNRL_ST.mtf_sz==3) { 322 | if( (N->roles_vec=(char**)calloc(N->vertices_num+1,sizeof(char*))) ==NULL) 323 | return RC_ERR; 324 | for(i=1;i<=N->vertices_num;i++) 325 | if( (N->roles_vec[i]=(char*)calloc(TOTAL_ROLES_3_NUM+1,sizeof(char))) ==NULL) 326 | return RC_ERR; 327 | } 328 | //if use clusterring in random network genereation 329 | if(GNRL_ST.use_clustering){ 330 | N->cluster_degree=(double*)calloc(N->vertices_num+2,sizeof(double)); 331 | for(i=0;i<=N->vertices_num;i++) { 332 | N->cluster_degree[i]=0.0; 333 | } 334 | //fill clustering series 335 | clustering_series(N,NULL); 336 | } 337 | //if efc prob approach then init hub_edges_vec and hub_edges_indices 338 | if(GNRL_ST.efc_prob){ 339 | N->hub_edges_vec=(int*)calloc(N->edges_num+1,sizeof(int)); 340 | N->hub_edges_indices=(int*)calloc(N->hub_deg+1,sizeof(int)); 341 | 342 | //fill hub vector and hub indices 343 | i=0; 344 | for(l_e=list_get_next(N->e_map->spr->m[N->hub].to,NULL);l_e!=NULL; 345 | l_e=list_get_next(N->e_map->spr->m[N->hub].to,l_e)) { 346 | e_idx=*(int*)l_e->p; 347 | N->hub_edges_indices[++i]=e_idx; 348 | N->hub_edges_vec[e_idx]=i; 349 | } 350 | for(l_e=list_get_next(N->e_map->spr->m[N->hub].from,NULL);l_e!=NULL; 351 | l_e=list_get_next(N->e_map->spr->m[N->hub].from,l_e)) { 352 | e_idx=*(int*)l_e->p; 353 | N->hub_edges_indices[++i]=e_idx; 354 | N->hub_edges_vec[e_idx]=i; 355 | } 356 | if(i!=N->hub_deg) 357 | printf("Error in Hub degree\n"); 358 | } 359 | //if conserve layers in random netowrks 360 | if(GNRL_ST.r_conserve_layers==TRUE){ 361 | N->num_of_layers=GNRL_ST.r_layers_num; 362 | N->layer_node_num=(int*)calloc(N->num_of_layers+1,sizeof(int)); 363 | N->layer_edges_num=(int*)calloc(N->num_of_layers+1,sizeof(int)); 364 | //copy num of nodes in each layer 365 | for(i=1;i<=N->num_of_layers;i++) 366 | N->layer_node_num[i]=GNRL_ST.r_layer_sz[i]; 367 | //run through e_arr and fill N->layer_edges_num 368 | //this is required for the randomizing process - in order to swtich edges 369 | //between nodes in the same layers only 370 | max_node=0; 371 | j=1; 372 | for(i=1;i<=N->num_of_layers;i++){ 373 | max_node+=N->layer_node_num[i]; 374 | while( (N->e_arr[j].s<=max_node) && (j<=N->edges_num) ){ 375 | N->layer_edges_num[i]++; 376 | j++; 377 | } 378 | } 379 | //sanity check - that num of edges in layers sum to total num of edges 380 | j=0; 381 | for(i=1;i<=N->num_of_layers;i++) 382 | j+=N->layer_edges_num[i]; 383 | if(j!=N->edges_num){ 384 | printf("\nERROR: in '-rcl' flag, check layers info\n"); 385 | at_exit(-1); 386 | } 387 | } 388 | if(DEBUG_LEVEL>11) 389 | dump_network(stdout,N); 390 | *N_p=N; 391 | return rc; 392 | } 393 | 394 | /* 395 | * function : read_network 396 | * read network from different input types 397 | * 398 | * arguments: 399 | * N_p - reference to network structure 400 | * mfinderi - mfinder wrapper input struct 401 | * 402 | * return values: 403 | * RC_OK - if not error occured 404 | * RC_ERR - if error occured 405 | */ 406 | int 407 | read_network(Network **N_p, mfinder_input mfinderi) 408 | { 409 | int rc=RC_OK; 410 | 411 | // load network from input file 412 | if(mfinderi.Filename != NULL){ 413 | rc = load_network(&G_N,mfinderi.Filename); 414 | if (rc == RC_ERR) { 415 | printf("load network from file failed\n"); 416 | return RC_ERR; 417 | } 418 | } 419 | // load network from array of edge info 420 | // this exists for streamlined use of the python module 421 | else{ 422 | rc = load_network_from_array(&G_N,mfinderi.Edges,mfinderi.NumEdges); 423 | if (rc == RC_ERR) { 424 | printf("load network from array failed\n"); 425 | return RC_ERR; 426 | } 427 | } 428 | 429 | return rc; 430 | } 431 | 432 | /******************************************************** 433 | * function : single_connected_component 434 | * Given a motif id and size, 435 | * Return whether there is a single connected component 436 | * arguments: 437 | * id 438 | * mtf_siz 439 | * return values: 440 | * TRUE/FALSE 441 | *********************************************************/ 442 | 443 | int single_connected_component(int64 id,int mtf_sz){ 444 | int i,j,k; 445 | int added; 446 | 447 | //fprintf(stderr,"checking the scc for id=%lli\n",id); 448 | 449 | // build the adjacency matrix 450 | Matrix *M; 451 | M = init_matrix(mtf_sz); 452 | fill_mat_id(M,id); 453 | 454 | // collect members of the connected component here 455 | int cc[mtf_sz+1]; 456 | int checked[mtf_sz+1]; 457 | for(i=1;i<=mtf_sz;i++){ 458 | cc[i] = FALSE; 459 | checked[i] = FALSE; 460 | } 461 | 462 | // add the first node to the connected component 463 | cc[1] = TRUE; 464 | 465 | // iteratively attempt to add more rows/columns to the cc 466 | added = TRUE; 467 | while(added == TRUE){ 468 | added = FALSE; 469 | for(i=1;i<=mtf_sz;i++) 470 | if(cc[i] == TRUE && checked[i] == FALSE){ 471 | checked[i] = TRUE; 472 | for(j=1;j<=mtf_sz;j++) 473 | if(MTRX(M,i,j)==1 || MTRX(M,j,i)==1) 474 | if(cc[j] == FALSE){ 475 | cc[j] = TRUE; 476 | added = TRUE; 477 | } 478 | } 479 | } 480 | 481 | free_matrix(M); 482 | free(M); 483 | 484 | for(i=1;i<=mtf_sz;++i) 485 | if(cc[i] == FALSE) 486 | return FALSE; 487 | 488 | return TRUE; 489 | } 490 | 491 | /******************************************************** 492 | * function : list_all_motifs 493 | * List all motifs for a given size 494 | * --> copied largely from calc_final_results in results.c 495 | * arguments: 496 | * AAA 497 | * BBB 498 | * CCC 499 | * return values: 500 | * XXX 501 | * YYY 502 | *********************************************************/ 503 | 504 | list64* list_motifs(int mtf_sz){ 505 | int i,j,illegal_id=FALSE; 506 | list64_item *l_tmp; 507 | int64 id,rep_id,mask_bit,mask_r,mask_c; 508 | 509 | list64* iso_list; 510 | list64* id_list_uniq; 511 | list64* id_list_scc_false; 512 | list64_init(&id_list_uniq); 513 | list64_init(&id_list_scc_false); 514 | 515 | for(id=0;id<=(int64)(pow(2,mtf_sz*mtf_sz)-1);id++){ 516 | illegal_id=FALSE; 517 | 518 | /* 519 | //Check if we've already found this id via the motif isomorphisms 520 | if(list64_get(id_list_all,(int64)id)!=NULL) 521 | illegal_id = TRUE; 522 | if(illegal_id) 523 | continue; 524 | */ 525 | 526 | //Check if the motif contains self edges 527 | for(i=0;ival; 569 | if(list64_get(id_list_uniq,(int64)rep_id)!=NULL) 570 | illegal_id = TRUE; 571 | if(illegal_id == TRUE) 572 | continue; 573 | 574 | //Check if the motif has a single connected component 575 | if(single_connected_component(rep_id,mtf_sz) == FALSE) 576 | //list64_insert(id_list_scc_false,(int64)rep_id,NULL); 577 | illegal_id = TRUE; 578 | if(illegal_id == TRUE) 579 | continue; 580 | 581 | list64_insert(id_list_uniq,(int64)rep_id,NULL); 582 | 583 | /* 584 | for(l_tmp=list64_get_next(iso_list,NULL); l_tmp !=NULL; l_tmp=list64_get_next(iso_list,l_tmp)) { 585 | rrep_id=l_tmp->val; 586 | if(list64_get(id_list_all,(int64)rrep_id)==NULL){ 587 | list64_insert(id_list_all,(int64)rrep_id,NULL); 588 | //fprintf(stdout,"iso_id %lli == iso_id %lli\n",rep_id,rrep_id); 589 | } 590 | } 591 | */ 592 | 593 | list64_free_mem(iso_list); 594 | } 595 | 596 | list64_free_mem(id_list_scc_false); 597 | 598 | return id_list_uniq; 599 | //list64_free_mem(id_list_uniq); 600 | } 601 | 602 | list* motif_edges(int64 id,int mtf_sz){ 603 | int i,j; 604 | Matrix *M; 605 | Edge *e; 606 | list *motif_edges; 607 | list_init(&motif_edges); 608 | 609 | M = init_matrix(mtf_sz); 610 | fill_mat_id(M,id); 611 | 612 | for(i=1;i<=mtf_sz;i++) 613 | for(j=1;j<=mtf_sz;j++) 614 | if(MTRX(M,i,j)==1){ 615 | e=(Edge*)calloc(1,sizeof(Edge)); 616 | e->s = i; 617 | e->t = j; 618 | e->weight = 1; 619 | 620 | list_insert(motif_edges,0,(void*)e); 621 | } 622 | 623 | free_matrix(M); 624 | free(M); 625 | 626 | return motif_edges; 627 | } 628 | 629 | /******************************************************** 630 | * function : random_network 631 | * Randomize an input network 632 | * arguments: 633 | * AAA 634 | * BBB 635 | * CCC 636 | * return values: 637 | * XXX 638 | * YYY 639 | *********************************************************/ 640 | 641 | list* random_network(mfinder_input mfinderi){ 642 | set_default_options(); 643 | 644 | // turn on quiet mode 645 | GNRL_ST.quiet_mode=TRUE; 646 | 647 | // ignore self edges 648 | GNRL_ST.calc_self_edges=FALSE; 649 | 650 | // general initialization 651 | int rc = gnrl_init(); 652 | if (rc == RC_ERR) { 653 | printf("general init failed\n"); 654 | return NULL; 655 | } 656 | 657 | // initialize the random seed 658 | init_random_seed(); 659 | 660 | // read in the network 661 | rc = read_network(&G_N,mfinderi); 662 | if(rc==RC_ERR){ 663 | fprintf(stderr,"load network failed\n"); 664 | return NULL; 665 | } 666 | 667 | // generate a new (to be randomized) network 668 | Network *N; 669 | 670 | // typical single/double switching algorithm 671 | if(mfinderi.UseMetropolis == 0){ // || GNRL_ST.mtf_sz <= 3){ 672 | //fprintf(stderr,"randomizing in typical single-double fashion\n"); 673 | double switch_ratio; 674 | rc = gen_rand_network_switches_method_conserve_double_edges(&N,&switch_ratio); 675 | if (rc == RC_ERR) { 676 | fprintf(stderr,"single-double randomize network failed\n"); 677 | return NULL; 678 | } 679 | rc = update_network(N,G_N); 680 | if (rc == RC_ERR) { 681 | fprintf(stderr,"randomize network failed to maintain node statistics\n"); 682 | return NULL; 683 | } 684 | } 685 | // metropolis algorithm to have same triad consensus 686 | else{ 687 | //printf("randomize while using the metropolis algorithm to preserve triads\n"); 688 | int j,real_vec13[14]; 689 | Res_tbl met_res_tbl; 690 | 691 | for(j=1;j<=13;j++) 692 | real_vec13[j]=0; 693 | init_res_tbl(&met_res_tbl); 694 | 695 | met_motifs_search_real(G_N,&met_res_tbl,real_vec13); 696 | list64_free_mem(met_res_tbl.real); 697 | //res_tbl_mem_free(met_res_tbl); 698 | 699 | rc = gen_rand_network_metrop(&N,real_vec13); 700 | if (rc == RC_ERR) { 701 | fprintf(stderr,"metropolis randomize network failed\n"); 702 | return NULL; 703 | } 704 | rc = update_network(N,G_N); 705 | if (rc == RC_ERR) { 706 | fprintf(stderr,"randomize network failed to maintain node statistics\n"); 707 | return NULL; 708 | } 709 | } 710 | 711 | list *randomized_edges; 712 | list_init(&randomized_edges); 713 | 714 | int i; 715 | Edge *e; 716 | // add the self edges that were never randomized 717 | for(i=1;i<=N->e_self_num;++i){ 718 | e=(Edge*)calloc(1,sizeof(Edge)); 719 | e->s = N->e_arr_self[i].s; 720 | e->t = N->e_arr_self[i].t; 721 | e->weight = N->e_arr_self[i].weight; 722 | 723 | list_insert(randomized_edges,0,(void*)e); 724 | } 725 | // add the now randomized edges 726 | for(i=1;i<=N->edges_num;++i){ 727 | e=(Edge*)calloc(1,sizeof(Edge)); 728 | e->s = N->e_arr[i].s; 729 | e->t = N->e_arr[i].t; 730 | e->weight = N->e_arr[i].weight; 731 | 732 | list_insert(randomized_edges,0,(void*)e); 733 | } 734 | 735 | // release memory of various objects 736 | free_network_mem(N); 737 | free(N); 738 | 739 | return randomized_edges; 740 | } 741 | 742 | /******************************************************** 743 | * function : motif_structure 744 | * Calculate the motif structure statistics 745 | * arguments: 746 | * AAA 747 | * BBB 748 | * CCC 749 | * return values: 750 | * XXX 751 | * YYY 752 | *********************************************************/ 753 | 754 | list64* motif_structure(mfinder_input mfinderi){ 755 | set_default_options(); 756 | 757 | // turn on quiet mode 758 | GNRL_ST.quiet_mode=TRUE; 759 | 760 | // what size motif are we talking about? 761 | GNRL_ST.mtf_sz = mfinderi.MotifSize; 762 | 763 | // against how many randomizations should we compare? 764 | GNRL_ST.rnd_net_num = mfinderi.NRandomizations; 765 | 766 | // ignore the uniqueness bit 767 | GNRL_ST.unique_th=0; 768 | GNRL_ST.calc_unique_flag=FALSE; 769 | 770 | // ignore self edges 771 | GNRL_ST.calc_self_edges=FALSE; 772 | 773 | // randomize with the metropolis algorithm to preserve the same triad consensus 774 | if(mfinderi.UseMetropolis == 1) 775 | GNRL_ST.use_metropolis=TRUE; 776 | 777 | // general initialization 778 | int rc = gnrl_init(); 779 | if (rc == RC_ERR) { 780 | printf("general init failed\n"); 781 | return NULL; 782 | }/*else 783 | printf("general init succeeded\n");*/ 784 | 785 | // initialize the random seed 786 | init_random_seed(); 787 | 788 | // read in the network 789 | rc = read_network(&G_N,mfinderi); 790 | if(rc==RC_ERR){ 791 | printf("load network failed\n"); 792 | return NULL; 793 | } 794 | 795 | // generate a fake network to search in 796 | Network *N; 797 | rc = duplicate_network(G_N,&N,"real_network"); 798 | if (rc == RC_ERR) { 799 | printf("duplicate network failed\n"); 800 | return NULL; 801 | } 802 | 803 | // exhaustive search motif size n 804 | rc = count_subgraphs(N, GNRL_ST.mtf_sz, &RES_TBL.real, REAL_NET); 805 | if (rc == RC_ERR) { 806 | printf("real search failed\n"); 807 | return NULL; 808 | } 809 | 810 | // calc result after isomorphism of ids 811 | join_subgraphs_res(&RES_TBL.real, GNRL_ST.mtf_sz, 0); 812 | 813 | // conduct randomized network analysis 814 | if(GNRL_ST.rnd_net_num > 0){ 815 | rc = process_rand_networks(&RES_TBL, GNRL_ST.mtf_sz); 816 | if (rc == RC_ERR) { 817 | printf("random network analysis failed\n"); 818 | return NULL; 819 | } 820 | } 821 | 822 | //calculate final results 823 | calc_final_results(&RES_TBL, &final_res, &final_res_all, GNRL_ST.rnd_net_num); 824 | 825 | // release memory of various network objects 826 | free_network_mem(N); 827 | free(N); 828 | 829 | // release the results table memory 830 | res_tbl_mem_free(&RES_TBL); 831 | 832 | // return the crazy results table 833 | // per mfinder, this depends on the size of the motifs 834 | if(GNRL_ST.mtf_sz<=4){ 835 | final_res_free(final_res); 836 | return final_res_all; 837 | }else{ 838 | final_res_free(final_res); 839 | return final_res_all; 840 | } 841 | } 842 | 843 | 844 | /******************************************************** 845 | * function : motif_participation 846 | * Calculate the motif participation statistics 847 | * arguments: 848 | * AAA 849 | * BBB 850 | * CCC 851 | * return values: 852 | * XXX 853 | * YYY 854 | *********************************************************/ 855 | 856 | list64* motif_participation(mfinder_input mfinderi){ 857 | set_default_options(); 858 | 859 | // turn on quiet mode 860 | GNRL_ST.quiet_mode=TRUE; 861 | 862 | // what size motif are we talking about? 863 | GNRL_ST.mtf_sz = mfinderi.MotifSize; 864 | 865 | // ignore the uniqueness bit 866 | GNRL_ST.unique_th=0; 867 | GNRL_ST.calc_unique_flag=FALSE; 868 | 869 | // ignore self edges 870 | GNRL_ST.calc_self_edges=FALSE; 871 | 872 | // keep track of motif members 873 | GNRL_ST.list_members=TRUE; 874 | GNRL_ST.max_members_list_sz=mfinderi.MaxMembersListSz; 875 | 876 | // general initialization 877 | int rc = gnrl_init(); 878 | if (rc == RC_ERR) { 879 | printf("general init failed\n"); 880 | return NULL; 881 | } 882 | 883 | // initialize the random seed 884 | init_random_seed(); 885 | 886 | // read in the network 887 | rc = read_network(&G_N,mfinderi); 888 | if(rc==RC_ERR){ 889 | printf("load network failed\n"); 890 | return NULL; 891 | } 892 | 893 | // generate a fake real network or randomize the network before counting motifs and participation 894 | Network *N; 895 | // use the fake real network 896 | if (mfinderi.Randomize == 0){; 897 | rc = duplicate_network(G_N,&N,"real_network"); 898 | if (rc == RC_ERR) { 899 | printf("duplicate network failed\n"); 900 | return NULL; 901 | } 902 | } 903 | // randomize the network 904 | else{ 905 | // typical single/double switching algorithm 906 | if(mfinderi.UseMetropolis == 0){ // || GNRL_ST.mtf_sz <= 3){ 907 | //printf("randomizing in typical single-double fashion\n"); 908 | double switch_ratio; 909 | rc = gen_rand_network_switches_method_conserve_double_edges(&N,&switch_ratio); 910 | if (rc == RC_ERR) { 911 | printf("single-double randomize network failed\n"); 912 | return NULL; 913 | } 914 | rc = update_network(N,G_N); 915 | if (rc == RC_ERR) { 916 | printf("randomize network failed to maintain node statistics\n"); 917 | return NULL; 918 | } 919 | } 920 | // metropolis algorithm to have same triad consensus 921 | else{ 922 | //printf("randomize while using the metropolis algorithm to preserve triads\n"); 923 | int j,real_vec13[14]; 924 | Res_tbl met_res_tbl; 925 | 926 | for(j=1;j<=13;j++) 927 | real_vec13[j]=0; 928 | init_res_tbl(&met_res_tbl); 929 | 930 | met_motifs_search_real(G_N,&met_res_tbl,real_vec13); 931 | list64_free_mem(met_res_tbl.real); 932 | 933 | rc = gen_rand_network_metrop(&N,real_vec13); 934 | if (rc == RC_ERR) { 935 | printf("metropolis randomize network failed\n"); 936 | return NULL; 937 | } 938 | rc = update_network(N,G_N); 939 | if (rc == RC_ERR) { 940 | printf("randomize network failed to maintain node statistics\n"); 941 | return NULL; 942 | } 943 | } 944 | } 945 | 946 | //FILE *fp; 947 | //fp = fopen("fargus.net","w"); 948 | //dump_network(stdout,N); 949 | //return NULL; 950 | //fclose(fp); 951 | 952 | //exhaustive search motif size n 953 | rc = count_subgraphs(N, GNRL_ST.mtf_sz, &RES_TBL.real, REAL_NET); 954 | if (rc == RC_ERR) { 955 | printf("real search failed\n"); 956 | return NULL; 957 | } 958 | 959 | // release memory of various objects 960 | free_network_mem(N); 961 | free(N); 962 | 963 | //calc result after isomorphism of ids 964 | join_subgraphs_res(&RES_TBL.real, GNRL_ST.mtf_sz, 0); 965 | 966 | return RES_TBL.real; 967 | } 968 | -------------------------------------------------------------------------------- /pymfinder/mfinder/wrapper.h: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | * 3 | * 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | *************************************************************************/ 11 | #ifndef __STOUFFER_H 12 | #define __STOUFFER_H 13 | 14 | #include "bits.h" 15 | #include "common.h" 16 | 17 | /******************* Definitions ****************************************/ 18 | 19 | // input for the mfinder wrapper 20 | typedef struct { 21 | // in case we need to read in the network's links 22 | char* Filename; 23 | 24 | // in case we give the networks' link info as input 25 | int* Edges; 26 | unsigned int NumEdges; 27 | 28 | // for the motif_structure code 29 | // 1) what size motifs are we interested in? 30 | // 2) to how many randomizations should we compare the real network? 31 | unsigned int MotifSize; 32 | int NRandomizations; 33 | 34 | // for the participation code: 35 | // how many "motif members" can we keep track of? 36 | // should we randomize the network beforehand? 37 | int MaxMembersListSz; 38 | int Randomize; 39 | 40 | // should we use the metropolis-hastings algorithm to preserve size-three motifs? 41 | int UseMetropolis; 42 | } mfinder_input; 43 | 44 | /******************************* Functions *******************************/ 45 | 46 | // modified from original mfinder code 47 | void 48 | free_network_mem(Network *N); 49 | int 50 | load_network(Network **N_p, char* network_fname); 51 | int 52 | duplicate_network(Network *SRC, Network **TRG_p, char *trg_name); 53 | 54 | // added to work interface with swig and python 55 | void set_default_options(); 56 | int load_network_from_array(Network **N_p, int* edges, int edges_num); 57 | int read_network(Network **N_p, mfinder_input mfinderi); 58 | int randomize_network(Network **N_p, mfinder_input mfinderi); 59 | 60 | int single_connected_component(int64 id,int mtf_sz); 61 | list64* list_motifs(int mtf_sz); 62 | list* motif_edges(int64 id,int mtf_sz); 63 | list* random_network(mfinder_input mfinderi); 64 | list64* motif_structure(mfinder_input mfinderi); 65 | list64* motif_participation(mfinder_input mfinderi); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /pymfinder/pymfinder.py: -------------------------------------------------------------------------------- 1 | 2 | import mfinder.mfinder as cmfinder 3 | import sys 4 | from itertools import combinations, permutations 5 | from math import sqrt 6 | from roles import * 7 | from datatypes import * 8 | import numpy as np 9 | 10 | ############################################################## 11 | ############################################################## 12 | # GENERAL UTILITIES 13 | ############################################################## 14 | ############################################################## 15 | 16 | def read_links(filename): 17 | inFile = open(filename, 'r') 18 | links = [] 19 | for i in inFile.readlines(): 20 | l = i.strip().split() 21 | if len(l) > 3 or len(l) < 2: 22 | inFile.close() 23 | sys.stderr.write("Error: there is something peculiar about one of the interactions in your input file.\n") 24 | sys.exit() 25 | elif len(l) == 2: 26 | links += [tuple(l + [1])] 27 | else: 28 | links += [tuple(l)] 29 | 30 | inFile.close() 31 | 32 | return links 33 | 34 | # turn any type of node label into integers (mfinder is finicky like that) 35 | def relabel_nodes(links,stats, buildon=False): 36 | node_dict = {} 37 | for i in range(len(links)): 38 | try: 39 | s,t,w = links[i] 40 | w = float(w) 41 | except ValueError: 42 | s,t = links[i] 43 | w = 1 44 | 45 | try: 46 | s = int(s) 47 | except: 48 | pass 49 | 50 | try: 51 | t = int(t) 52 | except: 53 | pass 54 | 55 | if s not in node_dict: 56 | node_dict[s] = len(node_dict)+1 57 | if t not in node_dict: 58 | node_dict[t] = len(node_dict)+1 59 | 60 | if buildon: 61 | links[i] = (s, t, stats.links[(s,t)].weight) 62 | 63 | else: 64 | links[i] = (node_dict[s], node_dict[t], w) 65 | stats.add_link(link_id = (node_dict[s], node_dict[t]), link_name = (s,t)) 66 | stats.links[(node_dict[s], node_dict[t])].weight = w 67 | try: 68 | x = stats.nodes[node_dict[s]] 69 | except KeyError: 70 | stats.add_node(node_id = node_dict[s], node_name = s) 71 | try: 72 | x = stats.nodes[node_dict[t]] 73 | except KeyError: 74 | stats.add_node(node_id = node_dict[t], node_name = t) 75 | 76 | return links 77 | 78 | def gen_mfinder_network(links): 79 | edges = cmfinder.intArray(len(links)*3+1) 80 | for i in range(len(links)): 81 | try: 82 | s,t,w = links[i] 83 | w = int(round(w)) 84 | except ValueError: 85 | s,t = links[i] 86 | w = 1 87 | 88 | edges[3*i+1] = s 89 | edges[3*i+2] = t 90 | edges[3*i+3] = w 91 | 92 | return edges, len(links) 93 | 94 | # populate the network info 95 | def mfinder_network_setup(network): 96 | if type(network) == type("hello world"): 97 | # DEBUG: if we want to use a filename we need to run a check here to make sure that the node labels are integers and that there are weights 98 | # web.Filename = network 99 | stats = NetworkStats() 100 | network = read_links(network) 101 | network = relabel_nodes(network,stats, buildon=False) 102 | edges, numedges = gen_mfinder_network(network) 103 | return network, stats, edges, numedges 104 | elif type(network) == type([1,2,3]): 105 | stats = NetworkStats() 106 | network = relabel_nodes(network,stats, buildon=False) 107 | edges, numedges = gen_mfinder_network(network) 108 | return network, stats, edges, numedges 109 | elif type(network) == NetworkStats: 110 | links = relabel_nodes(network.links.keys(), network, buildon=True) 111 | edges, numedges = gen_mfinder_network(links) 112 | return links, network, edges, numedges 113 | else: 114 | sys.stderr.write("Error: this is an invalid nework input.\n") 115 | sys.exit() 116 | 117 | 118 | def default_fweight(x): 119 | return sum(x)/len(x) 120 | 121 | 122 | def confidence_interval(data, confidence=0.75): 123 | av=np.mean(data) 124 | m=np.median(data) 125 | sd=np.std(data) 126 | n=len(data) 127 | if n==1: 128 | return data[0], 0.0, data[0],data[0],data[0] 129 | n_data=np.sort(data) 130 | mi=n_data[int(round(n*(1-confidence)))] 131 | ma=n_data[int(round(n*confidence)-1)] 132 | return av, sd, m, ma, mi 133 | 134 | 135 | ############################################################## 136 | ############################################################## 137 | # MOTIF GENERATING CODE 138 | ############################################################## 139 | ############################################################## 140 | 141 | def list_motifs(motifsize): 142 | 143 | motifs = cmfinder.list_motifs(motifsize) 144 | 145 | all_motifs = [] 146 | motif_result = motifs.l 147 | while (motif_result != None): 148 | all_motifs.append(motif_result.val) 149 | 150 | motif_result = motif_result.next 151 | 152 | return all_motifs 153 | 154 | def print_motifs(motifsize,motifID=None,outFile=None,links=False,sep=" "): 155 | if outFile: 156 | fstream = open(outFile,'w') 157 | else: 158 | fstream = sys.stdout 159 | 160 | if motifID: 161 | motifs=[x for x in list_motifs(motifsize) if int(x)==motifID] 162 | else: 163 | motifs=list_motifs(motifsize) 164 | 165 | if motifs==[]: 166 | sys.stderr.write("Error: this motif does not exist.\n") 167 | sys.exit() 168 | 169 | for m in motifs: 170 | output = sep.join(["%i" % m, 171 | ]) 172 | 173 | fstream.write(output + '\n') 174 | 175 | if links: 176 | motif_edges = cmfinder.motif_edges(m,motifsize) 177 | edge_result = motif_edges.l 178 | while (edge_result != None): 179 | edge = cmfinder.get_edge(edge_result.p) 180 | s = int(edge.s) 181 | t = int(edge.t) 182 | output = sep.join(["%i" % s, 183 | "%i" % t, 184 | ]) 185 | fstream.write(output + '\n') 186 | edge_result = edge_result.next 187 | 188 | if outFile: 189 | fstream.close() 190 | 191 | return 192 | 193 | ############################################################## 194 | ############################################################## 195 | # RANDOM NETWORK CODE 196 | ############################################################## 197 | ############################################################## 198 | 199 | def random_network(network, 200 | usemetropolis = False, 201 | ): 202 | 203 | # initialize the heinous input struct 204 | web = cmfinder.mfinder_input() 205 | 206 | # setup the network info 207 | network, stats, web.Edges, web.NumEdges = mfinder_network_setup(network) 208 | 209 | # parameterize the analysis 210 | if not usemetropolis: 211 | web.UseMetropolis = 0 212 | else: 213 | web.UseMetropolis = 1 214 | 215 | return randomized_network(web) 216 | 217 | def randomized_network(mfinderi): 218 | results = cmfinder.random_network(mfinderi) 219 | 220 | edges = [] 221 | edge_result = results.l 222 | while (edge_result != None): 223 | edge = cmfinder.get_edge(edge_result.p) 224 | s = int(edge.s) 225 | t = int(edge.t) 226 | w = int(edge.weight) 227 | edges.append((s,t,w)) 228 | 229 | edge_result = edge_result.next 230 | 231 | return edges 232 | 233 | ############################################################## 234 | ############################################################## 235 | # MOTIF STRUCTURE CODE 236 | ############################################################## 237 | ############################################################## 238 | 239 | def motif_structure(network, 240 | motifsize = 3, 241 | nrandomizations = 0, 242 | usemetropolis = False, 243 | allmotifs = False, 244 | stoufferIDs = False, 245 | weighted = False, 246 | fweight = None 247 | ): 248 | 249 | if motifsize < 2: 250 | sys.stderr.write("Error: this is not a valid motif size.\n") 251 | sys.exit() 252 | 253 | if motifsize > 8: 254 | sys.stderr.write("Error: this is not a recommended motif size.\n") 255 | sys.exit() 256 | 257 | if motifsize > 4 and allmotifs: 258 | sys.stderr.write("Warning: 'allmotifs' will be ignored for this motif size and motif_structure will only register existing motifs in the real network.\n") 259 | allmotifs=False 260 | 261 | if weighted and nrandomizations > 0: 262 | sys.stderr.write("Warning: the analysis of weighted motifs won't be performed for the randomized networks, only for the real one. There are different ways to randomize weighted networks, you could define your own and run motif_structure multiple times to find the random distribution of weighted motifs.\n") 263 | 264 | # initialize the heinous input struct 265 | web = cmfinder.mfinder_input() 266 | 267 | # setup the network info 268 | network, stats, web.Edges, web.NumEdges = mfinder_network_setup(network) 269 | 270 | # add or check some basics of stats object 271 | if stoufferIDs and motifsize!=3: 272 | sys.stderr.write("Warning: 'stoufferIDs' can only be true when 'motifsize=3' in unipartite networks.\n") 273 | stats.stoufferIDs = False 274 | else: 275 | stats.stoufferIDs = stoufferIDs 276 | 277 | if stats.motifsize: 278 | if stats.motifsize != motifsize: 279 | sys.stderr.write("Error: you're trying to mix motif sizes.\n") 280 | sys.exit() 281 | else: 282 | stats.motifsize = motifsize 283 | 284 | if stats.networktype: 285 | stats.networktype = "unipartite" 286 | 287 | if stats.weighted!=None: 288 | if stats.weighted != weighted: 289 | sys.stderr.write("Error: you're trying to mix two different motif analyses.\n") 290 | 291 | stats.weighted = weighted 292 | 293 | if fweight==None: 294 | fweight = default_fweight 295 | 296 | # parameterize the analysis 297 | web.MotifSize = motifsize 298 | web.NRandomizations = nrandomizations 299 | if not usemetropolis: 300 | web.UseMetropolis = 0 301 | else: 302 | web.UseMetropolis = 1 303 | 304 | #check if this function has already been run 305 | if len(stats.motifs) != 0: 306 | stats.motifs = dict() 307 | 308 | # determine all nodes' role statistics 309 | if stats.weighted: 310 | if len(stats.motifs) == 0: 311 | motif_stats(web,stats, allmotifs) 312 | web.MaxMembersListSz = max([stats.motifs[x].real for x in stats.motifs])+1 313 | return weighted_motif_stats(web, stats, fweight, allmotifs) 314 | else: 315 | return motif_stats(web, stats, allmotifs) 316 | 317 | 318 | def motif_stats(mfinderi,motif_stats, allmotifs): 319 | results = cmfinder.motif_structure(mfinderi) 320 | 321 | if results: 322 | motif_result = results.l 323 | while (motif_result != None): 324 | motif = cmfinder.get_motif_result(motif_result.p) 325 | 326 | motif_id = int(motif.id) 327 | 328 | if allmotifs or int(motif.real_count)+float(motif.rand_mean)!=0: 329 | motif_stats.add_motif(motif_id) 330 | motif_stats.motifs[motif_id].real = int(motif.real_count) 331 | motif_stats.motifs[motif_id].random_m = float(motif.rand_mean) 332 | motif_stats.motifs[motif_id].random_sd = float(motif.rand_std_dev) 333 | motif_stats.motifs[motif_id].real_z = float(motif.real_zscore) 334 | motif_stats.motifs[motif_id].mean_weight = 0.0 335 | motif_stats.motifs[motif_id].sd_weight = 0.0 336 | motif_stats.motifs[motif_id].median_weight = 0.0 337 | motif_stats.motifs[motif_id].firstq_weight = 0.0 338 | motif_stats.motifs[motif_id].thirdq_weight = 0.0 339 | 340 | motif_result = motif_result.next 341 | 342 | cmfinder.list64_free_mem(results) 343 | 344 | return motif_stats 345 | 346 | def weighted_motif_stats(mfinderi, motif_stats, fweight, allmotifs): 347 | 348 | results = cmfinder.motif_participation(mfinderi) 349 | CI={} 350 | 351 | r_l = results.l 352 | members = cmfinder.intArray(mfinderi.MotifSize) 353 | while (r_l != None): 354 | motif = cmfinder.get_motif(r_l.p) 355 | id = int(motif.id) 356 | idx=0 357 | 358 | CI[id]=np.zeros(motif_stats.motifs[id].real) 359 | 360 | am_l = motif.all_members.l 361 | 362 | while (am_l != None): 363 | 364 | cmfinder.get_motif_members(am_l.p, members, mfinderi.MotifSize) 365 | py_members = [int(members[i]) for i in xrange(mfinderi.MotifSize)] 366 | 367 | weight = fweight([motif_stats.links[x].weight for x in permutations(py_members, 2) if x in motif_stats.links]) 368 | 369 | CI[id][idx] = weight 370 | idx+=1 371 | 372 | am_l = am_l.next 373 | 374 | r_l = r_l.next 375 | 376 | cmfinder.res_tbl_mem_free_single(results) 377 | 378 | for motif_id in motif_stats.motifs: 379 | if motif_stats.motifs[motif_id].real>0: 380 | motif_stats.motifs[motif_id].mean_weight, motif_stats.motifs[motif_id].sd_weight, motif_stats.motifs[motif_id].median_weight, motif_stats.motifs[motif_id].thirdq_weight, motif_stats.motifs[motif_id].firstq_weight = confidence_interval(CI[motif_id]) 381 | 382 | return motif_stats 383 | 384 | 385 | ############################################################## 386 | ############################################################## 387 | # MOTIF PARTICIPATION CODE 388 | ############################################################## 389 | ############################################################## 390 | 391 | def motif_participation(network, 392 | links = False, 393 | motifsize = 3, 394 | randomize = False, 395 | usemetropolis = False, 396 | stoufferIDs = False, 397 | allmotifs = False, 398 | weighted = False, 399 | fweight = None 400 | ): 401 | 402 | if motifsize < 2: 403 | sys.stderr.write("Error: this is not a valid motif size.\n") 404 | sys.exit() 405 | 406 | if motifsize > 8: 407 | sys.stderr.write("Error: this is not a recommended motif size.\n") 408 | sys.exit() 409 | 410 | if motifsize > 4 and allmotifs: 411 | sys.stderr.write("Warning: 'allmotifs' will be ignored for this motif size and motif_participation will only register existing motifs in the real network.\n") 412 | allmotifs=False 413 | 414 | # do we want to randomize the network first? 415 | if randomize: 416 | #This will restart the whole object 417 | network = random_network(network, usemetropolis = usemetropolis) 418 | 419 | # initialize the heinous input struct 420 | web = cmfinder.mfinder_input() 421 | 422 | # setup the network info 423 | network, stats, web.Edges, web.NumEdges = mfinder_network_setup(network) 424 | 425 | # add or check some basics of stats object 426 | if stoufferIDs and motifsize!=3: 427 | sys.stderr.write("Warning: 'stoufferIDs' can only be true when 'motifsize=3' in unipartite networks.\n") 428 | stats.stoufferIDs = False 429 | else: 430 | stats.stoufferIDs = stoufferIDs 431 | 432 | if stats.motifsize: 433 | if stats.motifsize != motifsize: 434 | sys.stderr.write("Error: you're trying to mix motif sizes.\n") 435 | sys.exit() 436 | else: 437 | stats.motifsize = motifsize 438 | 439 | if stats.networktype: 440 | stats.networktype = "unipartite" 441 | 442 | if stats.weighted!=None: 443 | if stats.weighted != weighted: 444 | sys.stderr.write("Warning: you're trying to mix two different motif analyses (weighted and not weighted). Be careful!\n") 445 | 446 | stats.weighted = weighted 447 | 448 | if fweight==None: 449 | fweight = default_fweight 450 | 451 | # parameterize the analysis 452 | web.MotifSize = motifsize 453 | web.Randomize = 0 454 | web.UseMetropolis = 0 455 | if len(stats.motifs) == 0: 456 | web.NRandomizations = 0 457 | web.UseMetropolis = 0 458 | motif_stats(web,stats, allmotifs) 459 | 460 | web.MaxMembersListSz = max([stats.motifs[x].real for x in stats.motifs])+1 461 | 462 | #TODO I can also run this inside participation 463 | if stats.weighted: 464 | weighted_motif_stats(web,stats,fweight,allmotifs) 465 | 466 | #check if this function has already been run 467 | if len(stats.nodes[stats.nodes.keys()[0]].motifs) != 0: 468 | for x in stats.nodes.keys(): 469 | stats.nodes[x].motifs = dict() 470 | if len(stats.links[stats.links.keys()[0]].motifs) != 0: 471 | for x in stats.links.keys(): 472 | stats.links[x].motifs = dict() 473 | 474 | return participation_stats(web,stats,links,allmotifs,fweight) 475 | 476 | 477 | def participation_stats(mfinderi, participation, links, allmotifs, fweight): 478 | 479 | results = cmfinder.motif_participation(mfinderi) 480 | 481 | r_l = results.l 482 | members = cmfinder.intArray(mfinderi.MotifSize) 483 | while (r_l != None): 484 | motif = cmfinder.get_motif(r_l.p) 485 | id = int(motif.id) 486 | 487 | am_l = motif.all_members.l 488 | while (am_l != None): 489 | cmfinder.get_motif_members(am_l.p, members, mfinderi.MotifSize) 490 | py_members = [int(members[i]) for i in xrange(mfinderi.MotifSize)] 491 | 492 | if participation.weighted: 493 | 494 | weight = fweight([participation.links[x].weight for x in permutations(py_members, 2) if x in participation.links]) 495 | 496 | for m in py_members: 497 | try: 498 | participation.nodes[m].motifs[id] += 1 499 | except KeyError: 500 | participation.nodes[m].motifs[id] = 1 501 | try: 502 | participation.nodes[m].weighted_motifs[id] += weight 503 | except KeyError: 504 | participation.nodes[m].weighted_motifs[id] = weight 505 | else: 506 | for m in py_members: 507 | try: 508 | participation.nodes[m].motifs[id] += 1 509 | except KeyError: 510 | participation.nodes[m].motifs[id] = 1 511 | 512 | if links: 513 | for m in permutations(py_members, 2): 514 | if m in participation.links: 515 | try: 516 | participation.links[m].motifs[id] += 1 517 | except KeyError: 518 | participation.links[m].motifs[id] = 1 519 | 520 | if participation.weighted: 521 | try: 522 | participation.links[m].weighted_motifs[id] += weight 523 | except KeyError: 524 | participation.links[m].weighted_motifs[id] = weight 525 | 526 | am_l = am_l.next 527 | 528 | r_l = r_l.next 529 | 530 | cmfinder.res_tbl_mem_free_single(results) 531 | 532 | possible_motifs = set(participation.motifs.keys()) 533 | 534 | 535 | for r in possible_motifs: 536 | for n in participation.nodes: 537 | try: 538 | x = participation.nodes[n].motifs[r] 539 | except KeyError: 540 | participation.nodes[n].motifs[r] = 0 541 | 542 | if participation.weighted: 543 | try: 544 | x = participation.nodes[n].weighted_motifs[r] 545 | except KeyError: 546 | participation.nodes[n].weighted_motifs[r] = 0 547 | 548 | if links: 549 | for n in participation.links: 550 | try: 551 | x = participation.links[n].motifs[r] 552 | except KeyError: 553 | participation.links[n].motifs[r] = 0 554 | 555 | if participation.weighted: 556 | try: 557 | x = participation.links[n].weighted_motifs[r] 558 | except KeyError: 559 | participation.links[n].weighted_motifs[r] = 0 560 | 561 | 562 | return participation 563 | 564 | 565 | ############################################################## 566 | ############################################################## 567 | # MOTIF ROLES CODE 568 | ############################################################## 569 | ############################################################## 570 | 571 | def motif_roles(network, 572 | links=False, 573 | motifsize = 3, 574 | randomize = False, 575 | usemetropolis = False, 576 | stoufferIDs = False, 577 | networktype = "unipartite", 578 | allroles = False, 579 | weighted = False, 580 | fweight = None 581 | ): 582 | 583 | if motifsize < 2: 584 | sys.stderr.write("Error: this is not a valid motif size.\n") 585 | sys.exit() 586 | 587 | if (networktype=="unipartite" and motifsize>3) or (networktype=="bipartite" and motifsize>6): 588 | sys.stderr.write("Error: the analysis of the motif-role profiles can only be done for motif size 2 and 3 in unipartite networks and up to motif size 6 in bipartite networks.\n") 589 | sys.exit() 590 | 591 | # do we want to randomize the network first? 592 | if randomize: 593 | #This will restart the whole object 594 | network = random_network(network, usemetropolis = usemetropolis) 595 | 596 | # initialize the heinous input struct 597 | web = cmfinder.mfinder_input() 598 | 599 | # setup the network info 600 | network, stats, web.Edges, web.NumEdges = mfinder_network_setup(network) 601 | 602 | # add or check some basics of stats object 603 | if stoufferIDs and motifsize!=3: 604 | sys.stderr.write("Warning: 'stoufferIDs' can only be true when 'motifsize=3' in unipartite networks.\n") 605 | stats.stoufferIDs = False 606 | else: 607 | stats.stoufferIDs = stoufferIDs 608 | 609 | if stats.motifsize: 610 | if stats.motifsize != motifsize: 611 | sys.stderr.write("You're trying to mix motif sizes.\n") 612 | sys.exit() 613 | else: 614 | stats.motifsize = motifsize 615 | 616 | if stats.networktype: 617 | if stats.networktype != networktype: 618 | sys.stderr.write("You're trying to mix network types.\n") 619 | sys.exit() 620 | else: 621 | stats.networktype = networktype 622 | 623 | if stats.weighted!=None: 624 | if stats.weighted != weighted: 625 | sys.stderr.write("You're trying to mix two different motif analyses (weighted and not weighted). Be careful!\n") 626 | 627 | stats.weighted = weighted 628 | 629 | if fweight==None: 630 | fweight = default_fweight 631 | 632 | # parameterize the analysis 633 | web.MotifSize = motifsize 634 | web.Randomize = 0 635 | web.UseMetropolis = 0 636 | if len(stats.motifs) == 0: 637 | web.NRandomizations = 0 638 | web.UseMetropolis = 0 639 | motif_stats(web,stats, allroles) 640 | 641 | web.MaxMembersListSz = max([stats.motifs[x].real for x in stats.motifs])+1 642 | 643 | #TODO I can also run this inside role_stats 644 | if stats.weighted: 645 | weighted_motif_stats(web,stats,fweight,allroles) 646 | 647 | #check if this function has already been run. TODO this breaks... 648 | if len(stats.nodes[stats.nodes.keys()[0]].roles) != 0: 649 | for x in stats.nodes.keys(): 650 | stats.nodes[x].roles = dict() 651 | if len(stats.links[stats.links.keys()[0]].roles) != 0: 652 | for x in stats.links.keys(): 653 | stats.links[x].roles = dict() 654 | 655 | # determine all nodes' role statistics 656 | return role_stats(web,stats,links,networktype,allroles,fweight) 657 | 658 | 659 | def role_stats(mfinderi,roles,links,networktype,allroles,fweight): 660 | 661 | results = cmfinder.motif_participation(mfinderi) 662 | 663 | possible_roles = set([]) 664 | actual_roles = set([]) 665 | if networktype == "unipartite": 666 | for m,r in UNIPARTITE_ROLES[mfinderi.MotifSize]: 667 | possible_roles.update([tuple([m] + list(x)) for x in r]) 668 | elif networktype == "bipartite": 669 | for m,r in BIPARTITE_ROLES[mfinderi.MotifSize]: 670 | possible_roles.update([tuple([m] + list(x)) for x in r]) 671 | 672 | if links: 673 | possible_linkroles = set([]) 674 | actual_linkroles = set([]) 675 | if networktype == "unipartite": 676 | for m,l in UNIPARTITE_LINKS_ROLES[mfinderi.MotifSize]: 677 | possible_linkroles.update([tuple([m] + list(x)) for x in l]) 678 | elif networktype == "bipartite": 679 | for m,l in BIPARTITE_LINKS_ROLES[mfinderi.MotifSize]: 680 | possible_linkroles.update([tuple([m] + list(x)) for x in l]) 681 | 682 | r_l = results.l 683 | members = cmfinder.intArray(mfinderi.MotifSize) 684 | while (r_l != None): 685 | motif = cmfinder.get_motif(r_l.p) 686 | id = int(motif.id) 687 | 688 | am_l = motif.all_members.l 689 | while (am_l != None): 690 | cmfinder.get_motif_members(am_l.p, members, mfinderi.MotifSize) 691 | py_members = [int(members[i]) for i in xrange(mfinderi.MotifSize)] 692 | 693 | py_motif = [x for x in permutations(py_members, 2) if x in roles.links] 694 | 695 | if roles.weighted: 696 | weight_motif = fweight([roles.links[x].weight for x in py_motif]) 697 | weight_i = [fweight([roles.links[x].weight for x in py_motif if x[0]==m or x[1]==m]) for m in py_members] 698 | weight = weight_motif/float(sum(weight_i)) 699 | 700 | for idm, m in enumerate(py_members): 701 | npred, nprey = 0, 0 702 | for othernode in py_members: 703 | if (othernode,m) in py_motif: 704 | npred+=1 705 | if (m,othernode) in py_motif: 706 | nprey+=1 707 | 708 | key = (id, npred, nprey) 709 | 710 | # if the node's in and out degrees are insufficient to discern its role 711 | # we will add the degrees of the nodes it interacts with (its neighbors) 712 | if key not in possible_roles: 713 | if npred > 0: 714 | connected_to = set([othernode for othernode in py_members if othernode != m and (othernode,m) in py_motif]) 715 | npreys = [sum([(i,j) in py_motif for j in py_members if j != i]) for i in connected_to] 716 | npreys.sort() 717 | key = tuple(list(key) + [tuple(npreys)]) 718 | else: 719 | connected_to = set([othernode for othernode in py_members if othernode != m and (m,othernode) in py_motif]) 720 | npreds = [sum([(j,i) in py_motif for j in py_members if j != i]) for i in connected_to] 721 | npreds.sort() 722 | key = tuple(list(key) + [tuple(npreds)]) 723 | 724 | if key not in possible_roles: 725 | print >> sys.stderr, key 726 | print >> sys.stderr, "Apparently there is a role you aren't accounting for in 'roles.py'." 727 | sys.exit() 728 | 729 | try: 730 | roles.nodes[m].roles[key] += 1 731 | except KeyError: 732 | roles.nodes[m].roles[key] = 1 733 | 734 | if roles.weighted: 735 | try: 736 | roles.nodes[m].weighted_roles[key] += weight_i[idm]*weight 737 | except KeyError: 738 | roles.nodes[m].weighted_roles[key] = weight_i[idm]*weight 739 | 740 | 741 | actual_roles.add(key) 742 | 743 | if links: 744 | for n in py_members: 745 | if n!=m and (n,m) in roles.links: 746 | npred1,npred2,nprey1,nprey2 = 0,0,0,0 747 | for othernode in py_members: 748 | if (othernode,n) in py_motif: 749 | npred1+=1 750 | if (n,othernode) in py_motif: 751 | nprey1+=1 752 | if (othernode,m) in py_motif: 753 | npred2+=1 754 | if (m,othernode) in py_motif: 755 | nprey2+=1 756 | 757 | key = (id, (npred1, nprey1),(npred2, nprey2)) 758 | 759 | if key not in possible_linkroles: 760 | key = (id, (npred2, nprey2),(npred1, nprey1)) 761 | 762 | # There are three motifs containing links that cannot be uniquely specified by (npred1,nprey1),(npred2,nprey2). 763 | if key not in possible_linkroles: 764 | nconnected=set([othernode for othernode in py_members if othernode != n and (n,othernode) in py_motif]) 765 | mconnected=set([othernode for othernode in py_members if othernode != m and (othernode,m) in py_motif]) 766 | 767 | npreypreds=sorted([sum([(i,j) in py_motif for i in py_members if i!=j]) for j in nconnected]) # predators for each prey of n 768 | mpredpreys=sorted([sum([(i,j) in py_motif for j in py_members if j!=i]) for i in mconnected]) # prey for each predator of m 769 | 770 | # One link has both pred and prey with nonunique roles. 771 | key = (id, (npred1, nprey1,tuple(npreypreds)),(npred2,nprey2,tuple(mpredpreys))) 772 | # One link has only non-unique predator 773 | if key not in possible_linkroles: 774 | key= (id, (npred1, nprey1,tuple(npreypreds)),(npred2,nprey2)) 775 | # One link has only non-unique prey 776 | if key not in possible_linkroles: 777 | key = (id, (npred1, nprey1),(npred2,nprey2,tuple(mpredpreys))) 778 | 779 | if key not in possible_linkroles: 780 | print >> sys.stderr, key 781 | print >> sys.stderr, "Apparently there is a link you aren't accounting for in roles.py." 782 | 783 | try: 784 | roles.links[(n,m)].roles[key] += 1 785 | except KeyError: 786 | roles.links[(n,m)].roles[key] = 1 787 | 788 | if roles.weighted: 789 | try: 790 | roles.links[(n,m)].weighted_roles[key] += weight_motif 791 | except KeyError: 792 | roles.links[(n,m)].weighted_roles[key] = weight_motif 793 | 794 | actual_linkroles.add(key) 795 | 796 | am_l = am_l.next 797 | 798 | r_l = r_l.next 799 | 800 | cmfinder.res_tbl_mem_free_single(results) 801 | 802 | if not allroles: 803 | possible_roles = actual_roles 804 | if links: 805 | possible_linkroles = actual_linkroles 806 | 807 | 808 | for n in roles.nodes: 809 | for r in possible_roles: 810 | try: 811 | x = roles.nodes[n].roles[r] 812 | except KeyError: 813 | roles.nodes[n].roles[r] = 0 814 | 815 | if roles.weighted: 816 | try: 817 | x = roles.nodes[n].weighted_roles[r] 818 | except KeyError: 819 | roles.nodes[n].weighted_roles[r] = 0 820 | 821 | if links: 822 | for n in roles.links: 823 | for r in possible_linkroles: 824 | try: 825 | x = roles.links[n].roles[r] 826 | except KeyError: 827 | roles.links[n].roles[r] = 0 828 | 829 | if roles.weighted: 830 | try: 831 | x = roles.links[n].weighted_roles[r] 832 | except KeyError: 833 | roles.links[n].weighted_roles[r] = 0 834 | 835 | return roles 836 | 837 | 838 | 839 | ############################################################## 840 | ############################################################## 841 | # RUN IT ALL! 842 | ############################################################## 843 | ############################################################## 844 | 845 | def pymfinder(network, 846 | links=False, 847 | motifsize = 3, 848 | stoufferIDs = False, 849 | allmotifs = False, 850 | nrandomizations = 0, 851 | randomize = False, 852 | usemetropolis = False, 853 | networktype = "unipartite", 854 | weighted = False 855 | ): 856 | 857 | 858 | stats = motif_participation(network, 859 | links = links, 860 | motifsize = motifsize, 861 | randomize = randomize, 862 | usemetropolis = usemetropolis, 863 | stoufferIDs = stoufferIDs, 864 | allmotifs = allmotifs, 865 | weighted = weighted) 866 | 867 | stats = motif_roles(stats, 868 | links = links, 869 | motifsize = motifsize, 870 | randomize = False, 871 | usemetropolis = usemetropolis, 872 | stoufferIDs = stoufferIDs, 873 | networktype = networktype, 874 | allroles = allmotifs, 875 | weighted = weighted) 876 | 877 | if nrandomizations != 0: 878 | stats = motif_structure(stats, 879 | motifsize = motifsize, 880 | nrandomizations = nrandomizations, 881 | usemetropolis = usemetropolis, 882 | stoufferIDs = stoufferIDs, 883 | weighted = weighted) 884 | 885 | 886 | 887 | return stats 888 | 889 | ############################################################## 890 | ############################################################## 891 | # C'est fini 892 | ############################################################## 893 | ############################################################## 894 | -------------------------------------------------------------------------------- /pymfinder/roles.py: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | ############################################################## 3 | # USEFUL GLOBAL VARIABLES 4 | ############################################################## 5 | ############################################################## 6 | 7 | STOUFFER_MOTIF_IDS = {12: 'S1', 8 | 38: 'S2', 9 | 98: 'S3', 10 | 36: 'S4', 11 | 6: 'S5', 12 | 46: 'D1', 13 | 108: 'D2', 14 | 14: 'D3', 15 | 74: 'D4', 16 | 102: 'D5', 17 | 238: 'D6', 18 | 110: 'D7', 19 | 78: 'D8', 20 | } 21 | 22 | #key = (npred,nprey) 23 | STOUFFER_ROLE_IDS = dict(zip([(12, 0, 1), 24 | (12, 1, 1), 25 | (12, 1, 0), 26 | (38, 0, 2), 27 | (38, 1, 1), 28 | (38, 2, 0), 29 | (98, 1, 1), 30 | (36, 0, 1), 31 | (36, 2, 0), 32 | (6, 0, 2), 33 | (6, 1, 0), 34 | (46, 1, 2), 35 | (46, 2, 0), 36 | (108, 0, 2), 37 | (108, 2, 1), 38 | (14, 1, 2), 39 | (14, 1, 1), 40 | (14, 1, 0), 41 | (74, 0, 1), 42 | (74, 1, 1), 43 | (74, 2, 1), 44 | (102, 1, 1), 45 | (102, 2, 1), 46 | (102, 1, 2), 47 | (238, 2, 2), 48 | (110, 1, 2), 49 | (110, 2, 1), 50 | (110, 2, 2), 51 | (78, 1, 1), 52 | (78, 2, 2),], 53 | range(30) 54 | ) 55 | ) 56 | 57 | #key = size:(motif_id, (npred,nprey)) 58 | UNIPARTITE_ROLES = {2:[(2, [(0, 1), 59 | (1, 0), 60 | ]), 61 | (6, [(1, 1), 62 | ]), 63 | ], 64 | 65 | 3:[(12, [(0, 1), 66 | (1, 1), 67 | (1, 0), 68 | ]), 69 | (38, [(0, 2), 70 | (2, 0), 71 | (1, 1), 72 | ]), 73 | (98, [(1, 1), 74 | ]), 75 | (36, [(0, 1), 76 | (2, 0), 77 | ]), 78 | (6, [(1, 0), 79 | (0, 2), 80 | ]), 81 | (46, [(1, 2), 82 | (2, 0), 83 | ]), 84 | (108, [(2, 1), 85 | (0, 2), 86 | ]), 87 | (14, [(1, 1), 88 | (1, 0), 89 | (1, 2), 90 | ]), 91 | (74, [(2, 1), 92 | (0, 1), 93 | (1, 1), 94 | ]), 95 | (102, [(1, 2), 96 | (1, 1), 97 | (2, 1), 98 | ]), 99 | (238, [(2, 2), 100 | ]), 101 | (110, [(1, 2), 102 | (2, 2), 103 | (2, 1), 104 | ]), 105 | (78, [(1, 1), 106 | (2, 2), 107 | ]), 108 | ], 109 | } 110 | 111 | #key as for positions but with two species (eaten by,eats) ((eater),(eaten))) 112 | UNIPARTITE_LINKS_ROLES = {2:[(2, [((0,1),(1,0)),]), 113 | (6, [((1,1),(1,1)),]), 114 | ], 115 | 116 | 3:[ 117 | (6, [((0, 2),(1, 0)), 118 | ]), 119 | (12, [((0, 1),(1, 1)), 120 | ((1, 1),(1, 0)), 121 | ]), 122 | (14, [((1, 2),(1, 1)), 123 | ((1, 2),(1, 0)), 124 | ]), 125 | (36, [((0, 1),(2, 0)), 126 | ]), 127 | (38, [((0, 2),(1, 1)), 128 | ((1, 1),(2, 0)), 129 | ((0, 2),(2, 0)), 130 | ]), 131 | (46, [((1, 2),(2, 0)), 132 | ((1, 2),(1, 2)), 133 | ]), 134 | (74, [((0, 1),(2, 1)), 135 | ((1, 1),(2, 1)), 136 | ]), 137 | (78, [((1, 1),(2, 2)), 138 | ]), 139 | (98, [((1, 1),(1, 1)), 140 | ]), 141 | (102, [((1, 1),(2, 1)), 142 | ((1, 2),(2, 1)), 143 | ((1, 2),(1, 1)), 144 | ]), 145 | (108, [((0, 2),(2, 1)), 146 | ((2, 1),(2, 1)), 147 | ]), 148 | (110, [((1, 2),(2, 1)), 149 | ((1, 2),(2, 2)), 150 | ((2, 2),(2, 1)), 151 | ]), 152 | (238, [((2, 2),(2, 2)), 153 | ]), 154 | ], 155 | } 156 | 157 | #key = size:(motif_id, (npred,nprey,(degrees of preds, degrees of prey))) 158 | BIPARTITE_ROLES = {2:[(2, [(0, 1), 159 | (1, 0), 160 | ]), 161 | ], 162 | 163 | 3:[(36, [(0, 1), 164 | (2, 0), 165 | ]), 166 | (6, [(0, 2), 167 | (1, 0), 168 | ]), 169 | ], 170 | 171 | 4:[(2184, [(0, 1), 172 | (3, 0), 173 | ]), 174 | (14, [(0, 3), 175 | (1, 0), 176 | ]), 177 | (76, [(0, 1), 178 | (2, 0), 179 | (0, 2), 180 | (1, 0), 181 | ]), 182 | (204, [(2, 0), 183 | (0, 2), 184 | ]), 185 | ], 186 | 187 | 5:[(541200, [(0, 1), 188 | (4, 0), 189 | ]), 190 | (30, [(0, 4), 191 | (1, 0), 192 | ]), 193 | (8728, [(0, 1), 194 | (0, 2), 195 | (2, 0), 196 | ]), 197 | (404, [(0, 2), 198 | (1, 0), 199 | (2, 0), 200 | ]), 201 | (8472, [(0, 2), 202 | (0, 1), 203 | (1, 0), 204 | (3, 0), 205 | ]), 206 | (156, [(0, 3), 207 | (0, 1), 208 | (1, 0), 209 | (2, 0), 210 | ]), 211 | (8984, [(0, 2), 212 | (0, 1), 213 | (2, 0), 214 | (3, 0), 215 | ]), 216 | (412, [(0, 3), 217 | (0, 2), 218 | (1, 0), 219 | (2, 0), 220 | ]), 221 | (25368, [(0, 2), 222 | (3, 0), 223 | ]), 224 | (924, [(0, 3), 225 | (2, 0), 226 | ]), 227 | ], 228 | 229 | 6:[(545392672, [(0, 1), 230 | (5, 0), 231 | ]), 232 | (62, [(0, 5), 233 | (1, 0), 234 | ]), 235 | (4261936, [(0, 1, (2,)), 236 | (0, 2), 237 | (0, 1, (3,)), 238 | (2, 0), 239 | (3, 0), 240 | ]), 241 | (820, [(0, 2), 242 | (0, 3), 243 | (1, 0, (2,)), 244 | (2, 0), 245 | (1, 0, (3,)), 246 | ]), 247 | (4260912, [(0, 2), 248 | (0, 1), 249 | (1, 0), 250 | (4, 0), 251 | ]), 252 | (316, [(0, 1), 253 | (0, 4), 254 | (2, 0), 255 | (1, 0), 256 | ]), 257 | (4262960, [(0, 1), 258 | (0, 2), 259 | (4, 0), 260 | (2, 0), 261 | ]), 262 | (828, [(0, 2), 263 | (0, 4), 264 | (2, 0), 265 | (1, 0), 266 | ]), 267 | (4328496, [(0, 1), 268 | (0, 2), 269 | (3, 0), 270 | ]), 271 | (1836, [(0, 3), 272 | (1, 0), 273 | (2, 0), 274 | ]), 275 | (4394032, [(0, 2), 276 | (0, 1), 277 | (3, 0), 278 | (4, 0), 279 | ]), 280 | (1852, [(0, 3), 281 | (0, 4), 282 | (2, 0), 283 | (1, 0), 284 | ]), 285 | (12782640, [(0, 2), 286 | (4, 0), 287 | ]), 288 | (3900, [(0, 4), 289 | (2, 0), 290 | ]), 291 | (34352, [(0, 2, (1,2,)), 292 | (0, 2, (2,2,)), 293 | (0, 1), 294 | (1, 0), 295 | (2, 0, (2,2,)), 296 | (2, 0, (1,2,)), 297 | ]), 298 | (33848, [(0, 1), 299 | (0, 3), 300 | (2, 0), 301 | (1, 0), 302 | ]), 303 | (34344, [(0, 2), 304 | (0, 1), 305 | (1, 0), 306 | (3, 0), 307 | ]), 308 | (33336, [(0, 1), 309 | (0, 3), 310 | (3, 0), 311 | (1, 0), 312 | ]), 313 | (99880, [(0, 2, (1,3,)), 314 | (0, 2, (2,3,)), 315 | (1, 0), 316 | (3, 0), 317 | (2, 0), 318 | ]), 319 | (34360, [(0, 1), 320 | (0, 2), 321 | (0, 3), 322 | (3, 0), 323 | (2, 0), 324 | (1, 0), 325 | ]), 326 | (35896, [(0, 2), 327 | (0, 3), 328 | (0, 1), 329 | (2, 0, (2,3,)), 330 | (2, 0, (1,3,)), 331 | ]), 332 | (100912, [(0, 2), 333 | (2, 0), 334 | ]), 335 | (36408, [(0, 1), 336 | (0, 3), 337 | (3, 0), 338 | (2, 0), 339 | ]), 340 | (99896, [(0, 3), 341 | (0, 2), 342 | (1, 0), 343 | (3, 0), 344 | ]), 345 | (100920, [(0, 2), 346 | (0, 3), 347 | (2, 0), 348 | (3, 0), 349 | ]), 350 | (101944, [(0, 3), 351 | (0, 2), 352 | (2, 0), 353 | (3, 0), 354 | ]), 355 | (233016, [(0, 3), 356 | (3, 0), 357 | ]), 358 | ], 359 | } 360 | 361 | 362 | BIPARTITE_LINKS_ROLES = {2:[(2, [((0,1),(1,0)),])], 363 | 3:[(36, [((0,1),(2,0)),]), 364 | (6, [((0,2),(1,0)),]), 365 | ], 366 | 4:[ # (pred, prey) ((npred,nprey)) 367 | (14, [((0, 3),(1, 0)),]), # One link in the fan with 1 animal, 3 plants 368 | (76, [((0,1),(2,0)), 369 | ((0,2),(2,0)), 370 | ((0,2),(1,0)),]), # 3 links in the N 371 | (204, [((0,2),(2,0)),]), # One link in the X 372 | (2184, [((0, 1),(3, 0)),]), # One link in the fan with 3 animals, 1 plant 373 | ], 374 | 5:[ 375 | (30, [((0, 4),(1, 0)),]), 376 | (156, [((0, 1),(2, 0)), 377 | ((0, 3),(2, 0)), 378 | ((0, 3),(1, 0)),]), 379 | (404, [((0, 2),(1, 0)), 380 | ((0, 2),(2, 0)),]), 381 | (412, [((0, 2),(2, 0)), 382 | ((0, 3),(2, 0)), 383 | ((0, 3),(1, 0)),]), 384 | (924, [((0, 3),(2, 0)),]), 385 | (8472, [((0, 1),(3, 0)), 386 | ((0, 2),(3, 0)), 387 | ((0, 2),(1, 0)),]), 388 | (8728, [((0, 1),(2, 0)), 389 | ((0, 2),(2, 0)),]), 390 | (8984, [((0, 1),(3, 0)), 391 | ((0, 2),(3, 0)), 392 | ((0, 2),(2, 0)),]), 393 | (25368, [((0, 2),(3, 0)),]), 394 | (541200, [((0, 1),(4, 0)),]), 395 | ], 396 | 6:[ (62, [((0, 5),(1, 0)),]), 397 | (316, [((0, 1),(2, 0)), 398 | ((0, 4),(2, 0)), 399 | ((0, 4),(1, 0)),]), 400 | (820, [((0, 2), (1, 0)), 401 | ((0, 3), (1, 0)), 402 | ((0, 2),(2, 0)), 403 | ((0, 3),(2, 0)), 404 | ]), 405 | (828, [((0, 2),(2, 0)), 406 | ((0, 4),(2, 0)), 407 | ((0, 4),(1, 0)),]), 408 | (1836, [((0, 3),(1, 0)), 409 | ((0, 3),(2, 0)),]), 410 | (1852, [((0, 3),(2, 0)), 411 | ((0, 4),(2, 0)), 412 | ((0, 4),(1, 0)),]), 413 | (3900, [((0, 4),(2, 0)),]), 414 | (33336, [((0, 1),(3, 0)), 415 | ((0, 3),(3, 0)), 416 | ((0, 3),(1, 0)),]), 417 | (33848, [((0, 1),(2, 0)), 418 | ((0, 3),(2, 0)), 419 | ((0, 3),(1, 0)),]), 420 | (34344, [((0, 1),(3, 0)), 421 | ((0, 2),(3, 0)), 422 | ((0, 2),(1, 0)),]), 423 | (34352, [#((2, 0), (0, 2)), # This covers 2 unique roles 424 | ((0, 1), (2, 0)), 425 | ((0, 2), (1, 0)), 426 | ((0, 2, (2,2)),(2, 0, (1,2))), 427 | ((0, 2, (2,2)),(2, 0, (2,2))), 428 | ((0, 2,(1,2)),(2, 0, (2,2))), 429 | ]), 430 | (34360, [((0, 1),(3, 0)), 431 | ((0, 2),(3, 0)), 432 | ((0, 2),(2, 0)), 433 | ((0, 3),(3, 0)), 434 | ((0, 3),(2, 0)), 435 | ((0, 3),(1, 0)),]), 436 | (35896, [((0, 1), (2, 0)), 437 | ((0, 2), (2, 0)), 438 | #((2, 0), (0, 3)), # Also covers 2 unique roles 439 | ((0, 3),(2, 0, (1,3,))), 440 | ((0, 3),(2, 0, (2,3,))), 441 | ]), 442 | (36408, [((0, 1),(3, 0)), 443 | ((0, 3),(3, 0)), 444 | ((0, 3),(2, 0)),]), 445 | (99880, [ 446 | ((0,2), (1,0)), 447 | ((0,2), (2,0)), 448 | #((3, 0), (0, 2)), # Also covers 2 unique roles 449 | ((0, 2, (1,3)),(3, 0)), 450 | ((0, 2, (2,3)),(3, 0)), 451 | ]), 452 | (99896, [((0, 2),(3, 0)), 453 | ((0, 3),(3, 0)), 454 | ((0, 3),(1, 0)),]), 455 | (100912, [((0, 2),(2, 0)),]), 456 | (100920, [((0, 2),(2, 0)), 457 | ((0, 2),(3, 0)), 458 | ((0, 3),(2, 0)), 459 | ((0, 3),(3, 0)),]), 460 | (101944, [((0, 3),(2, 0)), 461 | ((0, 3),(3, 0)), 462 | ((0, 2),(2, 0)), 463 | ((0, 2),(3, 0)),]), 464 | (233016, [((0, 3),(3, 0)),]), 465 | (4260912, [((0, 2),(1, 0)), 466 | ((0, 2),(4, 0)), 467 | ((0, 1),(4, 0)),]), 468 | (4261936, [((0, 1), (2, 0)), 469 | ((0, 1), (3, 0)), 470 | ((0, 2),(2, 0)), 471 | ((0, 2),(3, 0)),]), 472 | (4262960, [((0, 1),(4, 0)), 473 | ((0, 2),(4, 0)), 474 | ((0, 2),(2, 0)),]), 475 | (4328496, [((0, 1),(3, 0)), 476 | ((0, 2),(3, 0)),]), 477 | (4394032, [((0, 2),(3, 0)), 478 | ((0, 2),(4, 0)), 479 | ((0, 1),(4, 0)),]), 480 | (12782640, [((0, 2),(4, 0)),]), 481 | (545392672, [((0, 1),(5, 0)),]), 482 | ], 483 | } 484 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | 2 | from setuptools import setup, Extension, find_packages 3 | 4 | ############################################################################# 5 | ### check for Python.h 6 | ############################################################################# 7 | from distutils.command.config import config as _config 8 | 9 | # a faux config command that checks for the Python.h header file 10 | class config(_config): 11 | def run(self): 12 | self.check_python_dev() 13 | _config.run(self) 14 | 15 | def check_python_dev(self): 16 | from distutils import sysconfig 17 | ok = self.check_header('Python.h',include_dirs=[sysconfig.get_python_inc()]) 18 | if not ok: 19 | from distutils.errors import DistutilsPlatformError 20 | errmsg = ("The compiler cannot find the 'Python.h' header file.\n" 21 | "Please check your configuration to see if you have python-dev installed.") 22 | raise DistutilsPlatformError(errmsg) 23 | 24 | # a faux build_ext command that calls the faux config command 25 | from distutils.command.build_ext import build_ext as _build_ext 26 | class build_ext(_build_ext): 27 | def run(self): 28 | self.run_command('config') 29 | _build_ext.run(self) 30 | 31 | ############################################################################# 32 | ### define the C extension for the original mfinder code 33 | ############################################################################# 34 | mfinder = Extension('_mfinder', 35 | sources=['/'.join(['pymfinder','mfinder',f]) \ 36 | for f in ['clustering.c', 37 | 'globals.c', 38 | 'grassberger.c', 39 | 'hash.c', 40 | 'list.c', 41 | 'mat.c', 42 | 'metropolis.c', 43 | 'motif_ids.c', 44 | 'output.c', 45 | 'permutation.c', 46 | 'prob.c', 47 | 'random.c', 48 | 'results.c', 49 | 'role.c', 50 | 'stubs.c', 51 | 'switches.c', 52 | 'wrapper.c', 53 | #'mfinder.i', # not required unless the user modifies the swig interface 54 | 'mfinder_wrap.c', # preferred since the user does not need to use swig directly 55 | ] 56 | ], 57 | define_macros=[('UNIX', None),], 58 | extra_compile_args = ["-O3",], 59 | ) 60 | 61 | ############################################################################# 62 | #### the pymfinder setup 63 | ############################################################################# 64 | setup( 65 | name = "pymfinder", 66 | version = "1.0", 67 | description = "Python wrapper for mfinder 1.2", 68 | author = "Daniel B. Stouffer", 69 | author_email = "daniel.stouffer@canterbury.ac.nz", 70 | url = 'http://github.com/stoufferlab/pymfinder', 71 | packages = find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]), 72 | ext_package = 'pymfinder.mfinder', 73 | ext_modules = [mfinder,], 74 | cmdclass={'build_ext': build_ext, 75 | 'config': config, 76 | }, 77 | test_suite = 'tests.test_pymfinder', 78 | ) 79 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoufferlab/pymfinder/e1791deb775d8dffbeaad6867b180d2bb042e9bd/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_pymfinder.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | 4 | from pymfinder import pymfinder 5 | 6 | links_per_motif={ 7 | 2:{2:1,6:2}, # One-way motif, two-way motif 8 | 3:{12:2,38:3,98:3,36:2,6:2, # One-way motifs only 9 | 46:4,108:4,14:3,74:3,102:4,238:6,110:5,78:4} #Motifs with 2-way ints 10 | } 11 | 12 | bipartite_links_per_motif={ 13 | 2:{2:1}, 14 | 3:{6:2, 36:2}, 15 | 4:{14:3, 76:3, 204:4, 2184:3}, 16 | 5:{30:4, 156:4, 404:4, 412:5, 924:6, 8472:4, 8728:4,8984:5,25368:6,541200:4}, 17 | 6:{62:5, 316:5, 820:5, 828:6, 1836:6, 1852:7, 3900:8, 33336:5, 33848:5, 34344:5, 34352:5, 34360:6, 35896:6, 36408:7, 99880:6, 99896:7, 100912:6, 100920:7, 101944:8, 233016:9, 4260912:5, 4261936:5, 4262960:6, 4328496:6, 4394032:7, 12782640:8, 545392672:5} } 18 | 19 | 20 | class pymfinderTestCase(unittest.TestCase): 21 | def setUp(self): 22 | import sys 23 | import os 24 | self.test_filename_u = [os.path.dirname(__file__) + "/../pymfinder/data/unipartite-"+str(x)+"-test.net" for x in range(2,4)] 25 | self.test_filename_b = [os.path.dirname(__file__) + "/../pymfinder/data/bipartite-"+str(x)+"-test.net" for x in range(2,7)] 26 | 27 | for x in range(0,2): 28 | print self.test_filename_u[x] 29 | try: 30 | with open(self.test_filename_u[x]) as file: 31 | pass 32 | except IOError: 33 | sys.stderr.write("Cannot find the test network 'unipartite-"+str(x+2)+"-test.net'.\n") 34 | sys.exit(1) 35 | 36 | for x in range(0,5): 37 | print self.test_filename_b[x] 38 | try: 39 | with open(self.test_filename_b[x]) as file: 40 | pass 41 | except IOError: 42 | sys.stderr.write("Cannot find the test network 'bipartite-"+str(x+2)+"-test.net'.\n") 43 | sys.exit(1) 44 | 45 | def test_unipartite_motif_structure(self): 46 | for i in range(0,2): 47 | result = pymfinder(self.test_filename_u[i], motifsize=i+2, networktype = "unipartite", nrandomizations=0, allmotifs=True) 48 | motifs=[result.motifs[n].real for n in result.motifs] 49 | self.assertTrue(motifs==[1]*len(motifs)) 50 | 51 | def test_unipartite_motif_weighted_structure(self): 52 | for i in range(0,2): 53 | result = pymfinder(self.test_filename_u[i], motifsize=i+2, networktype = "unipartite", nrandomizations=0, weighted=True, allmotifs=True) 54 | motifs=[int(result.motifs[n].mean_weight)==n for n in result.motifs.keys()] 55 | self.assertTrue(all(motifs)) 56 | 57 | def test_unipartite_motif_participation(self): 58 | for i in range(0,2): 59 | result = pymfinder(self.test_filename_u[i], motifsize=i+2, networktype = "unipartite", allmotifs=True,) 60 | all_roles = result.nodes[result.nodes.keys()[0]].motifs.keys() 61 | roles=[[result.nodes[n].motifs[r] for r in all_roles] for n in result.nodes] 62 | check_columns=[sum(x) for x in zip(*roles)]==[i+2]*len(all_roles) # Check the number of nodes in each motif 63 | check_rows=[sum(x) for x in roles]==[1]*len(result.nodes) # Check that each node is in only one motif 64 | self.assertTrue(check_columns and check_rows) 65 | 66 | def test_unipartite_motif_weighted_participation(self): 67 | for i in range(0,2): 68 | result = pymfinder(self.test_filename_u[i], motifsize=i+2, networktype = "unipartite", weighted=True, allmotifs=True) 69 | all_roles = result.nodes[result.nodes.keys()[0]].weighted_motifs.keys() 70 | roles=[[int(result.nodes[n].weighted_motifs[r]) for r in all_roles] for n in result.nodes] 71 | check_columns=[sum(x)/(i+2) for x in zip(*roles)]==all_roles # Check the number of nodes in each motif 72 | check_rows=[sum(x) for x in roles]==[int(result.nodes[x].id[:-1]) for x in result.nodes] # Check that each node is in only one motif 73 | self.assertTrue(check_columns and check_rows) 74 | 75 | def test_unipartite_link_participation(self): 76 | for i in range(0,2): 77 | result = pymfinder(self.test_filename_u[i], motifsize=i+2, networktype = "unipartite",links=True, allmotifs=True) 78 | all_roles = result.links[result.links.keys()[0]].motifs.keys() # List of motifs 79 | roles=[[result.links[n].motifs[r] for r in sorted(all_roles)] for n in result.links] # r are motifs, n are link tuples 80 | motiflist=sorted(result.motifs.keys()) # Need to keep these in the same order 81 | check_columns=[sum(x) for x in zip(*roles)]==[links_per_motif[i+2][motif] for motif in motiflist] # Each motif contains the number of links I think it should 82 | check_rows=[sum(x) for x in roles]==[1]*len(result.links) # Each link is in only one motif 83 | self.assertTrue(check_columns and check_rows) 84 | 85 | def test_bipartite_link_participation(self): 86 | for i in range(0,5): 87 | result = pymfinder(self.test_filename_b[i], motifsize=i+2, networktype = "bipartite",links=True, allmotifs=False) 88 | all_roles = result.links[result.links.keys()[0]].motifs.keys() # List of motifs 89 | roles=[[result.links[n].motifs[r] for r in sorted(all_roles)] for n in result.links] # r are motifs, n are link tuples 90 | motiflist=sorted(result.motifs.keys()) # Need to keep these in the same order 91 | check_columns=[sum(x) for x in zip(*roles)]==[bipartite_links_per_motif[i+2][motif] for motif in motiflist] # Each motif contains the number of links I think it should 92 | check_rows=[sum(x) for x in roles]==[1]*len(result.links) # Each link is in only one motif 93 | self.assertTrue(check_columns and check_rows) 94 | 95 | def test_unipartite_motif_roles(self): 96 | for i in range(0,2): 97 | result = pymfinder(self.test_filename_u[i], motifsize=i+2, networktype = "unipartite", allmotifs=True) 98 | all_roles = result.nodes[result.nodes.keys()[0]].roles.keys() 99 | roles=[[result.nodes[n].roles[r] for r in all_roles] for n in result.nodes] 100 | columns=[sum(x) for x in zip(*roles)] 101 | check_total_nodes=sum(columns)==3*13 or 2*2 102 | check_columns=any(v==0 for v in columns)==False 103 | check_rows=[sum(x) for x in roles]==[1]*len(result.nodes) 104 | self.assertTrue(check_columns and check_rows and check_total_nodes) 105 | 106 | def test_unipartite_link_roles(self): 107 | for i in range(0,2): 108 | result = pymfinder(self.test_filename_u[i], motifsize=i+2, networktype = "unipartite",links=True, allmotifs=True) 109 | all_roles = result.links[result.links.keys()[0]].roles.keys() 110 | roles=[[result.links[n].roles[r] for r in all_roles] for n in result.links] 111 | columns=[sum(x) for x in zip(*roles)] 112 | #Are there the number of links we think there are? 113 | check_total_links=sum(columns)==sum(links_per_motif[i+2].values()) 114 | check_columns=any(v==0 for v in columns)==False # Every link has a role? 115 | check_rows=[sum(x) for x in roles]==[1]*len(result.links) # Every link is in one position only 116 | self.assertTrue(check_columns and check_rows and check_total_links) 117 | 118 | def test_bipartite_motif_roles(self): 119 | for i in range(0,5): 120 | result = pymfinder(self.test_filename_b[i], motifsize=i+2, networktype = "bipartite", allmotifs=False) 121 | all_roles = result.nodes[result.nodes.keys()[0]].roles.keys() 122 | roles=[[result.nodes[n].roles[r] for r in all_roles] for n in result.nodes] 123 | check_columns=any(v==0 for v in [ sum(x) for x in zip(*roles)])==False 124 | check_rows=[sum(x) for x in roles]==[1]*len(result.nodes) 125 | self.assertTrue(check_columns and check_rows) 126 | 127 | def test_bipartite_link_roles(self): 128 | for i in range(0,5): 129 | result = pymfinder(self.test_filename_b[i], motifsize=i+2, networktype = "bipartite", links=True, allmotifs=False) 130 | all_roles = result.links[result.links.keys()[0]].roles.keys() 131 | roles=[[result.links[n].roles[r] for r in all_roles] for n in result.links] 132 | columns=[sum(x) for x in zip(*roles)] 133 | #Are there the number of links we think there are? 134 | check_total_links=sum(columns)==sum(bipartite_links_per_motif[i+2].values()) 135 | check_columns=any(v==0 for v in columns)==False # Every link has a role? 136 | check_rows=[sum(x) for x in roles]==[1]*len(result.links) # Every link is in one position only 137 | self.assertTrue(check_columns and check_rows and check_total_links) 138 | 139 | 140 | 141 | def suite(): 142 | suite = unittest.TestLoader().loadTestsFromTestCase(pymfinderTestCase) 143 | return suite 144 | 145 | if __name__ == '__main__': 146 | unittest.TextTestRunner(verbosity=2).run(suite()) 147 | --------------------------------------------------------------------------------