Skip to content

Commit a94c8a3

Browse files
Merge pull request #31 from agustin-recoba/feature/usability
Varias mejoras de usabilidad y separación de responsabilidades
2 parents ea39cc2 + bf59e17 commit a94c8a3

31 files changed

+1469
-1103
lines changed

Diff for: docs/conf.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@
7979
# The short X.Y version.
8080
#
8181
# This should match the version in pyproject.toml
82-
version = "1.0.5"
82+
version = "1.0.7"
8383
# The full version, including alpha/beta/rc tags.
84-
release = "1.0.5.dev"
84+
release = "1.0.7.dev"
8585

8686
# The language for content autogenerated by Sphinx. Refer to documentation
8787
# for a list of supported languages.

Diff for: docs/notebooks/animation.ipynb

+866-835
Large diffs are not rendered by default.

Diff for: docs/notebooks/behavior_viz.ipynb

+1-5
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@
1616
},
1717
"outputs": [],
1818
"source": [
19-
"# If pydistsim is not installed and the script is run from docs/notebooks directory\n",
20-
"# import sys\n",
21-
"# sys.path.append(\"../../\")\n",
22-
"\n",
2319
"# for interactive plots\n",
2420
"%matplotlib notebook\n",
2521
"\n",
@@ -7333,7 +7329,7 @@
73337329
"name": "python",
73347330
"nbconvert_exporter": "python",
73357331
"pygments_lexer": "ipython3",
7336-
"version": "3.11.0rc1"
7332+
"version": "3.11.0"
73377333
}
73387334
},
73397335
"nbformat": 4,

Diff for: docs/notebooks/benchmarking.ipynb

+78-42
Large diffs are not rendered by default.

Diff for: docs/notebooks/custom_observer.ipynb

+24-7
Large diffs are not rendered by default.

Diff for: docs/notebooks/hello_distributed_world.ipynb

