From 60b962d2a4d28aaba18913cd9232fd9a44004f80 Mon Sep 17 00:00:00 2001 From: debsankha manik Date: Sun, 28 Feb 2016 00:30:37 +0100 Subject: [PATCH 1/3] changed hierarchical.md --- spec/hierarchical.md | 148 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 spec/hierarchical.md diff --git a/spec/hierarchical.md b/spec/hierarchical.md new file mode 100644 index 0000000..ea33293 --- /dev/null +++ b/spec/hierarchical.md @@ -0,0 +1,148 @@ +# Hierarchichal Design Overview + +# User Story 1: Scaling of Basin of attraction volumes for Kuramoto Networks +## Setting: +A Kuramoto network $$F$$ is completely specified by it's graph topology $$G(V, E)$$ and its set of natural frequencies $$\vec{\omega})$$ for all the nodes. Here we are only intersted in ring topology. All fixed points of a Kuramoto ring are uniquely identified by an integer called the **winding number** $$k$$. + +## Study: +We are interested in the probability that a random initial condition evolves to the steady state with $$k = k'$$, i.e. $$V_{k, N} = P(k | len(V) = N)$$. And we want this over all possible distributions of natural frequencies $\vec{\omega}$ (subject to some constraints, that make it a finite space). + +## Sequential pseudocode would be: +```python +N_range = np.arange(10,100) +V = [] + +# Outermost loop: obver many ring sizes +for N in N_range: + V_N = 0 + # loop over all omega combinations + V_array = [] + for idx, omega in enumerate(all_omegas(N)): + # loop over many initial conditions + k_list = [] + for initcond in get_initconds(num_initconds): + k = find_k(N, omega, initcond) + k_list.append(k) + # Now bin the data to find the frequencies + V_omega = scipy.stats.itemfreq(k_list) + V_array.append(V_omega) + # Do the averaging over all omegas + V_N = np.average(V_array, axis = 2) + V.append(V_N) +``` + +## Can we transform this to this? +```python +basin_singlering = Experiment(find_k, initcond_range = initcond_iter(...), aggregator =\ + <#something that counts final states and computes probabilities>) +# outout is of the form: {0: 0.78, 1: 0.11, -1: 0.14} +basin_all_omegas_for_single_size = Experiment(basin_singlering, omega_range = omega_iter(100),\ + aggregator = <#averages over all omega distributions,\ + computes some sort of central tendency>) +# outout is of the form: {'averages': {0: 0.78, 1: 0.11, -1: 0.14}, 'variances': {0: 0.1, 1: 0.2, -1:0.3} +basin_scaling_with_size = Experiment(basin_all_omegas_for_single_size, n_range \= + np.arange(1, 100, 10), aggregator = <# concatenates results for all n>) +# outout is of the form: {n0: {'averages': {}, 'variances': {}}, n1: {'averages': {}, 'variances': {}}, ....} +``` + +### Advantages: +- Completely Hierarchichal +### Disadvantages: +- Fill it in! + +## Design idea: +Here I outline how to acheive the user interface that I outlined in the last subsection. +So here I present a code snippet. + +### Disclaimer: +#### What these code snippets are: +1. A *minimum working example (MWA)* that is capable of supporting a hierarchichal user interface. +2. I do this by writing some classes and their attributes and methods. +3. Everything apart from the object structures (classes) and call signature (functions) are demonstrative only. + +#### What they are NOT: +1. Taking into account the whole problem of scheduling. +2. The aspect of chunking and parallelizing. + +```python +class Experiment(object): +""" +Experiment +========= +An object that specifies how to compute a function *func* on a range of *arguments* and process +all the outputs from single runs to compute an *output*. + +Parameters +---------- +func : a function/callable + func must take a single argument that we call *input* +param : a parameter that, along with the function, completely specifies what the *output* + should be. +input_generator : + a callable taking a mandatoryargument, *parameter*, that generates the range of *inputs* + to *func*. it can also take optional parameters. See draft implementation of *run* below. +""" + def __init__(self, func, input_generator, input_generator_args = None): + """ + """ + pass + def run(self, param): + """ + """ + return [func(input) for input in input_generator(param, *input_generator_args)] +``` + +## Design used in test case: basin volume of Kuramoto rings +Let me try to make it clearer by giving an example use case, our very own problem of Kuramoto networks. +```python +def compute_k((omega, initcond)): + """Evolves a ring network with frequencies *omega* from initial condition + *initcond* + Returns winding number of final state k + """ + pass + +def generate_initconds(omega, nrepeat): + """generates nrepeat vectors of random phase angles, each same size as omega""" + for initcond in np.random.uniform(0, 2*np.pi, size = (nrepeat, len(omega))): + yield omega, initcond + +def gen_all_vectors_with_len(len): + """ + Generates all vectors with elements ±1 and length len + """ + pass + +# Experiment that computes the basin volumes of a single ring. Note how teh number of initial conditions is specified as input_generator_args. +E_onering = Experiment(compute_k, input_generator=\ + generate_initconds, input_generator_args = (1000,)) + +# Experiment that computes the basin volumes of all rings of a given size +E_onesize = Experiment(E_onering.run, input_generator=\ + gen_allvectors_with_len, input_generator_args = None) + +# Experiment that computes the basin volumes of rings of size in certain range +E_basin_scaling = Experiment(E_onesize.run, input_generator = lambda x:x) +# Finally, call the run function of E_basin_scaling causes all child experiments to run recursively. +E_basin_scaling.run(param = np.arange(min_size, max_size, 10)) +``` +OK. So this design can do hierarchical experiments. But let's see how it works in some other scenario, for sake of being thorough: +## Design used in another test case: find out the critical coupling of a kuramoto network +```python +def order_param(Network, initcond): + """Computes the order parameter by simulating the network from given initial condition""" + pass +def generate_initconds(nrepeat): + """ + generates args for func:`order_param` + """ + G = nx.Graph() + # code to set up your graph here + for thetas in np.random.uniform(0, 2*pi, size = nrepeat): + yield G, thetas +E_one_k = Experiment(order_param, input_generator = generate_initconds, input_generator_args = (1000,)) +E_orderparam_scaling = Experiment(E_one_k.run, input_generator =\ + lambda mink, maxk: np.arange(mink, maxk, (maxk - mink)/100)) +E_orderparam_scaling.run((0, 1)) +``` + From 22c9f29038d9ee58ded622d90f17e66b0ea68b57 Mon Sep 17 00:00:00 2001 From: debsankha manik Date: Sun, 28 Feb 2016 12:39:59 +0100 Subject: [PATCH 2/3] updated hierarchical.md --- spec/hierarchical.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/spec/hierarchical.md b/spec/hierarchical.md index ea33293..af3cc9a 100644 --- a/spec/hierarchical.md +++ b/spec/hierarchical.md @@ -5,14 +5,22 @@ A Kuramoto network $$F$$ is completely specified by it's graph topology $$G(V, E)$$ and its set of natural frequencies $$\vec{\omega})$$ for all the nodes. Here we are only intersted in ring topology. All fixed points of a Kuramoto ring are uniquely identified by an integer called the **winding number** $$k$$. ## Study: -We are interested in the probability that a random initial condition evolves to the steady state with $$k = k'$$, i.e. $$V_{k, N} = P(k | len(V) = N)$$. And we want this over all possible distributions of natural frequencies $\vec{\omega}$ (subject to some constraints, that make it a finite space). +We are interested in the probability that a random initial condition evolves to the steady state with $$k = k'$$, i.e. $$V_{k, N} = P(k | len(V) = N)$$. And we want this over all possible distributions of natural frequencies $\vec{\omega}$ (subject to some constraints, that make it a finite space). Then we want to compute it over a range of $$N$$ values to obtain the scaling behaviour of the same. ## Sequential pseudocode would be: ```python +def find_k(N, omega, initcond): + """ + Simulates an N ring kuramoto network with natural frequencies + omega from initcond untill the dynamics converges. + + Returns the winding number of the steady state. + """ + N_range = np.arange(10,100) V = [] -# Outermost loop: obver many ring sizes +# Outermost loop: over many ring sizes for N in N_range: V_N = 0 # loop over all omega combinations From 67dbe179b6ef956ca27742610ab4aa771ba75eaf Mon Sep 17 00:00:00 2001 From: debsankha manik Date: Sun, 28 Feb 2016 12:53:15 +0100 Subject: [PATCH 3/3] fixed second test case in hierarchical.md --- spec/hierarchical.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/hierarchical.md b/spec/hierarchical.md index af3cc9a..40d198d 100644 --- a/spec/hierarchical.md +++ b/spec/hierarchical.md @@ -140,17 +140,18 @@ OK. So this design can do hierarchical experiments. But let's see how it works i def order_param(Network, initcond): """Computes the order parameter by simulating the network from given initial condition""" pass -def generate_initconds(nrepeat): +def generate_order_param_args(coupling, nrepeat): """ generates args for func:`order_param` """ G = nx.Graph() # code to set up your graph here + for u,v in G.edges(): + G[u][v]['weight'] = coupling for thetas in np.random.uniform(0, 2*pi, size = nrepeat): yield G, thetas -E_one_k = Experiment(order_param, input_generator = generate_initconds, input_generator_args = (1000,)) -E_orderparam_scaling = Experiment(E_one_k.run, input_generator =\ +E_one_coupling = Experiment(order_param, input_generator = generate_initconds, input_generator_args = (1000,)) +E_orderparam_scaling = Experiment(E_one_coupling.run, input_generator =\ lambda mink, maxk: np.arange(mink, maxk, (maxk - mink)/100)) E_orderparam_scaling.run((0, 1)) ``` -