|
| 1 | +# Hierarchichal Design Overview |
| 2 | + |
| 3 | +# User Story 1: Scaling of Basin of attraction volumes for Kuramoto Networks |
| 4 | +## Setting: |
| 5 | +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$$. |
| 6 | + |
| 7 | +## Study: |
| 8 | +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). |
| 9 | + |
| 10 | +## Sequential pseudocode would be: |
| 11 | +```python |
| 12 | +N_range = np.arange(10,100) |
| 13 | +V = [] |
| 14 | + |
| 15 | +# Outermost loop: obver many ring sizes |
| 16 | +for N in N_range: |
| 17 | + V_N = 0 |
| 18 | + # loop over all omega combinations |
| 19 | + V_array = [] |
| 20 | + for idx, omega in enumerate(all_omegas(N)): |
| 21 | + # loop over many initial conditions |
| 22 | + k_list = [] |
| 23 | + for initcond in get_initconds(num_initconds): |
| 24 | + k = find_k(N, omega, initcond) |
| 25 | + k_list.append(k) |
| 26 | + # Now bin the data to find the frequencies |
| 27 | + V_omega = scipy.stats.itemfreq(k_list) |
| 28 | + V_array.append(V_omega) |
| 29 | + # Do the averaging over all omegas |
| 30 | + V_N = np.average(V_array, axis = 2) |
| 31 | + V.append(V_N) |
| 32 | +``` |
| 33 | + |
| 34 | +## Can we transform this to this? |
| 35 | +```python |
| 36 | +basin_singlering = Experiment(find_k, initcond_range = initcond_iter(...), aggregator =\ |
| 37 | + <#something that counts final states and computes probabilities>) |
| 38 | +# outout is of the form: {0: 0.78, 1: 0.11, -1: 0.14} |
| 39 | +basin_all_omegas_for_single_size = Experiment(basin_singlering, omega_range = omega_iter(100),\ |
| 40 | + aggregator = <#averages over all omega distributions,\ |
| 41 | + computes some sort of central tendency>) |
| 42 | +# 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} |
| 43 | +basin_scaling_with_size = Experiment(basin_all_omegas_for_single_size, n_range \= |
| 44 | + np.arange(1, 100, 10), aggregator = <# concatenates results for all n>) |
| 45 | +# outout is of the form: {n0: {'averages': {}, 'variances': {}}, n1: {'averages': {}, 'variances': {}}, ....} |
| 46 | +``` |
| 47 | + |
| 48 | +### Advantages: |
| 49 | +- Completely Hierarchichal |
| 50 | +### Disadvantages: |
| 51 | +- Fill it in! |
| 52 | + |
| 53 | +## Design idea: |
| 54 | +Here I outline how to acheive the user interface that I outlined in the last subsection. |
| 55 | +So here I present a code snippet. |
| 56 | + |
| 57 | +### Disclaimer: |
| 58 | +#### What these code snippets are: |
| 59 | +1. A *minimum working example (MWA)* that is capable of supporting a hierarchichal user interface. |
| 60 | +2. I do this by writing some classes and their attributes and methods. |
| 61 | +3. Everything apart from the object structures (classes) and call signature (functions) are demonstrative only. |
| 62 | + |
| 63 | +#### What they are NOT: |
| 64 | +1. Taking into account the whole problem of scheduling. |
| 65 | +2. The aspect of chunking and parallelizing. |
| 66 | + |
| 67 | +```python |
| 68 | +class Experiment(object): |
| 69 | +""" |
| 70 | +Experiment |
| 71 | +========= |
| 72 | +An object that specifies how to compute a function *func* on a range of *arguments* and process |
| 73 | +all the outputs from single runs to compute an *output*. |
| 74 | +
|
| 75 | +Parameters |
| 76 | +---------- |
| 77 | +func : a function/callable |
| 78 | + func must take a single argument that we call *input* |
| 79 | +param : a parameter that, along with the function, completely specifies what the *output* |
| 80 | + should be. |
| 81 | +input_generator : |
| 82 | + a callable taking a mandatoryargument, *parameter*, that generates the range of *inputs* |
| 83 | + to *func*. it can also take optional parameters. See draft implementation of *run* below. |
| 84 | +""" |
| 85 | + def __init__(self, func, input_generator, input_generator_args = None): |
| 86 | + """ |
| 87 | + """ |
| 88 | + pass |
| 89 | + def run(self, param): |
| 90 | + """ |
| 91 | + """ |
| 92 | + return [func(input) for input in input_generator(param, *input_generator_args)] |
| 93 | +``` |
| 94 | + |
| 95 | +## Design used in test case: basin volume of Kuramoto rings |
| 96 | +Let me try to make it clearer by giving an example use case, our very own problem of Kuramoto networks. |
| 97 | +```python |
| 98 | +def compute_k((omega, initcond)): |
| 99 | + """Evolves a ring network with frequencies *omega* from initial condition |
| 100 | + *initcond* |
| 101 | + Returns winding number of final state k |
| 102 | + """ |
| 103 | + pass |
| 104 | + |
| 105 | +def generate_initconds(omega, nrepeat): |
| 106 | + """generates nrepeat vectors of random phase angles, each same size as omega""" |
| 107 | + for initcond in np.random.uniform(0, 2*np.pi, size = (nrepeat, len(omega))): |
| 108 | + yield omega, initcond |
| 109 | + |
| 110 | +def gen_all_vectors_with_len(len): |
| 111 | + """ |
| 112 | + Generates all vectors with elements ±1 and length len |
| 113 | + """ |
| 114 | + pass |
| 115 | + |
| 116 | +# Experiment that computes the basin volumes of a single ring. Note how teh number of initial conditions is specified as input_generator_args. |
| 117 | +E_onering = Experiment(compute_k, input_generator=\ |
| 118 | + generate_initconds, input_generator_args = (1000,)) |
| 119 | + |
| 120 | +# Experiment that computes the basin volumes of all rings of a given size |
| 121 | +E_onesize = Experiment(E_onering.run, input_generator=\ |
| 122 | + gen_allvectors_with_len, input_generator_args = None) |
| 123 | + |
| 124 | +# Experiment that computes the basin volumes of rings of size in certain range |
| 125 | +E_basin_scaling = Experiment(E_onesize.run, input_generator = lambda x:x) |
| 126 | +# Finally, call the run function of E_basin_scaling causes all child experiments to run recursively. |
| 127 | +E_basin_scaling.run(param = np.arange(min_size, max_size, 10)) |
| 128 | +``` |
| 129 | +OK. So this design can do hierarchical experiments. But let's see how it works in some other scenario, for sake of being thorough: |
| 130 | +## Design used in another test case: find out the critical coupling of a kuramoto network |
| 131 | +```python |
| 132 | +def order_param(Network, initcond): |
| 133 | + """Computes the order parameter by simulating the network from given initial condition""" |
| 134 | + pass |
| 135 | +def generate_initconds(nrepeat): |
| 136 | + """ |
| 137 | + generates args for func:`order_param` |
| 138 | + """ |
| 139 | + <a name="ugly"></a> |
| 140 | + G = nx.Graph() |
| 141 | + # code to set up your graph here |
| 142 | + for thetas in np.random.uniform(0, 2*pi, size = nrepeat): |
| 143 | + yield G, thetas |
| 144 | +E_one_k = Experiment(order_param, input_generator = generate_initconds, input_generator_args = (1000,)) |
| 145 | +E_orderparam_scaling = Experiment(E_one_k.run, input_generator =\ |
| 146 | + lambda mink, maxk: np.arange(mink, maxk, (maxk - mink)/100)) |
| 147 | +E_orderparam_scaling.run((0, 1)) |
| 148 | +``` |
| 149 | + |
| 150 | +## Problems: |
| 151 | +1. It is plain ugly how we [link text](#ugly). |
| 152 | + |
| 153 | + |
0 commit comments