Welcome to LoopDetect’s documentation!

LoopDetect provides functions to determine all feedback loops of an ordinary differential equation (ODE) system. The example workflow description shows how to use the provided functions, the glossary provides an overview over all functions.

Other implementations

This documentation is for the implementation in Python (Github: Source). For other programming languages, see:

LoopDetect.compare_loops(loop_list_a, loop_list_b, list_b_inds='True')

Compares two loop lists to find identical loops. Same node indices are considered to encode the same nodes in the compared loops. Sets of indices are returned.

Parameters
  • loop_list_a (pandas dataframe): loop list, i.e. pandas dataframe with columns loop, length, sign

  • loop_list_b (pandas dataframe): loop list, i.e. pandas dataframe with columns loop, length, sign

  • list_b_inds (boolean, optional): whether also the indices for the second list are computed (might take long)

Details

Loop lists could be generated from functions find_loops or find_loops_noscc. Indices of the loops are sorted internally with the function sort_loop_index() to start with the lowest node index and make comparison possible.

Returns

A dictionary containing five entries

  • ind_a_id: indices of the loops in the first loop list that occur identically in the second loop list

  • ind_a_switch: indices of the loops in the first loop list that occur in the second loop list with a different sign

  • ind_a_notin: indices of the loops in the first loop list that do not occur in the second loop list

  • ind_b_id: indices of loops in the second loop list corresponding to the loops reported in ind_a_id

  • ind_b_switch: indices of loops in the second loop list corresponding to loops reported in ind_a_switch.

See Also

find_loops, find_loops_noscc

Example

Comparing loop lists from two systems of size 4 with coinciding nodes:

#import the relevant packages 
import LoopDetect
import numpy as np
#define the Jacobian matrix as numpy array
jac = np.array([[-1,0,0,-1],[1,-1,0,1],[0,1,-1,0],[0,0,1,-1]])
#compute the loop list
loop_list = LoopDetect.find_loops(jac)
#define a slightly different Jacobian matrix
jac2 = np.array([[-1,0,0,0],[1,-1,0,-1],[0,1,1,0],[0,0,1,-1]])
#compute the loop list
loop_list2 = LoopDetect.find_loops(jac2)
#compare the loop lists
loop_compare = compare_loops(loop_list,loop_list2)
#get sublist of all loops that match
loop_list.iloc(loop_compare['ind_a_id'])
#get only loops in first list that match exactly a loop in the second list
loop_list.loop[loop_compare['ind_a_id']]
LoopDetect.find_edge(loop_list, source_node, target_node)

Reports which loops in a loop list contain a certain edge.

Parameters
  • loop_list (pandas dataframe): loop list as generated from find_loops, has to contain a column named ‘loop’

  • source_node (int): index of the source node of the edge

  • target_node (int): index of the target node of the edge

Returns

A list with Boolean values of the same length as the number of rows in the loop list. The values are True if the rows contain the edge, False if not.

See Also

find_loops, find_loops_noscc

Example

Finding all loops with an edge between species 0 and 1:

#import the relevant packages 
import LoopDetect
import numpy as np
#define the Jacobian matrix as numpy array
jac = np.array([[-1,0,0,-1],[1,-1,0,1],[0,1,-1,0],[0,0,1,-1]])
#compute the loop list
loop_list = LoopDetect.find_loops_noscc(jac)
#find loops containing the edge [0,1]
first_edge = LoopDetect.find_edge(loop_list,0,1)
#return the loops containing the edge
loop_list.iloc[first_edge]
LoopDetect.find_loops(jacobian, max_num_loops=100000)

Function to determine all feedback loops in an ordinary differential equation (ODE) model given by its Jacobian matrix. Strongly connected components are determined before cycle detection.

Parameters
  • jacobian (numpy array): matrix indicating the Jacobian of the ODE, \(J_ij = df_i/dx_j\).

  • max_num_loops (int, optional): positive integer (default: 1e5) giving the maximal number of reported feedback loops. Note that only up to max_num_loops feedback loops are returned (without warning).