+24-24
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
},
1414
{
1515
"cell_type": "code",
16-
"execution_count": 1,
16+
"execution_count": 2,
1717
"metadata": {
1818
"id": "bQX5hbAmIKRO",
1919
"outputId": "10242ef7-4936-4970-9711-0379033b9d30"
@@ -49,7 +49,7 @@
4949
},
5050
{
5151
"cell_type": "code",
52-
"execution_count": 2,
52+
"execution_count": 3,
5353
"metadata": {},
5454
"outputs": [],
5555
"source": [
@@ -84,7 +84,7 @@
8484
},
8585
{
8686
"cell_type": "code",
87-
"execution_count": 3,
87+
"execution_count": 4,
8888
"metadata": {
8989
"id": "dUU7kZ1wIKRR"
9090
},
@@ -104,7 +104,7 @@
104104
},
105105
{
106106
"cell_type": "code",
107-
"execution_count": 4,
107+
"execution_count": 5,
108108
"metadata": {
109109
"id": "-vesDvtnIKRS",
110110
"outputId": "2f347168-f241-4d1e-c3c3-38ac871f9e24"
@@ -113,10 +113,10 @@
113113
{
114114
"data": {
115115
"text/plain": [
116-
"<pydistsim.network.network.BidirectionalNetwork at 0x7f5dfb676a50>"
116+
"<pydistsim.network.network.BidirectionalNetwork at 0x7fc1769ae210>"
117117
]
118118
},
119-
"execution_count": 4,
119+
"execution_count": 5,
120120
"metadata": {},
121121
"output_type": "execute_result"
122122
}
@@ -136,7 +136,7 @@
136136
},
137137
{
138138
"cell_type": "code",
139-
"execution_count": 16,
139+
"execution_count": 17,
140140
"metadata": {
141141
"id": "q0JVUYBcIKRS",
142142
"outputId": "16c3bf7f-07f3-4a14-ea51-7717abb88237"
@@ -149,7 +149,7 @@
149149
"<Figure size 640x480 with 1 Axes>"
150150
]
151151
},
152-
"execution_count": 16,
152+
"execution_count": 17,
153153
"metadata": {},
154154
"output_type": "execute_result"
155155
}
@@ -167,14 +167,14 @@
167167
},
168168
{
169169
"cell_type": "code",
170-
"execution_count": 6,
170+
"execution_count": 7,
171171
"metadata": {},
172172
"outputs": [
173173
{
174174
"name": "stdout",
175175
"output_type": "stream",
176176
"text": [
177-
"\u001b[32m2024-09-02 21:37:09.829\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpydistsim.simulation\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m58\u001b[0m - \u001b[1mSimulation 0x7f5dfb567710 created successfully.\u001b[0m\n"
177+
"\u001b[32m2024-09-22 21:10:53.707\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpydistsim.simulation\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m58\u001b[0m - \u001b[1mSimulation 0x7fc1a3f38e50 created successfully.\u001b[0m\n"
178178
]
179179
}
180180
],
@@ -197,7 +197,7 @@
197197
},
198198
{
199199
"cell_type": "code",
200-
"execution_count": 7,
200+
"execution_count": 8,
201201
"metadata": {
202202
"id": "wwaAh2VeIKRS"
203203
},
@@ -304,14 +304,14 @@
304304
},
305305
{
306306
"cell_type": "code",
307-
"execution_count": 8,
307+
"execution_count": 9,
308308
"metadata": {},
309309
"outputs": [
310310
{
311311
"name": "stdout",
312312
"output_type": "stream",
313313
"text": [
314-
"\u001b[32m2024-09-02 21:37:09.862\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpydistsim.simulation\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m58\u001b[0m - \u001b[1mSimulation 0x7f5dfb54e090 created successfully.\u001b[0m\n"
314+
"\u001b[32m2024-09-22 21:10:53.735\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpydistsim.simulation\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m58\u001b[0m - \u001b[1mSimulation 0x7fc1746c2c90 created successfully.\u001b[0m\n"
315315
]
316316
}
317317
],
@@ -339,14 +339,14 @@
339339
},
340340
{
341341
"cell_type": "code",
342-
"execution_count": 9,
342+
"execution_count": 10,
343343
"metadata": {},
344344
"outputs": [
345345
{
346346
"name": "stdout",
347347
"output_type": "stream",
348348
"text": [
349-
"\u001b[32m2024-09-02 21:37:09.881\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpydistsim.simulation\u001b[0m:\u001b[36m_run_algorithm\u001b[0m:\u001b[36m147\u001b[0m - \u001b[1m[Echo] Algorithm finished\u001b[0m\n"
349+
"\u001b[32m2024-09-22 21:10:53.750\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpydistsim.simulation\u001b[0m:\u001b[36m_run_algorithm\u001b[0m:\u001b[36m147\u001b[0m - \u001b[1m[Echo] Algorithm finished\u001b[0m\n"
350350
]
351351
}
352352
],
@@ -365,7 +365,7 @@
365365
},
366366
{
367367
"cell_type": "code",
368-
"execution_count": 10,
368+
"execution_count": 11,
369369
"metadata": {
370370
"id": "H2rsruiUIKRT",
371371
"outputId": "32e92d06-26d8-4892-d661-a84dabfe411e"
@@ -398,7 +398,7 @@
398398
},
399399
{
400400
"cell_type": "code",
401-
"execution_count": 11,
401+
"execution_count": 12,
402402
"metadata": {
403403
"id": "mcc7XWTRIKRU",
404404
"outputId": "d437f0f2-9edd-4a33-c988-3be908afde73"
@@ -410,7 +410,7 @@
410410
"{'index': 0, 'step': 17, 'finished': True}"
411411
]
412412
},
413-
"execution_count": 11,
413+
"execution_count": 12,
414414
"metadata": {},
415415
"output_type": "execute_result"
416416
}
@@ -430,7 +430,7 @@
430430
},
431431
{
432432
"cell_type": "code",
433-
"execution_count": 12,
433+
"execution_count": 13,
434434
"metadata": {
435435
"id": "gprEPr49IKRU",
436436
"outputId": "439d8dbd-65e5-41f4-f5f7-2d9bce9eb7bd"
@@ -453,7 +453,7 @@
453453
},
454454
{
455455
"cell_type": "code",
456-
"execution_count": 13,
456+
"execution_count": 14,
457457
"metadata": {
458458
"id": "jMTwzLRkIKRU",
459459
"outputId": "a1948897-04cd-4bc1-cb97-a45723f30493"
@@ -465,7 +465,7 @@
465465
"{'index': 0, 'step': 1, 'finished': False}"
466466
]
467467
},
468-
"execution_count": 13,
468+
"execution_count": 14,
469469
"metadata": {},
470470
"output_type": "execute_result"
471471
}
@@ -485,7 +485,7 @@
485485
},
486486
{
487487
"cell_type": "code",
488-
"execution_count": 14,
488+
"execution_count": 15,
489489
"metadata": {
490490
"id": "3AgVUCXcIKRU",
491491
"outputId": "e4dc9056-b8d0-435a-bd33-9892b9fc7e10"
@@ -507,7 +507,7 @@
507507
},
508508
{
509509
"cell_type": "code",
510-
"execution_count": 15,
510+
"execution_count": 16,
511511
"metadata": {
512512
"id": "wG4Jq_s7IKRU",
513513
"outputId": "940c51e0-35c6-41ea-b511-81b6a51acf9f"
@@ -517,7 +517,7 @@
517517
"name": "stdout",
518518
"output_type": "stream",
519519
"text": [
520-
"\u001b[32m2024-09-02 21:37:09.934\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpydistsim.simulation\u001b[0m:\u001b[36m_run_algorithm\u001b[0m:\u001b[36m147\u001b[0m - \u001b[1m[Echo] Algorithm finished\u001b[0m\n"
520+
"\u001b[32m2024-09-22 21:10:53.828\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpydistsim.simulation\u001b[0m:\u001b[36m_run_algorithm\u001b[0m:\u001b[36m147\u001b[0m - \u001b[1m[Echo] Algorithm finished\u001b[0m\n"
521521
]
522522
}
523523
],

Diff for: docs/notebooks/network_generators.ipynb

+1-5
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@
1616
},
1717
"outputs": [],
1818
"source": [
19-
"# If pydistsim is not installed and the script is run from docs/notebooks directory\n",
20-
"# import sys\n",
21-
"# sys.path.append(\"../../\")\n",
22-
"\n",
2319
"# for interactive plots\n",
2420
"%matplotlib notebook\n",
2521
"\n",
@@ -278,7 +274,7 @@
278274
"name": "python",
279275
"nbconvert_exporter": "python",
280276
"pygments_lexer": "ipython3",
281-
"version": "3.11.0rc1"
277+
"version": "3.11.0"
282278
}
283279
},
284280
"nbformat": 4,

