Generate
This module provides functions for generating random Boolean functions and Boolean networks with specified structural and dynamical properties.
The generate module enables the systematic creation of
Boolean functions and networks that satisfy particular constraints, such as
specified canalization depth, sensitivity range, bias, or connectivity.
Generated instances can be used for statistical analysis, benchmarking, or
simulation studies.
Several generation routines leverage Numba acceleration for efficient sampling and evaluation of large function spaces. While Numba is recommended to achieve near-native performance, it is not required for functionality; all functions have pure Python fallbacks.
This module complements boolean_function and
boolean_network by facilitating reproducible generation of
synthetic test cases and large ensembles of random networks.
Example
>>> from boolforge import generate
>>> generate.random_function(n=3)
>>> str(generate.random_network(N=5, n=2))
- boolforge.generate.random_function(n: int, depth: int = 0, EXACT_DEPTH: bool = False, UNIFORM_STRUCTURE: bool = True, layer_structure: list[int] | None = None, PARITY: bool = False, ALLOW_DEGENERATE_FUNCTIONS: bool = False, bias: float = 0.5, absolute_bias: float = 0, USE_ABSOLUTE_BIAS: bool = False, hamming_weight: int | None = None, *, rng=None) BooleanFunction[source]
Generate a random Boolean function under flexible structural constraints.
This function acts as a high-level generator that unifies several common ensembles of Boolean functions, including parity functions, canalizing functions of specified depth or layer structure, functions with fixed Hamming weight, and biased random functions. The first applicable generation rule (in the order described below) is applied.
Selection logic (first applicable rule is used)
If
PARITYis True, return a random parity function (seerandom_parity_function).Else, if
layer_structureis provided, return a Boolean function with the specified canalizing layer structure usingrandom_k_canalizing_function_with_specific_layer_structure. Exactness of the canalizing depth is controlled byEXACT_DEPTH.Else, if
depth > 0, return a k-canalizing function withk = min(depth, n)usingrandom_k_canalizing_function. IfEXACT_DEPTHis True, the function has exactly this depth; otherwise, its canalizing depth is at leastk.If
UNIFORM_STRUCTUREis True, canalizing layer structures are sampled uniformly at random (up to the imposed constraints). If False, canalized outputs are sampled independently and uniformly as bitstrings, which biases the distribution toward more symmetric layer structures.Else, if
hamming_weightis provided, repeatedly sample Boolean functions with the specified Hamming weight until additional constraints implied byEXACT_DEPTHandALLOW_DEGENERATE_FUNCTIONSare satisfied.Else, generate a random Boolean function using a Bernoulli model with either:
fixed bias
bias, oran automatically chosen bias determined by
absolute_biasifUSE_ABSOLUTE_BIASis True.
Additional constraints on canalization and degeneracy are enforced depending on
EXACT_DEPTHandALLOW_DEGENERATE_FUNCTIONS.
Parameters
- nint
Number of input variables. Must be a positive integer.
- depthint, optional
Requested canalizing depth. Used only if
layer_structureis None anddepth > 0. IfEXACT_DEPTHis True, the function has exactly this canalizing depth (clipped atn); otherwise, its depth is at leastdepth. Default is 0.- EXACT_DEPTHbool, optional
Enforce exact canalizing depth where applicable. If
depth == 0, settingEXACT_DEPTH=Trueenforces that the function is non-canalizing. Default is False.- UNIFORM_STRUCTUREbool, optional
If True (default), canalizing layer structures are sampled uniformly at random in canalizing-function branches. If False, canalized outputs are sampled independently as bitstrings, inducing a bias toward more symmetric structures.
- layer_structurelist[int] or None, optional
Explicit canalizing layer structure
[k1, ..., kr]. If provided, this takes precedence overdepth. Default is None.- PARITYbool, optional
If True, ignore all other options and return a random parity function. Default is False.
- ALLOW_DEGENERATE_FUNCTIONSbool, optional
If True, functions with non-essential variables may be returned in random-generation branches. If False, non-degenerate functions are enforced whenever possible. Default is False.
- biasfloat, optional
Probability of a 1 when sampling truth-table entries independently. Used only if
USE_ABSOLUTE_BIASis False and no other branch applies. Must lie in[0, 1]. Default is 0.5.- absolute_biasfloat, optional
Absolute deviation from 0.5 used to determine the bias when
USE_ABSOLUTE_BIASis True. The bias is chosen uniformly from{0.5*(1 - absolute_bias), 0.5*(1 + absolute_bias)}. Must lie in[0, 1]. Default is 0.- USE_ABSOLUTE_BIASbool, optional
If True, ignore
biasand determine the bias usingabsolute_bias. Default is False.- hamming_weightint or None, optional
If provided, enforce that the Boolean function has exactly this many ones in its truth table. Additional constraints are enforced depending on
EXACT_DEPTHandALLOW_DEGENERATE_FUNCTIONS. Default is None.- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
A randomly generated Boolean function of arity
n.
Raises
- TypeError
If parameters have invalid types.
- ValueError
If parameter values or combinations are invalid.
Notes
For any fixed combination of parameters, this function samples uniformly at random from the set of Boolean functions satisfying the corresponding constraints. Non-uniformity arises only when explicitly requested via
UNIFORM_STRUCTURE=False.Extremely biased functions are often degenerate or highly canalizing; under restrictive parameter choices, some branches may reject repeatedly before returning a valid function.
Examples
>>> # Unbiased, non-degenerate random function >>> f = random_function(n=3)
>>> # Function with canalizing depth at least 2 >>> f = random_function(n=5, depth=2)
>>> # Function with exact canalizing depth 2 >>> f = random_function(n=5, depth=2, EXACT_DEPTH=True)
>>> # Function with a specific canalizing layer structure >>> f = random_function(n=6, layer_structure=[2, 1])
>>> # Parity function >>> f = random_function(n=4, PARITY=True)
>>> # Fixed Hamming weight with non-canalizing and non-degenerate constraints >>> f = random_function( ... n=5, ... hamming_weight=10, ... EXACT_DEPTH=True, ... ALLOW_DEGENERATE_FUNCTIONS=False ... )
- boolforge.generate.random_function_with_bias(n: int, bias: float = 0.5, *, rng=None) BooleanFunction[source]
Generate a random Boolean function with a specified bias.
The Boolean function is represented by its truth table of length
2**n, where each entry is independently set to 1 with probabilitybiasand to 0 otherwise.Parameters
- nint
Number of Boolean variables.
- biasfloat, optional
Probability that a given truth-table entry equals 1. Default is 0.5.
- rngint, np.random.Generator, np.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
Random Boolean function with the specified bias.
- boolforge.generate.random_function_with_exact_hamming_weight(n: int, hamming_weight: int, *, rng=None) BooleanFunction[source]
Generate a random Boolean function with a fixed Hamming weight.
The Boolean function is represented by its truth table of length
2**n, containing exactlyhamming_weightentries equal to 1. All such functions are sampled uniformly at random.Parameters
- nint
Number of Boolean variables.
- hamming_weightint
Number of truth-table entries equal to 1.
- rngint, np.random.Generator, np.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
Random Boolean function with exactly
hamming_weightones in its truth table.
Raises
- TypeError
If
hamming_weightis not an integer.- ValueError
If
hamming_weightis not in the range[0, 2**n].
- boolforge.generate.random_parity_function(n: int, *, rng=None) BooleanFunction[source]
Generate a random parity Boolean function.
A parity Boolean function evaluates to the parity (sum modulo 2) of all input variables, optionally shifted by a constant. This function returns either the parity function or its complement, chosen uniformly at random.
Parameters
- nint
Number of Boolean variables.
- rngint, np.random.Generator, np.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
Random parity Boolean function on
nvariables.
Raises
- ValueError
If
nis not a positive integer.
Notes
The returned function is either
x1 XOR x2 XOR ... XOR xnor its complement.All variables are included symmetrically.
Parity functions are never canalizing. All variables must always be known to determine the output; they have maximal average sensitivity.
Examples
>>> f = random_parity_function(3) >>> sum(f) 4
- boolforge.generate.random_non_degenerate_function(n: int, bias: float = 0.5, *, rng=None) BooleanFunction[source]
Generate a random non-degenerate Boolean function.
A Boolean function is non-degenerate if every variable is essential, i.e., the function depends on all
ninput variables. Functions are sampled repeatedly from the Bernoulli(bias) ensemble until a non-degenerate function is obtained.Parameters
- nint
Number of Boolean variables.
- biasfloat, optional
Probability that a truth-table entry equals 1. Default is 0.5.
- rngint, np.random.Generator, np.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
Random non-degenerate Boolean function.
Raises
- ValueError
If
nis not a positive integer.- ValueError
If
biasis not strictly between 0 and 1.
Notes
For moderate bias values, almost all Boolean functions are non-degenerate.
Extremely biased functions are very likely to be degenerate, which may lead to long rejection-sampling times.
- boolforge.generate.random_degenerate_function(n: int, bias: float = 0.5, *, rng=None) BooleanFunction[source]
Generate a random degenerate Boolean function.
A Boolean function is degenerate if at least one variable is non-essential, i.e., the function does not depend on that variable. This function constructs a degenerate Boolean function by selecting one variable uniformly at random and enforcing that the output is independent of that variable.
Parameters
- nint
Number of Boolean variables.
- biasfloat, optional
Probability that a truth-table entry equals 1 for the underlying (n−1)-variable function. Default is 0.5.
- rngint, np.random.Generator, np.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
Random degenerate Boolean function on
nvariables.
Raises
- ValueError
If
nis not a positive integer.- ValueError
If
biasis not strictly between 0 and 1.
Notes
Exactly one variable is forced to be non-essential by construction, though additional variables may also be non-essential by chance.
The degenerate variable is chosen uniformly at random.
The resulting distribution is not uniform over all degenerate Boolean functions.
This construction avoids rejection sampling.
- boolforge.generate.random_non_canalizing_function(n: int, bias: float = 0.5, *, rng=None) BooleanFunction[source]
Generate a random non-canalizing Boolean function.
A Boolean function is canalizing if there exists at least one variable and a value of that variable such that fixing it forces the output of the function. This function samples Boolean functions from the Bernoulli(bias) ensemble until a non-canalizing function is obtained.
Parameters
- nint
Number of Boolean variables. Must satisfy
n > 1.- biasfloat, optional
Probability that a truth-table entry equals 1. Default is 0.5.
- rngint, np.random.Generator, np.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
Random non-canalizing Boolean function on
nvariables.
Raises
- ValueError
If
nis not an integer greater than 1.- ValueError
If
biasis not strictly between 0 and 1.
Notes
This function uses rejection sampling.
For moderate bias values, almost all Boolean functions are non-canalizing.
Extremely biased functions are more likely to be canalizing and may lead to longer sampling times.
References
C. Kadelka, J. Kuipers, and R. Laubenbacher (2017). The influence of canalization on the robustness of Boolean networks. Physica D: Nonlinear Phenomena, 353, 39–47.
- boolforge.generate.random_non_canalizing_non_degenerate_function(n: int, bias: float = 0.5, *, rng=None) BooleanFunction[source]
Generate a random Boolean function that is both non-canalizing and non-degenerate.
A Boolean function is non-canalizing if no variable can force the output when fixed, and non-degenerate if every variable is essential. This function samples Boolean functions from the Bernoulli(bias) ensemble until both properties are satisfied.
Parameters
- nint
Number of Boolean variables. Must satisfy
n > 1.- biasfloat, optional
Probability that a truth-table entry equals 1. Default is 0.5.
- rngint, np.random.Generator, np.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
Random Boolean function on
nvariables that is both non-canalizing and non-degenerate.
Raises
- ValueError
If
nis not an integer greater than 1.- ValueError
If
biasis not strictly between 0 and 1.
Notes
This function uses rejection sampling.
For moderate bias values and sufficiently large
n, almost all Boolean functions are both non-canalizing and non-degenerate.Extremely biased functions are more likely to be canalizing or degenerate and may lead to longer sampling times.
References
C. Kadelka, J. Kuipers, and R. Laubenbacher (2017). The influence of canalization on the robustness of Boolean networks. Physica D: Nonlinear Phenomena, 353, 39–47.
- boolforge.generate.sample_canalized_outputs_uniform_structure(n, W, *, rng)[source]
Sample a canalized output bitstring yielding uniform layer-structure weighting.
This function samples a binary vector
bof lengthnrepresenting canalized output values, where consecutive equal values are part of the same canalizing layer. The probability of a given layer structure(k_1, k_2, ..., k_r)is proportional to1 / (k_1! k_2! … k_r!).
Sampling is performed sequentially using precomputed dynamic-programming weights
W, stored in _uniform_structure_weights.Parameters
- nint
Length of the output bitstring to sample.
- Wndarray of shape (n+1, n+1)
Dynamic-programming weight table, where
W[m, s]gives the total weight of all valid completions withmpositions remaining and current layer sizes.- rngnumpy.random.Generator
Random number generator used for sampling.
Returns
- bndarray of shape (n,), dtype int
Sampled binary canalized output vector.
Notes
The bitstring is generated left-to-right. At each step, the algorithm probabilistically chooses whether to extend the current layer or start a new one, using the weights in
Wto ensure correct global sampling probabilities. The first bit is chosen uniformly at random.
- boolforge.generate.random_k_canalizing_function(n: int, k: int, EXACT_DEPTH: bool = False, UNIFORM_STRUCTURE: bool = True, ALLOW_DEGENERATE_FUNCTIONS: bool = False, *, rng=None) BooleanFunction[source]
Generate a random k-canalizing Boolean function in n variables.
A Boolean function is k-canalizing if it has at least k conditionally canalizing variables. If
EXACT_DEPTHis True, the function has exactly k conditionally canalizing variables; otherwise, its canalizing depth may exceed k.Parameters
- nint
Number of Boolean variables.
- kint
Requested canalizing depth. Must satisfy
0 <= k <= n. Settingk = ngenerates a nested canalizing function.- EXACT_DEPTHbool, optional
If True, enforce that the canalizing depth is exactly
k. If False (default), the depth is at leastk.- UNIFORM_STRUCTUREbool, optional
If True (default), canalized outputs are sampled uniformly over canalizing layer structures. Specifically, layer structures
(k_1, ..., k_r)are sampled with probability proportional to1 / (k_1! ... k_r!), removing the bias toward symmetric structures induced by independent sampling. Ifk == n, the nested canalizing constraint that the final layer has size at least 2 is enforced. If False, canalized outputs are sampled independently and uniformly as a bitstring, which biases the distribution toward more symmetric layer structures.- ALLOW_DEGENERATE_FUNCTIONSbool, optional
If True, the non-canalizing core function may be degenerate. If False (default), non-degenerate core functions are enforced whenever possible.
- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
A Boolean function on
nvariables with canalizing depth at leastk(or exactlykifEXACT_DEPTH=True).
Raises
- AssertionError
If
nis not a positive integer.- AssertionError
If
kdoes not satisfy0 <= k <= n.- AssertionError
If
EXACT_DEPTH=Trueandk = n-1(no such functions exist).
Notes
For fixed parameter values, this function samples uniformly at random from the ensemble of Boolean functions consistent with the specified constraints. Non-uniformity arises only when
UNIFORM_STRUCTURE=False.The construction follows the standard decomposition of a k-canalizing function into canalizing variables, canalizing inputs and outputs, and a residual core function on
n-kvariables.References
- He, Q., and Macauley, M. (2016).
Stratification and enumeration of Boolean functions by canalizing depth. Physica D: Nonlinear Phenomena, 314, 1–8.
- Dimitrova, E., Stigler, B., Kadelka, C., and Murrugarra, D. (2022).
Revealing the canalizing structure of Boolean functions: Algorithms and applications. Automatica, 146, 110630.
- boolforge.generate.random_k_canalizing_function_with_specific_layer_structure(n: int, layer_structure: list, EXACT_DEPTH: bool = False, ALLOW_DEGENERATE_FUNCTIONS: bool = False, *, rng=None) BooleanFunction[source]
Generate a random Boolean function with a specified canalizing layer structure.
The canalizing layer structure is given as a list
[k_1, ..., k_r], where eachk_ispecifies the number of canalizing variables in the i-th layer. The total canalizing depth issum(layer_structure).If
sum(layer_structure) == nandn > 1, the function is a nested canalizing function and the final layer is required to have size at least 2.Parameters
- nint
Total number of Boolean variables.
- layer_structurelist of int
Canalizing layer structure
[k_1, ..., k_r]. Each entry must be at least 1. Ifsum(layer_structure) == nandn > 1, the final entry must satisfylayer_structure[-1] >= 2.- EXACT_DEPTHbool, optional
If True, enforce that the canalizing depth is exactly
sum(layer_structure). If False (default), additional canalizing variables may occur in the core function.- ALLOW_DEGENERATE_FUNCTIONSbool, optional
If True, the non-canalizing core function may be degenerate. If False (default), non-degenerate core functions are enforced whenever possible.
- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
A Boolean function on
nvariables with the prescribed canalizing layer structure.
Raises
- AssertionError
If
nis not a positive integer.- AssertionError
If
sum(layer_structure)does not satisfy0 <= sum(layer_structure) <= n.- AssertionError
If
EXACT_DEPTH=Trueandsum(layer_structure) = n - 1.- AssertionError
If
sum(layer_structure) = n > 1and the final layer has size less than 2.- AssertionError
If any entry of
layer_structureis less than 1.
Notes
For fixed parameter values, this function samples uniformly at random from the ensemble of Boolean functions consistent with the specified canalizing layer structure and additional constraints.
The construction follows the standard decomposition of a canalizing function into ordered canalizing layers and a residual core function on the remaining variables.
References
- He, Q., and Macauley, M. (2016).
Stratification and enumeration of Boolean functions by canalizing depth. Physica D: Nonlinear Phenomena, 314, 1–8.
- Kadelka, C., Kuipers, J., and Laubenbacher, R. (2017).
The influence of canalization on the robustness of Boolean networks. Physica D: Nonlinear Phenomena, 353, 39–47.
- boolforge.generate.random_NCF(n: int, UNIFORM_STRUCTURE: bool = True, layer_structure: list | None = None, *, rng=None) BooleanFunction[source]
Generate a random nested canalizing Boolean function in n variables.
A nested canalizing function (NCF) is an n-canalizing Boolean function, i.e., a function whose canalizing depth equals the number of variables. Optionally, a specific canalizing layer structure may be prescribed.
Parameters
- nint
Total number of Boolean variables.
- UNIFORM_STRUCTUREbool, optional
If True (default) and
layer_structureis None, canalizing layer structures are sampled uniformly at random, removing the bias toward symmetric structures induced by independent sampling of canalized outputs. If False, canalized outputs are sampled independently and uniformly as a bitstring, which biases the distribution toward more symmetric layer structures. This parameter is ignored iflayer_structureis provided.- layer_structurelist of int or None, optional
Canalizing layer structure
[k_1, ..., k_r]. Each entry must be at least 1. If provided, it must satisfysum(layer_structure) == n. Ifn > 1, the final entry must satisfylayer_structure[-1] >= 2. If None (default), the layer structure is sampled at random.- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanFunction
A nested canalizing Boolean function on
nvariables.
Raises
- AssertionError
If
nis not a positive integer.- AssertionError
If
layer_structureis provided but does not satisfysum(layer_structure) == n.- AssertionError
If
n > 1and the final layer has size less than 2.
Notes
For fixed parameter values, this function samples uniformly at random from the ensemble of nested canalizing Boolean functions consistent with the specified constraints. Non-uniformity arises only when
UNIFORM_STRUCTURE=False.This function is a convenience wrapper around
random_k_canalizing_functionandrandom_k_canalizing_function_with_specific_layer_structure.References
- He, Q., and Macauley, M. (2016).
Stratification and enumeration of Boolean functions by canalizing depth. Physica D: Nonlinear Phenomena, 314, 1–8.
- Kadelka, C., Kuipers, J., and Laubenbacher, R. (2017).
The influence of canalization on the robustness of Boolean networks. Physica D: Nonlinear Phenomena, 353, 39–47.
- boolforge.generate.random_degrees(N: int, n: int | float | list | ndarray, indegree_distribution: str = 'constant', NO_SELF_REGULATION: bool = True, *, rng=None) ndarray[source]
Draw an in-degree vector for a directed network with N nodes.
This function either accepts a user-specified in-degree vector or samples in-degrees independently for each node from a specified distribution.
Parameters
- Nint
Number of nodes in the network. Must be a positive integer.
- nint, float, list of int, or ndarray of int
Interpretation depends on
indegree_distribution:If
nis a length-Nvector of integers, it is interpreted as a user-specified in-degree sequence and returned after validation.If
indegree_distributionis one of{'constant', 'dirac', 'delta'}, thennis a single integer specifying the in-degree of every node.If
indegree_distribution == 'uniform', thennis a positive integer upper bound, and each node independently receives an in-degree sampled uniformly from{1, 2, ..., n}.If
indegree_distribution == 'poisson', thennis the Poisson rate parameterλ > 0. Each node independently receives a Poisson(λ) draw, truncated to lie in[1, N - int(NO_SELF_REGULATION)].
- indegree_distributionstr, optional
Distribution used to generate in-degrees when
nis not a vector. Must be one of{'constant', 'dirac', 'delta', 'uniform', 'poisson'}. Default is'constant'.- NO_SELF_REGULATIONbool, optional
If True (default), self-loops are disallowed in subsequent wiring generation. This is enforced here by capping in-degrees at
N-1. If False, in-degrees may be as large asN.- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- indegreesndarray of int, shape (N,)
In-degree of each node. For sampled distributions, values lie in
[1, N - int(NO_SELF_REGULATION)].
Raises
- AssertionError
If inputs are malformed, out of range, or an unsupported distribution is requested.
Notes
When sampling is requested, in-degrees for different nodes are generated independently. No attempt is made to enforce graphicality or feasibility of the resulting degree sequence for a particular wiring model; such constraints must be handled downstream.
Examples
>>> random_degrees(5, n=2, indegree_distribution='constant') array([2, 2, 2, 2, 2])
>>> random_degrees(4, n=2, indegree_distribution='uniform', NO_SELF_REGULATION=True) array([2, 1, 2, 2])
>>> random_degrees(6, n=1.7, indegree_distribution='poisson') array([1, 2, 1, 1, 2, 1])
>>> random_degrees(3, n=[1, 2, 1]) array([1, 2, 1])
- boolforge.generate.random_edge_list(N: int, indegrees: Sequence[int], NO_SELF_REGULATION: bool, AT_LEAST_ONE_REGULATOR_PER_NODE: bool = False, *, rng=None) list[source]
Generate a random directed edge list for a network with prescribed in-degrees.
Each node
ireceives exactlyindegrees[i]incoming edges, with regulators chosen uniformly at random from the set of admissible source nodes. Optionally, the construction enforces that every node regulates at least one other node.Parameters
- Nint
Number of nodes in the network.
- indegreessequence of int
Length-
Nsequence specifying the number of incoming edges for each node.- NO_SELF_REGULATIONbool
If True, self-loops (edges from a node to itself) are disallowed.
- AT_LEAST_ONE_REGULATOR_PER_NODEbool, optional
If True, enforce that every node has at least one outgoing edge. This is achieved by rewiring edges while preserving the prescribed in-degree sequence. Default is False.
- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- edge_listlist of tuple of int
List of directed edges represented as
(source, target)pairs.
Raises
- ValueError
If
Norindegreesare inconsistent.- AssertionError
If sampling constraints cannot be satisfied.
Notes
Regulators for each node are sampled uniformly at random without replacement from the set of admissible source nodes. If
AT_LEAST_ONE_REGULATOR_PER_NODE, the algorithm post-processes the initially sampled edge list by replacing edges until every node has at least one outgoing edge, while preserving all in-degrees and respecting the self-regulation constraint.No guarantee is made that the resulting edge list is uniformly sampled from the space of all directed graphs satisfying the constraints.
- boolforge.generate.random_wiring_diagram(N: int, n: int | float | list | ndarray, NO_SELF_REGULATION: bool = True, STRONGLY_CONNECTED: bool = False, indegree_distribution: str = 'constant', AT_LEAST_ONE_REGULATOR_PER_NODE: bool = False, n_attempts_to_generate_strongly_connected_network: int = 1000, *, rng=None) tuple[source]
Generate a random wiring diagram for a directed network with N nodes.
A wiring diagram specifies, for each node, the set of its regulators (incoming neighbors). In-degrees are first generated according to the specified distribution, after which edges are sampled uniformly at random subject to the requested constraints.
Parameters
- Nint
Number of nodes in the network.
- nint, float, list of int, or ndarray of int
Parameter determining the in-degree sequence. Interpretation depends on
indegree_distribution:If a length-
Nvector is provided, it is interpreted as the in-degree of each node.If
indegree_distributionis'constant'(or'dirac'/'delta'),nspecifies the in-degree of every node.If
indegree_distributionis'uniform',nspecifies the upper bound of a discrete uniform distribution on{1, ..., n}.If
indegree_distributionis'poisson',nis the Poisson rate parameterlambda > 0.
- NO_SELF_REGULATIONbool, optional
If True (default), self-loops are disallowed.
- STRONGLY_CONNECTEDbool, optional
If True, repeatedly resample the wiring diagram until a strongly connected network is obtained, or until the maximum number of attempts is exceeded. Default is False.
- indegree_distributionstr, optional
Distribution used to generate in-degrees. Must be one of
{'constant', 'dirac', 'delta', 'uniform', 'poisson'}. Default is'constant'.- AT_LEAST_ONE_REGULATOR_PER_NODEbool, optional
If True, enforce that every node has at least one outgoing edge. This is achieved by rewiring edges while preserving the in-degree sequence. Default is False.
- n_attempts_to_generate_strongly_connected_networkint, optional
Maximum number of attempts to generate a strongly connected wiring diagram before raising a
RuntimeError. Default is 1000.- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- WiringDiagram
A wiring diagram object encoding the regulator set of each node.
Raises
- RuntimeError
If
STRONGLY_CONNECTED=Trueand a strongly connected wiring diagram cannot be generated within the specified number of attempts.
Notes
In-degrees are generated first using
random_degrees, and edges are then sampled uniformly at random subject to the imposed constraints. WhenSTRONGLY_CONNECTED=TrueorAT_LEAST_ONE_REGULATOR_PER_NODE=True, the resulting distribution is not uniform over all wiring diagrams with the given in-degree sequence.This function is a high-level convenience wrapper around
random_degreesandrandom_edge_list.Examples
>>> W = random_wiring_diagram(5, n=2) >>> W = random_wiring_diagram(10, n=3, STRONGLY_CONNECTED=True) >>> W = random_wiring_diagram(6, n=[1, 2, 1, 2, 1, 2])
- boolforge.generate.rewire_wiring_diagram(I: list | ndarray | WiringDiagram, average_swaps_per_edge: float = 10, DO_NOT_ADD_SELF_REGULATION: bool = True, FIX_SELF_REGULATION: bool = True, *, rng=None) list[source]
Degree-preserving rewiring of a wiring diagram via double-edge swaps.
The wiring diagram is represented in regulator form:
I[target]lists all regulators (incoming neighbors) oftarget. The algorithm performs random double-edge swaps of the form(u -> v, x -> y) -> (u -> y, x -> v), while preserving both the in-degree and out-degree of every node. Parallel edges are disallowed.Parameters
- Ilist of array-like or WiringDiagram
Wiring diagram in regulator representation. For each node
target,I[target]contains the regulators of that node. Regulator indices must be integers in{0, ..., N-1}. If aWiringDiagramis provided, its internal adjacency representation is used.- average_swaps_per_edgefloat, optional
Target number of successful double-edge swaps per edge. Larger values typically yield better mixing but increase runtime. Default is 10.
- DO_NOT_ADD_SELF_REGULATIONbool, optional
If True (default), proposed swaps that would introduce a self-loop are rejected.
- FIX_SELF_REGULATIONbool, optional
If True (default), existing self-loops are kept fixed and excluded from the pool of swappable edges. If False, existing self-loops may be rewired; if
DO_NOT_ADD_SELF_REGULATIONis True, no new self-loops will be introduced.- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- WiringDiagram
A new wiring diagram obtained by degree-preserving rewiring of
I.
Raises
- ValueError
If the input wiring diagram is malformed.
- AssertionError
If rewiring constraints cannot be satisfied.
Notes
Both in-degrees and out-degrees of all nodes are preserved exactly. Duplicate edges are never introduced. Control over self-regulation is governed by the two Boolean flags above.
The resulting wiring diagram is not guaranteed to be sampled uniformly from the space of all directed graphs with the same degree sequence; the procedure is intended as a practical degree-preserving randomization method rather than an exact uniform sampler.
Examples
>>> I = random_network(8,3) >>> J = rewire_wiring_diagram(I) >>> I.indegrees == J.indegrees True >>> I.get_outdegrees() == J.get_outdegrees() True
- boolforge.generate.random_network(N: int | None = None, n: int | float | list | ndarray | None = None, depth: int | list | ndarray = 0, EXACT_DEPTH: bool = False, UNIFORM_STRUCTURE: bool = True, layer_structure: list | None = None, ALLOW_DEGENERATE_FUNCTIONS: bool = False, PARITY: bool = False, bias: float | list | ndarray = 0.5, absolute_bias: float | list | ndarray = 0.0, USE_ABSOLUTE_BIAS: bool = True, hamming_weight: int | list | ndarray | None = None, NO_SELF_REGULATION: bool = True, STRONGLY_CONNECTED: bool = False, indegree_distribution: str = 'constant', AT_LEAST_ONE_REGULATOR_PER_NODE: bool = False, n_attempts_to_generate_strongly_connected_network: int = 1000, I: list | ndarray | None | WiringDiagram | DiGraph = None, *, rng=None) BooleanNetwork[source]
Construct a random Boolean network with configurable wiring and update rules.
The network is built in two stages:
Wiring diagram If
Iis provided, it is used directly as the wiring diagram, whereI[v]lists the regulators of nodev. Otherwise, a wiring diagram forNnodes is sampled usingrandom_wiring_diagram, with in-degrees determined bynandindegree_distribution. Self-loops may be disallowed and strong connectivity may be enforced.Update rules For each node
i, a Boolean update function with arityindegrees[i]is generated usingrandom_functionsubject to the requested constraints on canalizing depth or layer structure, parity, bias or absolute bias, and exact Hamming weight.
Parameters
- Nint or None, optional
Number of nodes. Required when
Iis not provided. Ignored ifIis given.- nint, float, list of int, ndarray of int, or None, optional
Controls the in-degree distribution when generating a wiring diagram (ignored if
Iis given). Interpretation depends onindegree_distribution:'constant','dirac','delta': Every node has constant in-degreen.'uniform':nis an integer upper bound; each node’s in-degree is sampled uniformly from{1, ..., n}.'poisson':nis a positive rate parameter lambda; in-degrees are Poisson(lambda) draws truncated to[1, N - int(NO_SELF_REGULATION)].If
nis a length-Nvector of integers, it is taken as the exact in-degree sequence.
- depthint, list of int, or ndarray of int, optional
Requested canalizing depth per node. If an integer, it is broadcast to all nodes and clipped at each node’s in-degree. If a vector, it must have length
N. Interpreted as a minimum depth unlessEXACT_DEPTH=True. Default is 0.- EXACT_DEPTHbool, optional
If True, each Boolean function is generated with exactly the requested canalizing depth (or exactly
sum(layer_structure[i])if a layer structure is provided). If False, the canalizing depth is at least as large as requested. Default is False.- UNIFORM_STRUCTUREbool, optional
Controls how canalized outputs are sampled when generating canalizing functions.
If True (default), canalizing layer structures are sampled uniformly at random, i.e., proportional to the inverse factorials of layer sizes, removing the bias toward symmetric structures induced by independent sampling of canalized outputs.
If False, canalized outputs are sampled independently and uniformly as bitstrings, which biases the distribution toward more symmetric layer structures.
This parameter is ignored when
layer_structureis explicitly provided.- layer_structurelist, list of lists, or None, optional
Canalizing layer structure specifications.
If None (default), rule generation is controlled by
depthandEXACT_DEPTH.If a single list
[k1, ..., kr], the same structure is used for all nodes.If a list of lists of length
N,layer_structure[i]is used for nodei.
In all cases,
sum(layer_structure[i])must not exceed the in-degree of nodei. When provided,layer_structuretakes precedence overdepth.- ALLOW_DEGENERATE_FUNCTIONSbool, optional
If True and
depth == 0andlayer_structure is None, degenerate Boolean functions (with non-essential inputs) may be generated, as in classical NK-Kauffman models. If False, generated functions are required to be non-degenerate whenever possible. Default is False.- PARITYbool, optional
If True, parity Boolean functions are generated for all nodes and all other rule parameters are ignored. Default is False.
- biasfloat, list of float, or ndarray of float, optional
Probability of output 1 when generating random (non-canalizing) Boolean functions. Used only when
depth == 0,layer_structure is None,PARITYis False, andUSE_ABSOLUTE_BIASis False. Scalars are broadcast to lengthN. Must lie in[0, 1]. Default is 0.5.- absolute_biasfloat, list of float, or ndarray of float, optional
Absolute deviation from 0.5 used when
USE_ABSOLUTE_BIASis True. Scalars are broadcast to lengthN. Must lie in[0, 1]. Default 0.0.- USE_ABSOLUTE_BIASbool, optional
If True, the bias of each rule is chosen at random from
{0.5*(1-absolute_bias), 0.5*(1+absolute_bias)}. If False,biasis used directly. Default is True.- hamming_weightint, list of int, ndarray of int, or None, optional
Exact Hamming weight (number of ones) of each truth table. Scalars are broadcast to length
N. Values must lie in{0, ..., 2^k}for a k-input function. Additional restrictions apply when requesting exact depth zero. Default is None.- NO_SELF_REGULATIONbool, optional
If True, self-loops are forbidden in generated wiring diagrams. Ignored if
Iis provided. Default is True.- STRONGLY_CONNECTEDbool, optional
If True, wiring generation is repeated until a strongly connected directed graph is obtained or the attempt limit is exceeded. Ignored if
Iis provided. Default is False.- indegree_distributionstr, optional
Distribution used when sampling in-degrees. Must be one of
{'constant', 'dirac', 'delta', 'uniform', 'poisson'}. Default'constant'.- AT_LEAST_ONE_REGULATOR_PER_NODEbool, optional
If True, ensure that each node has at least one outgoing edge in the generated wiring diagram. Default is False.
- n_attempts_to_generate_strongly_connected_networkint, optional
Maximum number of attempts to generate a strongly connected wiring diagram before raising an error. Default is 1000.
- Ilist, ndarray, WiringDiagram, networkx.DiGraph, or None, optional
Existing wiring diagram. If provided,
Nandnare ignored and in-degrees are inferred fromI. If I is a BooleanNetwork, its wiring diagram is reused and its Boolean update rules are ignored.- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.
Returns
- BooleanNetwork
A Boolean network with wiring diagram
I(given or generated) and Boolean update functions generated according to the specified constraints.
Raises
- AssertionError
If input shapes or parameter combinations are invalid.
- RuntimeError
If
STRONGLY_CONNECTED=Trueand a strongly connected wiring diagram cannot be generated within the specified number of attempts.
Notes
Constraint precedence for rule generation is:
PARITY->layer_structure->depth/EXACT_DEPTH-> bias or Hamming-weight constraints.When
EXACT_DEPTH=Trueand the requested depth is zero, Hamming weights{0, 1, 2^k - 1, 2^k}correspond to canalizing functions and are therefore disallowed.Examples
>>> # Boolean network with only essential inputs >>> bn = random_network(N=10, n=2, ALLOW_DEGENERATE_FUNCTIONS=False)
>>> # Classic NK-Kauffman network allowing degenerate rules >>> bn = random_network(N=10, n=3, ALLOW_DEGENERATE_FUNCTIONS=True)
>>> # Fixed wiring: reuse an existing diagram but resample rules >>> bn0 = random_network(N=6, n=2) >>> bn = random_network(I=bn)
>>> # Exact canalizing depth k for all nodes >>> bn = random_network(N=8, n=3, depth=1, EXACT_DEPTH=True)
>>> # Nested canalizing update rules with specific layer structure (broadcast) >>> bn = random_network(N=5, n=3, layer_structure=[1,2]) # same for all nodes
>>> # Parity rules >>> bn = random_network(N=7, n=2, PARITY=True)
>>> # Poisson in-degrees (truncated), no self-regulation, request strong connectivity >>> bn = random_network(N=12, n=1.6, indegree_distribution='poisson', ... NO_SELF_REGULATION=True, STRONGLY_CONNECTED=True)
>>> # Exact Hamming weights (broadcast) >>> bn = random_network(N=6, n=3, hamming_weight=4)
>>> # To ensure strong connectivity, set ALLOW_DEGENERATE_FUNCTIONS=False >>> # and STRONGLY_CONNECTED=True >>> bn = random_network(N,n,ALLOW_DEGENERATE_FUNCTIONS=False,STRONGLY_CONNECTED=True)
- boolforge.generate.random_null_model(bn: BooleanNetwork, wiring_diagram: str = 'fixed', PRESERVE_BIAS: bool = True, PRESERVE_CANALIZING_DEPTH: bool = True, *, rng=None, **kwargs) BooleanNetwork[source]
Generate a randomized Boolean network (null model) from an existing Boolean network while preserving selected structural and dynamical properties.
The returned network has the same number of nodes as
bn. Depending on the selected options, the wiring diagram and/or the Boolean update rules are randomized subject to specified invariants.Wiring diagram randomization
The wiring diagram can be handled in one of three ways:
'fixed'(default): The original wiring diagrambn.Iis reused unchanged.'fixed_indegree': A new wiring diagram is sampled uniformly at random subject to preserving the in-degree of each node. This usesrandom_wiring_diagramwithN = bn.Nandn = bn.indegrees.'fixed_in_and_outdegree': The original wiring diagram is randomized via degree-preserving double-edge swaps usingrewire_wiring_diagram, preserving both in-degrees and out-degrees of all nodes.
Rule randomization
Independently of the wiring diagram, Boolean update rules are randomized for each node, optionally preserving properties of the original rules:
If
PRESERVE_BIASis True, the exact Hamming weight (number of ones in the truth table) of each rule is preserved.If
PRESERVE_CANALIZING_DEPTHis True, the canalizing depth of each rule is preserved exactly.
If both flags are True, both properties are preserved simultaneously. If neither flag is True, rules are regenerated subject only to non-degeneracy and the node’s in-degree.
Parameters
- bnBooleanNetwork
Source Boolean network.
- wiring_diagram{‘fixed’, ‘fixed_indegree’, ‘fixed_in_and_outdegree’}, optional
Strategy for handling the wiring diagram. Default is
'fixed'.- PRESERVE_BIASbool, optional
If True, preserve the exact Hamming weight of each Boolean rule. Default is True.
- PRESERVE_CANALIZING_DEPTHbool, optional
If True, preserve the exact canalizing depth of each Boolean rule. Default is True.
- rngint, numpy.random.Generator, numpy.random.RandomState, random.Random, or None, optional
Random number generator or seed specification. Passed to
utils._coerce_rng.- **kwargs
Additional keyword arguments forwarded to the wiring-diagram randomization routine:
For
wiring_diagram == 'fixed_indegree', forwarded torandom_wiring_diagram(e.g.,NO_SELF_REGULATION,STRONGLY_CONNECTED).For
wiring_diagram == 'fixed_in_and_outdegree', forwarded torewire_wiring_diagram(e.g.,average_swaps_per_edge,DO_NOT_ADD_SELF_REGULATION,FIX_SELF_REGULATION).
Returns
- BooleanNetwork
A randomized Boolean network satisfying the selected invariants.
Raises
- AssertionError
If invalid options are provided.
- RuntimeError
If wiring-diagram randomization fails (e.g., strong connectivity cannot be achieved within the allowed number of attempts).
Notes
This function generates null models by selectively preserving structural and dynamical properties of an existing Boolean network. It is intended for hypothesis testing and comparative studies rather than for uniform sampling over all networks satisfying the given constraints.
Examples
>>> # Most restrictive use case: Preserve both wiring and rule properties (default) >>> bn_null = random_null_model(bn)
>>> # Preserve in-degrees only and preserve rule bias >>> bn_null = random_null_model( ... bn, ... wiring_diagram='fixed_indegree', ... PRESERVE_BIAS=True, ... PRESERVE_CANALIZING_DEPTH=False ... )
>>> # Preserve both in- and out-degrees via rewiring >>> bn_null = random_null_model( ... bn, ... wiring_diagram='fixed_in_and_outdegree', ... average_swaps_per_edge=15 ... )