Returns

A pandas dataframe: dataframe with the three columns “loop”, “length” and “sign” that contain the information on one feedback loop in each row. “loop” gives the order of the variables (indices) forming the loop as tuple, “length” indicates the number of participating species and “sign” is +1 or -1 indicating a positive or a negative loop, respectively.

Details

A feedback loop is a circular regulation without visiting any node twice. This function relies on the Python modules networkx to detect strongly connected components and simple cycles in the graph generated by the Jacobian matrix.

Example

Define the Jacobian matrix of a four-variable system (jac) and compute all feedback loops:

#import the relevant packages 
import LoopDetect
import numpy as np
#define the Jacobian matrix as numpy array
jac = np.array([[-1,0,0,-1],[1,-1,0,1],[0,1,-1,0],[0,0,1,-1]])
#compute the loop list
loop_list = LoopDetect.find_loops(jac)
LoopDetect.find_loops_noscc(jacobian, max_num_loops=100000)

Function to determine all feedback loops in an ordinary differential equation (ODE) model given by its Jacobian matrix. No strongly connected components are determined before cycle detection.

Parameters
  • jacobian (numpy array): matrix indicating the Jacobian of the ODE, \(J_ij = df_i/dx_j\).

  • max_num_loops (int, optional): positive integer (default: 1e5) giving the maximal number of reported feedback loops. Note that only up to max_num_loops feedback loops are returned (without warning).

Returns

A pandas dataframe: dataframe with the three columns “loop”, “length” and “sign” that contain the information on one feedback loop in each row. “loop” gives the order of the variables (indices) forming the loop as tuple, “length” indicates the number of participating species and “sign” is +1 or -1 indicating a positive or a negative loop, respectively.

Details

A feedback loop is a circular regulation without visiting any node twice. This function relies on the Python modules networkx to detect simple cycles in the graph generated by the Jacobian matrix.

See Also

find_loops

Example

Define the Jacobian matrix of a four-variable system (jac) and compute all feedback loops:

#import the relevant packages 
import LoopDetect
import numpy as np
#define the Jacobian matrix as numpy array
jac = np.array([[-1,0,0,-1],[1,-1,0,1],[0,1,-1,0],[0,0,1,-1]])
#compute the loop list
loop_list = LoopDetect.find_loops_noscc(jac)
LoopDetect.find_loops_vset(fun, vset, *args, numdiff_method='central', max_num_loops=100000, compute_full_list=True, **kwargs)

Determines loop lists for an ODE system given by a function and at multiple sets of variables. Loop lists are reported if signs of Jacobian matrix have changed.

Parameters
  • fun (function): function defining the ODE system, returns the vector \(dx/dt\) of derivatives of the variables as a numpy ndarray. The derivative is taken in direction of the first parameter of the function (i.e. \(x\) if the function returns \(dx/dt\)). It may depend on further parameters (defined in *args, **kwargs).

  • vset (list): list of lists or list of tuples of variable values at which the loops are determined.

  • *args Further parameters except variable values to the function fun.

  • numdiff_method (string, optional): central finite difference approach for derivative calculation (‘central’,default) or ‘complex’ for complex-step approach.

  • max_num_loops (int, optional): Positive numeric value indicating the maximal number of loops that are reported in a loop list. Defaults to \(10^5\).

  • compute_full_list (bool, optional): Logical value indicating whether for each Jacobian matrix with any different sign the loop list is computed (True, default), or whether further checks are performed to ensure that loops may be altered (see Details).

  • **kwargs: any number of further (named) parameters that are all used as input to the function fun.

Details

The Jacobian matrices are computed for each of the variable values defined in vset with the package numdifftools using the standard central finite difference approach or the complex-step approach, depending on the input numdiff_method. The complex-step will only deliver correct results if the function works with complex numbers and does not contain non-analytic parts such as min, max or abs. Please be aware that functions have to return numpy arrays! If compute_full_list is set to False, loop lists are not re-computed for Jacobians that clearly do not allow for altered loop lists. These two criteria are checked: (a) no new regulations appear, and (b) only signs of regulations are altered that are not member of any loop. Loop lists can still be identical for different Jacobians, e.g. if two sign switches occur that are both affecting the same loops.