Diff for: docs/notebooks/tree_construction_viz.ipynb

+1-5
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@
1919
},
2020
"outputs": [],
2121
"source": [
22-
"# If pydistsim is not installed and the script is run from docs/notebooks directory\n",
23-
"# import sys\n",
24-
"# sys.path.append(\"../../\")\n",
25-
"\n",
2622
"# for interactive plots\n",
2723
"%matplotlib notebook\n",
2824
"\n",
@@ -1600,7 +1596,7 @@
16001596
"name": "python",
16011597
"nbconvert_exporter": "python",
16021598
"pygments_lexer": "ipython3",
1603-
"version": "3.11.0rc1"
1599+
"version": "3.11.0"
16041600
}
16051601
},
16061602
"nbformat": 4,

Diff for: docs/reference/networkgenerator.rst

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ which are defined like this:
5151
* gradually increase number of nodes up to `n_max`
5252
* if comm_range is None gradually increase nodes commRange
5353
* if still not connected raise an exception
54+
5455
3. if `degree` condition is defined and current network degree is
5556
* lower - repeat measures from the last step to increase current
5657
network degree

Diff for: docs/tutorials/implementing.rst

+66-7
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,71 @@ sending messages and setting alarms.
5151
Actions without an implementation will only log a warning message, so for no-ops, it is not necessary to implement
5252
anything.
5353

