Examples

The examples can be downloaded from COLNA’s github repository.

Feedforward Network

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# +-----------------------------------------------------------------------------+
# |  Copyright 2019-2020 IBM Corp. All Rights Reserved.                         |
# |                                                                             |
# |  Licensed under the Apache License, Version 2.0 (the "License");            |
# |  you may not use this file except in compliance with the License.           |
# |  You may obtain a copy of the License at                                    |
# |                                                                             |
# |      http://www.apache.org/licenses/LICENSE-2.0                             |
# |                                                                             |
# |  Unless required by applicable law or agreed to in writing, software        |
# |  distributed under the License is distributed on an "AS IS" BASIS,          |
# |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   |
# |  See the License for the specific language governing permissions and        |
# |  limitations under the License.                                             |
# +-----------------------------------------------------------------------------+
# |  Authors: Lorenz K. Mueller, Pascal Stark                                   |
# +-----------------------------------------------------------------------------+
""" Creates a simple feedforward network with constant input.

This example is part of the :ref:`User Manual`.

The network topology is as follows:

A > B > D
    v
    C
"""

from colna.analyticnetwork import Network, Edge

# Create a network
net = Network()

# Add nodes
net.add_node(name='a')
net.add_node(name='b')
net.add_node(name='c')
net.add_node(name='d')

# Add edges
net.add_edge(Edge(start='a',end='b',phase=1,attenuation=0.8,delay=1))
net.add_edge(Edge(start='b',end='c',phase=2,attenuation=0.6,delay=2))
net.add_edge(Edge(start='b',end='d',phase=3,attenuation=0.4,delay=3))

# Add input
net.add_input(name='a',amplitude=1.0, phase=0)

# Visualize the network
net.visualize(path='./visualizations/feedforward', format='svg')

# Evaluate the network
net.evaluate(amplitude_cutoff=1e-3)

# Compute output and show results
print('paths leading to c:', net.get_paths('c'))
print('paths leading to d:', net.get_paths('d'))
print('waves arriving at c:', net.get_result('c'))
print('waves arriving at d:', net.get_result('d'))
print('latex string for waves arriving at c:', net.get_latex_result('c'))

# render output in a html file
net.get_html_result(['c','d'], precision=2, path='./visualizations/feedforward.html')
_images/feedforward.svg

Output of the Network.get_html_result():

Waves at node c

\(\begin{equation}\begin{split}&0.48\cdot\exp(j (3))\cdot a_{in}(t-3)\\\end{split}\end{equation}\)

Waves at node d

\(\begin{equation}\begin{split}&0.32\cdot\exp(j (4))\cdot a_{in}(t-4)\\\end{split}\end{equation}\)

Feedforward Network with Testbench

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# +-----------------------------------------------------------------------------+
# |  Copyright 2019-2020 IBM Corp. All Rights Reserved.                                       |
# |                                                                             |
# |  Licensed under the Apache License, Version 2.0 (the "License");            |
# |  you may not use this file except in compliance with the License.           |
# |  You may obtain a copy of the License at                                    |
# |                                                                             |
# |      http://www.apache.org/licenses/LICENSE-2.0                             |
# |                                                                             |
# |  Unless required by applicable law or agreed to in writing, software        |
# |  distributed under the License is distributed on an "AS IS" BASIS,          |
# |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   |
# |  See the License for the specific language governing permissions and        |
# |  limitations under the License.                                             |
# +-----------------------------------------------------------------------------+
# |  Authors: Lorenz K. Mueller, Pascal Stark                                   |
# +-----------------------------------------------------------------------------+
""" Creates a simple feedforward network with a testbench.

This is the example used in the basic usage guide.
The network topology is as follows:

A -> B > D
     v
     C

A testbench is used to inject time varying signals at node A and B.
"""

from colna.analyticnetwork import Network, Edge, Testbench
import numpy as np
import matplotlib.pyplot as plt

### Create the Network and add the nodes
net = Network()

net.add_node(name='a')
net.add_node(name='b')
net.add_node(name='c')
net.add_node(name='d')