Returns

dictionary: containing four entries:

  • loop_rep: List of loop lists (pandas dataframes).

  • loop_rep_index: Vector of integer numbers returning the index of the loop list in loop_rep belonging to each entry in vset.

  • jac_rep: List of signed Jacobian matrices.

  • jac_rep_index: Vector of integer numbers returning the index of the Jacobian matrix in jac_rep belonging to each entry in vset.

Details

If there is only one class of Jacobian matrix (i.e. the signs of the Jacobian matrix are the same for all entries in vset), loop_rep and jac_rep will have only one entry each. The number of entries for loop_rep_index and jac_rep_index corresponds to the length of vset. Only if compute_full_list is set to False, loop_rep can contain fewer elements than jac_rep, otherwise both have the same number of elements.

See Also

find_loops numdifftools.Jacobian

Examples

Perform the loop analysis for a bacterial cell cycle system:

#import the relevant packages 
import LoopDetect as ld
import numpy as np
#Note: the example function from the script func_li08.py is loaded together
#with the other functions from LoopDetect
#read in solutions from the data accompanying the package, file li08_solution.tsv
sols=ld.load_li08_sol()
sols_as_tuples=[tuple(sols.iloc[i,1:20]) for i in range(len(sols))] #removing the time column
#we reduce the loop lists as much as possible
loop_results = ld.find_loops_vset(ld.func_li08,vset=sols_as_tuples,numdiff_method='central',
        max_num_loops=100000,compute_full_list=False,t=0)
loop_results['loop_rep']

Perform the loop analysis for a simpler system with a function with more input parameters and defined in complex numbers:

#The example function func_POSm4_comp() is that of a 4-variable system and is supplied
#together with the other functions in LoopDetect.
#define 5 possible variables (4-variable-system) in as list, as tuples
vset_def = [f for f in zip([1,1,2,2,3],[0,1,2,3,4],[2,2,2,2,2],[3,0,1,2,3])]
#we compute the loop lists at parameter values klin = [1,2,3,4,5,6,7,8] (in *args) 
#and knonlin=[2,2] (as **kwargs) using complex step derivatives
loop_results = ld.find_loops_vset(ld.func_POSm4_comp,vset_def,[1,2,3,4,5,6,7,8],
        numdiff_method='complex',compute_full_list=True,knonlin=[2,2])
#please be aware that the function func_POSm4_comp defines complex values 
# (otherwise the Jacobian would be always zeros everywhere for numdiff_method='complex')
LoopDetect.loop_summary(loop_list, column_val='length')

Reports a summary of the loops in a loop list: numbers of positive (pos) loops or negative (neg) loops of a certain length

Parameters
  • loop_list (pandas dataframe): loop list as generated from find_loops, has to contain a column named ‘loop’

  • column_val (string, optional): if this is ‘length’ (default), the column names are the length, otherwise the sign of the loop are the columns

Returns

A pandas dataframe containing the counts of negative (neg), positive (pos) or all loops (total) subdivided by their length. Lengths that do not occur are omitted.

See Also

find_loops, find_loops_noscc

Example

Summarize a short loop list.:

#import the relevant packages 
import LoopDetect
import numpy as np
#define the Jacobian matrix as numpy array
jac = np.array([[-1,0,0,-1],[1,-1,0,1],[0,1,-1,0],[0,0,1,-1]])
#compute the loop list
loop_list = LoopDetect.find_loops_noscc(jac)
#determine summary
sum_tab = loop_summary(loop_list)
LoopDetect.sort_loop_index(loop_list)

Sort all loops in a loop list such that they start with the node with the smallest index. This is a helper function for comparing loop lists.

Parameters
  • loop_list (pandas dataframe): loop list as generated from find_loops, has to contain a column named ‘loop’

Returns
  • pandas dataframe containing the sorted list of loops

See Also