54-
*************************
54+
55+
Node's own id and neighbor labels
56+
=================================
57+
58+
The framework is designed to prevent the programmer from accessing information that should not be available to the
59+
nodes. For this reason, we provide two classes that act as proxies for the node and its neighbors, respectively.
60+
61+
62+
`NodeAccess` class
63+
------------------
64+
65+
A :class:`NodeAccess` instance represents a node's own view, encapsulating the knowledge gathered so far (inside the
66+
``memory`` attribute) and inherent of the node (such as who are it's neighbors).
67+
68+
By default, this class allows read-only access to the node's ``clock`` attribute and read-and-write access to the
69+
``memory`` and ``status`` attributes.
70+
71+
In addition to this attributes, each NodeAccess instance has an integer ``id`` attribute, by default it's random and
72+
won't be unique in the network.
73+
74+
75+
These are the two main ways a programmer comes across a :class:`NodeAccess` instance:
76+
77+
.. code-block:: python
78+
79+
@Status.IDLE
80+
def receiving(self, node: NodeAccess, message: Message):
81+
82+
83+
def initializer(self):
84+
for node in self.nwm.nodes():
85+
86+
87+
node.memory['SPAM_COUNT'] = 0
88+
89+
90+
for node in self.network.nodes():
91+
NOT A NodeAccess INSTANCE
92+
93+
`NeighborLabel` class
94+
---------------------
95+
96+
A :class:`NeighborLabel` instance represents the knowledge of the neighbor respect to current processing node.
97+
98+
Similar to the :class:`NodeAccess` class, the :class:`NeighborLabel` instances have an integer ``id`` attribute, by default it's random
99+
and won't match any other ``id`` in the network. It's only used to identify that neighbor among the other neighbors.
100+
101+
These are the two main ways a programmer comes across a :class:`NeighborLabel` instance:
102+
103+
.. code-block:: python
104+
105+
@Status.IDLE
106+
def receiving(self, node: NodeAccess, message: Message):
107+
source = message.source # The node that sent the message
108+
109+
110+
for neighbor in node.neighbors():
111+
112+
113+
55114
"The Santoro's interface"
56-
*************************
115+
=========================
57116

58117
Send a message
59-
==============
118+
--------------
60119
The :meth:`NodeAlgorithm.send_msg` method receives a source node and a message. The message will be sent to the destinations
61120
specified in the message itself. The destinations must be a list of nodes or a single node. The message will be sent to
62121
all the destinations.
@@ -66,20 +125,20 @@ The :meth:`NodeAlgorithm.send` method receives a source node, a message content
66125
a header. Is equivalent to the :meth:`NodeAlgorithm.send_msg` method, but the message is created automatically.
67126

68127
Set an alarm
69-
============
128+
------------
70129
The :meth:`NodeAlgorithm.set_alarm` method receives a node and a time. An empty message will be sent to the node after
71130
the time has passed. The time is in algorithm steps, which behavior varies according to the algorithm and the simulation\
72131
parameters.
73132

74133

75134
Check the extended interface methods for advanced use of the alarm mechanism.
76135

77-
*******************************************
136+
78137
Helper functions and the extended interface
79-
*******************************************
138+
===========================================
80139

81140
Alarm management
82-
================
141+
----------------
83142

84143
The :meth:`NodeAlgorithm.set_alarm` method receives an extra, optional, parameter, the message. This message will be
85144
sent to the node when the alarm goes off. The message must be an instance of :class:`Message`. This, however, is not

Diff for: pydistsim/algorithm/base_algorithm.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,10 @@ def check_restrictions(self):
171171
if issubclass(restriction, CheckableRestriction):
172172
logger.debug("Checking restriction {}.", restriction.__name__)
173173
if not restriction.check(self.network):
174-
raise AlgorithmException(f"Restriction {restriction.__name__} not satisfied for this network.")
174+
raise AlgorithmException(
175+
f"Restriction {restriction.__name__} not satisfied for this network.\n"
176+
+ restriction.get_explanation(self.network)
177+
)
175178

176179
def apply_restrictions(self):
177180
"""

0 commit comments

Comments
 (0)