net.add_edge(Edge(start='a',end='b',phase=1,attenuation=0.8,delay=1))
net.add_edge(Edge(start='b',end='c',phase=2,attenuation=0.6,delay=2))
net.add_edge(Edge(start='b',end='d',phase=3,attenuation=0.4,delay=3))

# Visualize the network
net.visualize(path='./visualizations/feedforward_with_testbench', format='svg')

# Create a testbench
tb = Testbench(network=net, timestep=0.1) # Timestep should be factor of all delays

# add an input signal to the testbench
x_in_a = np.sin(np.linspace(0,15,500))+1.5 # create the input signal (Dimensino N)
t_in = np.linspace(0, 10, num=501) # create the input time vector (Dimension N+1)
tb.add_input_sequence(node_name='a',x=x_in_a,t=t_in)

# add output nodes to testbench (nodes at which output signal should be recorded)
tb.add_output_node('c')
tb.add_output_node('d')

# evaluate the network (through the testbench)
tb.evaluate_network()

# Calculate the output signal at the output nodes
tb.calculate_output(n_threads=8) # uses multithreading with at most 8 threads
t, x = tb.t_out.transpose(), tb.x_out.transpose()

### Plot the signals
plt.plot(tb.input_t[0][:-1], np.abs(tb.input_x[0][:-1]), 'o') # Input signal
plt.plot(t, np.abs(x), 'x') # Output signal
plt.xlabel('Time')
plt.ylabel('|x|')
plt.legend(['Input', 'Output C', 'Output D'], loc='lower left')
plt.grid()
# plt.savefig('./visualizations/feedforward_with_testbench_output.svg')
plt.show()
_images/feedforward_with_testbench_output.svg

Physical Network

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# +-----------------------------------------------------------------------------+
# |  Copyright 2019-2020 IBM Corp. All Rights Reserved.                         |
# |                                                                             |
# |  Licensed under the Apache License, Version 2.0 (the "License");            |
# |  you may not use this file except in compliance with the License.           |
# |  You may obtain a copy of the License at                                    |
# |                                                                             |
# |      http://www.apache.org/licenses/LICENSE-2.0                             |
# |                                                                             |
# |  Unless required by applicable law or agreed to in writing, software        |
# |  distributed under the License is distributed on an "AS IS" BASIS,          |
# |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   |
# |  See the License for the specific language governing permissions and        |
# |  limitations under the License.                                             |
# +-----------------------------------------------------------------------------+
# |  Authors: Lorenz K. Mueller, Pascal Stark                                   |
# +-----------------------------------------------------------------------------+
"""
Creates a physical network.

This demonstrates how devices and devicelinks can be used to create a PhysicalNetwork.
"""

from colna.analyticnetwork import PhysicalNetwork, Device, DeviceLink
import numpy as np

# define a physical network
physnet = PhysicalNetwork()

# create a splitter and a combiner Device based on their scattering matrix
splitter = Device(name='0', devicetype='Splitter', scattering_matrix=np.array([[1 / np.sqrt(2), 1 / np.sqrt(2)]]),
                  delay=1)
combiner = Device(name='0', devicetype='Combiner', scattering_matrix=np.array([[1 / np.sqrt(2)], [1 / np.sqrt(2)]]),
                  delay=1)

# add input and output nodes to the devices
splitter.add_input('i0', amplitude=1)
combiner.add_output('o0')

# add the devices to the physical network
physnet.add_device(splitter)
physnet.add_device(combiner)

# connect the devices using two DeviceLinks
physnet.add_devicelink(
    DeviceLink(startdevice='0', startdevicetype='Splitter', startnode='o0', enddevicetype='Combiner', enddevice='0',
               endnode='i0', phase=5 * np.pi, attenuation=0.5, delay=2))
physnet.add_devicelink(
    DeviceLink(startdevice='0', startdevicetype='Splitter', startnode='o1', enddevicetype='Combiner', enddevice='0',
               endnode='i1', phase=6 * np.pi, attenuation=0.7, delay=3)
)