find_loops, find_loops_noscc

Example

Create a new loop list with sorted entries (starting from the smalles node index).:

#import the relevant packages 
        import LoopDetect
        import numpy as np
        #define the Jacobian matrix as numpy array
        jac = np.array([[-1,0,0,-1],[1,-1,0,1],[0,1,-1,0],[0,0,1,-1]])
        #compute the loop list
        loop_list = find_loops(jac)
        #manipulate the second loop to start with a different entry than the smallest
        loop_list.loop[1]=tuple([2,3,1,3])
        #sort loop order
        sorted_loop_list = LoopDetect.sort_loop_index(loop_list)
func_li08.func_li08(x, t)

example function: bacterial cell cycle [modelwtin(t,y), Li et al. 2008]

Parameters
  • x (numpy array, list, tuple): numerical of length 18, ordered input of the variable values

  • t (float): time variable. Note that the function is independent from time.

Returns

A numpy array of length 18 containing the temporal derivative of the 18 variables.

Details

This is a function encoding an ordinary differential equation model that delivers the dynamics of the Caulobacter cell cycle. Note that to obtain the solution as published, also events have to be considered, i.e. certain conditions lead to a change in certain variable values; see Li et al., 2008 for details.

Reference

Li S, Brazhnik P, Sobral B, Tyson JJ. A Quantitative Study of the Division Cycle of Caulobacter crescentus Stalked Cells. Plos Comput Biol. 2008;4(1):e9.

func_li08.load_li08_sol()

Loads solutions for an example function of the bacterial cell cycle, Li et al. 2008, as dataframe.

Returns

A pandas dataframe that provides the solution for 18 species over time (roughly 3 cycles, up to 360 minutes, 634 time points in between). It contains the following columns:

  • time, y1=x0, y2=x1,…, y18=x17

All are numbers. Time is given in minutes.

Reference

Li S, Brazhnik P, Sobral B, Tyson JJ. A Quantitative Study of the Division Cycle of Caulobacter crescentus Stalked Cells. Plos Comput Biol. 2008;4(1):e9.

func_POSm4.func_POSm4(x, klin, knonlin)

example function: chain model with positive feedback regulation as from Baum et al., 2016

::Parameters:

  • x (numpy array, list, tuple): numerical, ordered values of length 4; these are the variable values.

  • klin: (numpy array, list, tuple): numerical, ordered values of length 8; these are some of the kinetic parameters of the model

  • knonlin:

Returns

A numpy array of length 4 that contains the time-derivatives of the four variables.

Details

It is a function delivering an ordinary differential equation system with chain structure with 4 species and a positive feedback regulation from the last species on the conversion between species 1 and 2. The system can give rise to oscillations; see Baum et al., 2016 for details.

Reference

Baum K, Politi AZ, Kofahl B, Steuer R, Wolf J: Feedback, Mass Conservation and Reaction Kinetics Impact the Robustness of Cellular Oscillationss. Plos Comput Biol. 2016;12(12):e1005298.

func_POSm4.func_POSm4_comp(x, klin, knonlin)

example function: complex-valued chain model with positive feedback regulation as from Baum et al., 2016

Parameters
  • x (numpy array, list, tuple): numerical, ordered values of length 4; these are the variable values.

  • klin: (numpy array, list, tuple): numerical, ordered values of length 8; these are some of the kinetic parameters of the model

  • knonlin:

Returns

A complex-valued numpy array of length 4 that contains the time-derivatives of the four variables.

Details

This function is the same as func_POSm4(), only that the output is complex. Thus, it can be used with complex-step derivatives. It is a function delivering an ordinary differential equation system with chain structure with 4 species and a positive feedback regulation from the last species on the conversion between species 1 and 2. The system can give rise to oscillations; see Baum et al., 2016 for details.

Reference

Baum K, Politi AZ, Kofahl B, Steuer R, Wolf J: Feedback, Mass Conservation and Reaction Kinetics Impact the Robustness of Cellular Oscillationss. Plos Comput Biol. 2016;12(12):e1005298.