# visualize the full and simplified
physnet.visualize(full_graph=True, path='./visualizations/Physical_Network_Full', format='svg')
physnet.visualize(full_graph=False, path='./visualizations/Physical_Network_Simplified', format='svg')

# evaluate network
physnet.evaluate()
out = physnet.get_outputs()
print(out)
_images/PhysicalNetworkSimplified.svg

Simplified visualization of physical network.

_images/PhysicalNetworkFull.svg

Full visualization of physical network.

Small Recurrent Network

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# +-----------------------------------------------------------------------------+
# |  Copyright 2019-2020 IBM Corp. All Rights Reserved.                         |
# |                                                                             |
# |  Licensed under the Apache License, Version 2.0 (the "License");            |
# |  you may not use this file except in compliance with the License.           |
# |  You may obtain a copy of the License at                                    |
# |                                                                             |
# |      http://www.apache.org/licenses/LICENSE-2.0                             |
# |                                                                             |
# |  Unless required by applicable law or agreed to in writing, software        |
# |  distributed under the License is distributed on an "AS IS" BASIS,          |
# |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   |
# |  See the License for the specific language governing permissions and        |
# |  limitations under the License.                                             |
# +-----------------------------------------------------------------------------+
# |  Authors: Lorenz K. Mueller, Pascal Stark                                   |
# +-----------------------------------------------------------------------------+
""" Example of a basic recurrent network.

Network topology:

A -> B
^    v
D <- C

"""
from colna.analyticnetwork import Network, Edge

###Define Network

nodes = ['a', 'b', 'c', 'd']
edges = [Edge('a', 'b', phase=0.5, attenuation=1.1, delay=1.0), # some edges can have gain, but the overall gain of loops must be <1
         Edge('b', 'c', phase=1, attenuation=0.9, delay=2.0),
         Edge('c', 'd', phase=0.2, attenuation=0.98, delay=0.5),
         Edge('d', 'a', phase=-0.5, attenuation=0.8, delay=1.5)]

net = Network()
for node in nodes:
    net.add_node(node)
for edge in edges:
    net.add_edge(edge)
net.add_input('a', amplitude=1.0)
net.visualize(path='./visualizations/recurrent', format='svg')

####
#Evaluate Network
####
net.evaluate(amplitude_cutoff=1e-1, max_endpoints=1e6)


####
#Print data
####
print('paths leading to a:', net.get_paths('a'))
print('waves arriving at a:', net.get_result('a'))
net.print_stats()
_images/recurrent_net.svg

Recurrent Network with Testbench

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# +-----------------------------------------------------------------------------+
# |  Copyright 2019-2020 IBM Corp. All Rights Reserved.                         |
# |                                                                             |
# |  Licensed under the Apache License, Version 2.0 (the "License");            |
# |  you may not use this file except in compliance with the License.           |
# |  You may obtain a copy of the License at                                    |
# |                                                                             |
# |      http://www.apache.org/licenses/LICENSE-2.0                             |
# |                                                                             |
# |  Unless required by applicable law or agreed to in writing, software        |
# |  distributed under the License is distributed on an "AS IS" BASIS,          |
# |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   |
# |  See the License for the specific language governing permissions and        |
# |  limitations under the License.                                             |
# +-----------------------------------------------------------------------------+
# |  Authors: Lorenz K. Mueller, Pascal Stark                                   |
# +-----------------------------------------------------------------------------+
""" Creates a very simple recurrent network with a testbench.

This is the example used in the basic usage guide.
The network topology is as follows:

A -> B
^    v
D <- C

A testbench is used to inject time varying signals at node A and B.
"""
from colna.analyticnetwork import Network, Edge, Testbench
import numpy as np
import matplotlib.pyplot as plt

### Create the Network and add the nodes

net = Network()

net.add_node(name='a')
net.add_node(name='b')
net.add_node(name='c')
net.add_node(name='d')


net.add_edge(Edge(start='a',end='b',phase=1,attenuation=0.8,delay=1))
net.add_edge(Edge(start='b',end='c',phase=2,attenuation=0.7,delay=2))
net.add_edge(Edge(start='c',end='d',phase=3,attenuation=0.8,delay=1))
net.add_edge(Edge(start='d',end='a',phase=-1,attenuation=0.9,delay=0.5))

net.visualize(path='./visualizations/recurrent_with_testbench')

### Create a testbench
tb = Testbench(network=net, timestep=0.1) # Timestep should be factor of all delays

x_in_a = np.sin(np.linspace(0,15,500))+1.5 # create the input signal (Dimensino N)
t_in = np.linspace(0, 10, num=501) # create the input time vector (Dimension N+1)
tb.add_input_sequence(node_name='a',x=x_in_a,t=t_in)

# add output nodes to testbench (nodes at which output signal should be recorded)
tb.add_output_node('c')
tb.add_output_node('d')

# evaluate the network (through the testbench)
tb.evaluate_network(amplitude_cutoff=1e-6)

# Calculate the output signal at the output nodes
tb.calculate_output(n_threads=8) # uses multithreading with at most 8 threads
t, x = tb.t_out.transpose(), tb.x_out.transpose()

### Plot the signals

plt.plot(tb.input_t[0][:-1], np.abs(tb.input_x[0][:-1]), 'o') # Input signal
plt.plot(t, np.abs(x), 'x') # Output signal

plt.xlabel('Time')
plt.ylabel('|x|')
plt.legend(['Input', 'Output C', 'Output D'], loc='lower left')
plt.grid()
# plt.savefig('basic_feedforward_tb_output.svg')
plt.show()

Symbolic Feedforward Network

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# +-----------------------------------------------------------------------------+
# |  Copyright 2019-2020 IBM Corp. All Rights Reserved.                         |
# |                                                                             |
# |  Licensed under the Apache License, Version 2.0 (the "License");            |
# |  you may not use this file except in compliance with the License.           |
# |  You may obtain a copy of the License at                                    |
# |                                                                             |
# |      http://www.apache.org/licenses/LICENSE-2.0                             |
# |                                                                             |
# |  Unless required by applicable law or agreed to in writing, software        |
# |  distributed under the License is distributed on an "AS IS" BASIS,          |
# |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   |
# |  See the License for the specific language governing permissions and        |
# |  limitations under the License.                                             |
# +-----------------------------------------------------------------------------+
# |  Authors: Lorenz K. Mueller, Pascal Stark                                   |
# +-----------------------------------------------------------------------------+
""" Creates a very simple feedforward network with constant input and some symbolic edge properties.

The network topology is as follows:

A -> B > D
     v
     C
"""

from colna.analyticnetwork import Network, Edge, SymNum, Testbench

amp1 = SymNum(name='a1', default=1.5, product=True)
amp2 = SymNum(name='a2', default=2.0, product=True)
phi1 = SymNum(name='phi1', default=2.0, product=False)
phi2 = SymNum(name='phi2', default=3.0, product=False)

net = Network()

net.add_node(name='a')
net.add_node(name='b')
net.add_node(name='c')
net.add_node(name='d')

net.add_edge(Edge(start='a',end='b',phase=phi1,attenuation=amp1,delay=1))
net.add_edge(Edge(start='b',end='c',phase=phi2,attenuation=amp2,delay=2))
net.add_edge(Edge(start='b',end='d',phase=3,attenuation=0.4,delay=3))

net.add_input(name='a',amplitude=1.0, phase=0)

net.visualize(path='./visualizations/symbolicfeedforward', format='svg')

net.evaluate(use_shared_default=False, feed_dict=None)

# print('paths leading to c:', net.get_paths('c'))
# print('paths leading to d:', net.get_paths('d'))

print('waves arriving at c:', net.get_result('c'))
print('waves arriving at d:', net.get_result('d'))
net.get_html_result(['c','d'],path='./visualizations/symbolicfeedforward.html')
# Evaluation without feed dictionary, using the default value of each SymNum
waves = [tuple([w.eval(feed_dict=None, use_shared_default=False) if hasattr(w,'eval') else w for w in inner]) for inner in net.get_result('c')]
print('Waves arriving at c:', waves, '\n')
print(net.get_eval_result(name='c',feed_dict=None,use_shared_default=False))

# Evaluation without feed dictionary, with global defaults
waves = [tuple([w.eval(feed_dict=None, use_shared_default=True) if hasattr(w,'eval') else w for w in inner]) for inner in net.get_result('c')]
print('Waves arriving at c:', waves, '\n')
print(net.get_eval_result(name='c',feed_dict=None,use_shared_default=True))

# Evaluation with a feed dictionary
feed = {'a1': 1, 'a2': 2, 'phi1': 2, 'phi2': 4}
waves = [tuple([w.eval(feed_dict=feed, use_shared_default=True) if hasattr(w,'eval') else w for w in inner]) for inner in net.get_result('c')]
print('Waves arriving at c:', waves, '\n')
print(net.get_eval_result(name='c',feed_dict=feed,use_shared_default=True))

# Evaluation with a partial feed dictionary
feed = {'a1': 0.5, 'phi2': 4}
waves = [tuple([w.eval(feed_dict=feed, use_shared_default=True) if hasattr(w,'eval') else w for w in inner]) for inner in net.get_result('c')]
print('Waves arriving at c:', waves, '\n')
print(net.get_eval_result(name='c',feed_dict=feed,use_shared_default=True))
_images/symbolicfeedforward.svg

Symbolic Feedforward Network with Testbench

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# +-----------------------------------------------------------------------------+
# |  Copyright 2019-2020 IBM Corp. All Rights Reserved.                         |
# |                                                                             |
# |  Licensed under the Apache License, Version 2.0 (the "License");            |
# |  you may not use this file except in compliance with the License.           |
# |  You may obtain a copy of the License at                                    |
# |                                                                             |
# |      http://www.apache.org/licenses/LICENSE-2.0                             |
# |                                                                             |
# |  Unless required by applicable law or agreed to in writing, software        |
# |  distributed under the License is distributed on an "AS IS" BASIS,          |
# |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   |
# |  See the License for the specific language governing permissions and        |
# |  limitations under the License.                                             |
# +-----------------------------------------------------------------------------+
# |  Authors: Lorenz K. Mueller, Pascal Stark                                   |
# +-----------------------------------------------------------------------------+
""" Creates a very simple recurrent network with some symbolic edge properties and a testbench.

The network topology is as follows:

A -> B > D
     v
     C
"""

from colna.analyticnetwork import Network, Edge, SymNum
from colna.analyticnetwork import Testbench
import numpy as np
import matplotlib.pyplot as plt

amp1 = SymNum(name='a1', default=1.5, product=True)
amp2 = SymNum(name='a2', default=2, product=True)
phi1 = SymNum(name='phi1', default=2, product=False)
phi2 = SymNum(name='phi2', default=3, product=False)

net = Network()

net.add_node(name='a')
net.add_node(name='b')
net.add_node(name='c')
net.add_node(name='d')

net.add_edge(Edge(start='a',end='b',phase=phi1,attenuation=amp1,delay=1))
net.add_edge(Edge(start='b',end='c',phase=phi2,attenuation=amp2,delay=2))
net.add_edge(Edge(start='b',end='d',phase=3,attenuation=0.4,delay=3))

### Create a testbench with a feed dictionary
tb = Testbench(network=net, timestep=0.1, feed_dict={'a1':0.2,'a2':1.5,'phi1':2,'phi2':3})

x_in_a = np.sin(np.linspace(0,15,500))+1.5 # create the input signal (Dimensino N)
t_in = np.linspace(0, 10, num=501) # create the input time vector (Dimension N+1)
tb.add_input_sequence(node_name='a',x=x_in_a,t=t_in)
tb.add_output_node(node_name='c')
tb.add_output_node(node_name='d')

# evaluate the network (through the testbench)
tb.evaluate_network(amplitude_cutoff=1e-3,use_shared_default=False)

# Calculate the output signal at the output nodes
tb.calculate_output(n_threads=8, use_shared_default=False) # uses multithreading with at most 8 threads
t, x = tb.t_out.transpose(), tb.x_out.transpose()

### Plot the signals
plt.plot(tb.input_t[0][:-1], np.abs(tb.input_x[0][:-1]), 'o') # Input signal
plt.plot(t, np.abs(x), 'x') # Output signal


# Set a different feed dict and recompute the
tb.set_feed_dict({'a1':1.2,'a2':1.5,'phi1':2,'phi2':3})
tb.calculate_output(n_threads=8, use_shared_default=False) # uses multithreading with at most 8 threads
t, x = tb.t_out.transpose(), tb.x_out.transpose()

### Plot the signals
plt.plot(t, np.abs(x), 'x') # Output signal

### Format the plot
plt.xlabel('Time')
plt.ylabel('|x|')
plt.legend(['Input', 'Output C', 'Output D', 'Output C (Feed Dict 2)', 'Output D (Feed Dict 2)'], loc='lower left')
plt.grid()
# plt.savefig('./visualizations/symnum_feedforward_tb_output.svg')
plt.show()

Symbolic Recurrent Network

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# +-----------------------------------------------------------------------------+
# |  Copyright 2019-2020 IBM Corp. All Rights Reserved.                         |
# |                                                                             |
# |  Licensed under the Apache License, Version 2.0 (the "License");            |
# |  you may not use this file except in compliance with the License.           |
# |  You may obtain a copy of the License at                                    |
# |                                                                             |
# |      http://www.apache.org/licenses/LICENSE-2.0                             |
# |                                                                             |
# |  Unless required by applicable law or agreed to in writing, software        |
# |  distributed under the License is distributed on an "AS IS" BASIS,          |
# |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   |
# |  See the License for the specific language governing permissions and        |
# |  limitations under the License.                                             |
# +-----------------------------------------------------------------------------+
# |  Authors: Lorenz K. Mueller, Pascal Stark                                   |
# +-----------------------------------------------------------------------------+
""" Example of a basic recurrent network with symbolic variables.

Network topology:

A -> B
^    v
D <- C

"""
from colna.analyticnetwork import Network, Edge, SymNum


####
# Define Network
####
nodes = ['a', 'b', 'c', 'd']
edges = [Edge('a', 'b', phase=SymNum('ph1', default=0.4, product=False), attenuation=0.95, delay=1.0),
         Edge('b', 'c', .5, SymNum('amp1', default=0.95), 1.),
         Edge('c', 'd', .5, 0.95, SymNum('del1', default=1.2, product= False)),
         Edge('d', 'a', .5, 0.95, 1.)]

net = Network()
for node in nodes:
    net.add_node(node)
for edge in edges:
    net.add_edge(edge)
net.add_input('a', amplitude=1.0)

net.visualize(path='./visualizations/symbolicrecurrent')

####
# Evaluate Network
####
net.evaluate(amplitude_cutoff=1e-2, max_endpoints=1e6, use_shared_default=False)

print('paths leading to a:', net.get_paths('a'))
waves = [tuple([w.eval() if hasattr(w, 'eval') else w for w in inner]) for inner in net.get_result('a')]
print('waves arriving at a:', waves, '\n')
net.print_stats()

####
# Inserting variable values
###
waves = [tuple([w.eval(feed_dict={'amp1': .5, 'ph1': .2}) if hasattr(w, 'eval') else w for w in inner])
         for inner in net.get_result('a')]
print('waves arriving at a (different variable values):', waves, '\n')

####
# Showing symbolic values
####
print('symbolic values', net.get_result('a'), '\n')

Large Symbolic Recurrent Network

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
# +-----------------------------------------------------------------------------+
# |  Copyright 2019-2020 IBM Corp. All Rights Reserved.                         |
# |                                                                             |
# |  Licensed under the Apache License, Version 2.0 (the "License");            |
# |  you may not use this file except in compliance with the License.           |
# |  You may obtain a copy of the License at                                    |
# |                                                                             |
# |      http://www.apache.org/licenses/LICENSE-2.0                             |
# |                                                                             |
# |  Unless required by applicable law or agreed to in writing, software        |
# |  distributed under the License is distributed on an "AS IS" BASIS,          |
# |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   |
# |  See the License for the specific language governing permissions and        |
# |  limitations under the License.                                             |
# +-----------------------------------------------------------------------------+
# |  Authors: Lorenz K. Mueller, Pascal Stark                                   |
# +-----------------------------------------------------------------------------+
"""
Network topology:

P <- N <- L <- J
v    v    v    ^
O <- M <- K <- I
v    v    ^    ^
A -> C -> E -> G
v    v    ^    ^
B -> D -> F -> H
"""
from colna.analyticnetwork import Network, Edge, SymNum
import numpy as np
import matplotlib.pyplot as plt

# 4x4 network



class SymbolicEdge(Edge):
    def __init__(self, start, end, name=None, phase=.4, attenuation=.75, delay=1.0):
        super().__init__(start, end, phase, attenuation, delay)
        if name is None:
            name = "Edge_"+start+end
        self.attenuation = SymNum(name, default=0.75)


####
# Define Network
####
nodes = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p']
edges = [SymbolicEdge('a', 'b'), SymbolicEdge('a', 'c'), SymbolicEdge('b', 'd'), SymbolicEdge('c', 'd'),
         SymbolicEdge('c', 'e'), SymbolicEdge('d', 'f'), SymbolicEdge('f', 'e'), SymbolicEdge('e', 'g'),
         SymbolicEdge('f', 'h'), SymbolicEdge('h', 'g'), SymbolicEdge('g', 'i'), SymbolicEdge('e', 'k'),
         SymbolicEdge('i', 'j'), SymbolicEdge('i', 'k'), SymbolicEdge('j', 'l'), SymbolicEdge('l', 'k'),
         SymbolicEdge('l', 'n'), SymbolicEdge('k', 'm'), SymbolicEdge('n', 'm'), SymbolicEdge('n', 'p'),
         SymbolicEdge('p', 'o'), SymbolicEdge('m', 'o'), SymbolicEdge('o', 'a'), SymbolicEdge('m', 'c')]

net = Network()
for node in nodes:
    net.add_node(node)
for edge in edges:
    net.add_edge(edge)
net.add_input('a', amplitude=1.0)
for i, edge in enumerate(net.edges):
    edge.phase = np.random.uniform(0, 2 * np.pi)

####
# Evaluate Network
####
net.evaluate(amplitude_cutoff=5e-3, max_endpoints=1e6,use_shared_default=True)
waves = [tuple([w.eval() if hasattr(w,'eval') else w for w in inner]) for inner in net.get_result('a')]

####
# Print and plot
####
for node in net.nodes:
    print('number of paths to ' + node + ':', len(net.get_paths(node)))
print('final path to a added:', net.get_paths('a')[-1])
print('10 first waves arriving at a:', waves[:10])
net.print_stats()

#####
# Reset variable
#####
feed = {"Edge_ab": 0.8}
waves = [tuple([w.eval(feed_dict=feed) if hasattr(w,'eval') else w for w in inner]) for inner in net.get_result('a')]
print('10 first waves arriving at a:', waves[:10], '\n')

####
# Print Symbolic values
####
print('3 last waves at a (symbolic)', net.get_result('a')[-3:], '\n')

#####
# Plot
#####
phases = np.asarray([val[1].eval() if hasattr(val[1], 'eval') else val[1] for val in net.get_result('a')])
phases = phases % 2 * np.pi
amplitudes = np.asarray([val[0].eval() if hasattr(val[0], 'eval') else val[0] for val in net.get_result('a')])
plt.hist(phases, weights=amplitudes, bins=30)
plt.title("amplitude weighted, binned phase contributions to a")
plt.ylabel('amplitude')
plt.xlabel('phase')
plt.show()