Skip to content

Commit 0f217d3

Browse files
authored
Merge branch 'master' into validate_routes_uncompressed
2 parents c6691d2 + fe8743b commit 0f217d3

24 files changed

Lines changed: 676 additions & 104 deletions

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ requires = ["setuptools"]
1717
build-backend = "setuptools.build_meta"
1818

1919
[[tool.mypy.overrides]]
20-
module = ["matplotlib", "matplotlib.*", "pyNN.*", "quantities", "neo", "neo.*", "scipy", "scipy.*", "lazyarray"]
20+
module = ["csa", "docstring_parser", "matplotlib", "matplotlib.*", "pyNN.*", "quantities", "neo", "neo.*", "scipy", "scipy.*", "lazyarray", "testfixtures"]
2121
ignore_missing_imports = true

spynnaker/pyNN/models/neural_projections/connectors/abstract_connector.py

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
import logging
1616
import math
1717
import re
18-
from typing import Dict, Optional, Sequence, Tuple, Union, TYPE_CHECKING
18+
from typing import Any, Dict, Optional, Sequence, Tuple, Union, TYPE_CHECKING
1919
from typing_extensions import Never
2020

2121
import numpy
2222
from numpy import float64, uint32, uint16, uint8
2323
from numpy.typing import NDArray
2424

25+
from pyNN import descriptions
2526
from pyNN.random import NumpyRNG, RandomDistribution
2627
from pyNN.space import Space
2728

@@ -76,7 +77,8 @@ class AbstractConnector(object, metaclass=AbstractBase):
7677
"__safe",
7778
"__space",
7879
"__verbose",
79-
"__param_seeds")
80+
"__param_seeds",
81+
"__used")
8082

8183
def __init__(self, safe: bool = True, callback: None = None,
8284
verbose: bool = False):
@@ -102,6 +104,7 @@ def __init__(self, safe: bool = True, callback: None = None,
102104
self.__n_clipped_delays = numpy.int64(0)
103105
self.__min_delay = 0.0
104106
self.__param_seeds: Dict[Tuple[int, int], int] = dict()
107+
self.__used = False
105108

106109
def set_space(self, space: Space) -> None:
107110
"""
@@ -573,37 +576,20 @@ def safe(self) -> bool:
573576
"""
574577
return self.__safe
575578

576-
@safe.setter
577-
def safe(self, new_value: bool) -> None:
578-
self.__safe = new_value
579-
580579
@property
581580
def space(self) -> Optional[Space]:
582581
"""
583582
The space object (may be updated after instantiation).
584583
"""
585584
return self.__space
586585

587-
@space.setter
588-
def space(self, new_value: Space) -> None:
589-
"""
590-
Set the space object (allowed after instantiation).
591-
592-
:param new_value:
593-
"""
594-
self.__space = new_value
595-
596586
@property
597587
def verbose(self) -> bool:
598588
"""
599589
verbose value supplied by user
600590
"""
601591
return self.__verbose
602592

603-
@verbose.setter
604-
def verbose(self, new_value: bool) -> None:
605-
self.__verbose = new_value
606-
607593
def get_connected_vertices(
608594
self, s_info: SynapseInformation, source_vertex: ApplicationVertex,
609595
target_vertex: ApplicationVertex) -> Sequence[
@@ -679,3 +665,82 @@ def validate_connection(
679665
"Using a projection where the source or target is a "
680666
"PopulationView on a multi-dimensional Population is not "
681667
"supported")
668+
669+
def get_parameters(self) -> Dict[str, Any]:
670+
"""
671+
A list of parameters that would recreate this connector.
672+
673+
May not be exactly the same as the ones used to construct this.
674+
675+
Will also not include any information or changes added by later calls.
676+
677+
:return: A map of the init parameters to the values passed in.
678+
"""
679+
# The default is error
680+
# This to avoid missing parameters in user Connectors
681+
raise NotImplementedError(
682+
f"{type(self)} does not implement "
683+
f"Standard pyNN get_parameters method")
684+
685+
def _get_parameters(self) -> Dict[str, Any]:
686+
"""
687+
:return: A map of the init parameters to the values passed in.
688+
"""
689+
return {
690+
"safe": self.safe,
691+
"verbose": self.verbose,
692+
"callback": None
693+
}
694+
695+
def clone(self) -> "AbstractConnector":
696+
"""
697+
Create a clone of the Connector at init point
698+
699+
This is a best effort attempt and its use is not recommended
700+
701+
:return: A clone of the Connector. Ignoring any SynapseInformation
702+
"""
703+
theType = type(self)
704+
params = self.get_parameters()
705+
logger.warning(
706+
f"Cloning type{self} which may lead to incorrect results.")
707+
return theType(**params)
708+
709+
def get_unused(self) -> "AbstractConnector":
710+
"""
711+
Checks the Connector is unused and clones if needed
712+
713+
This method should just check the connector is unused,
714+
mark it as used and return it.
715+
716+
If the Connector is used will attempt to make a clone,
717+
log warning that this is not recommended and may be incorrect,
718+
and returns the clone.
719+
720+
:return: Ideally this Connector
721+
"""
722+
if self.__used:
723+
logger.warning(
724+
"Reusing Connectors in sPyNNaker is not recommended")
725+
clone = self.clone()
726+
# call get_unused to mark used
727+
return clone.get_unused()
728+
self.__used = True
729+
return self
730+
731+
def describe(self, template: Optional[str] = None,
732+
engine: str = 'default') -> str:
733+
"""
734+
Returns a human-readable description of the connection method.
735+
736+
The output may be customized by specifying a different template
737+
together with an associated template engine (see pyNN.descriptions).
738+
739+
If template is None,
740+
then a dictionary containing the template context will be returned.
741+
742+
:return: A human-readable description of the connector.
743+
"""
744+
context = {"Type": self.__class__.__name__}
745+
context.update(self.get_parameters())
746+
return descriptions.render(engine, template, context)

spynnaker/pyNN/models/neural_projections/connectors/all_but_me_connector.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
from __future__ import annotations
15-
from typing import Sequence, Optional, TYPE_CHECKING
15+
from typing import Any, Dict, Sequence, Optional, TYPE_CHECKING
1616

1717
import numpy
1818
from numpy import uint32
@@ -92,6 +92,13 @@ def __init__(self, n_neurons_per_group: Optional[int] = None,
9292
self.__weights = weights
9393
self.__check_weights(weights, n_neurons_per_group)
9494

95+
@overrides(AbstractGenerateConnectorOnMachine.get_parameters)
96+
def get_parameters(self) -> Dict[str, Any]:
97+
parameters = self._get_parameters()
98+
parameters["n_neurons_per_group"] = self.__n_neurons_per_group
99+
parameters["weights"] = self.__weights
100+
return parameters
101+
95102
def __check_weights(self, weights: Optional[NDArray[numpy.float64]],
96103
n_neurons_per_group: Optional[int]) -> None:
97104
if weights is not None and n_neurons_per_group is not None:

spynnaker/pyNN/models/neural_projections/connectors/all_to_all_connector.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
from __future__ import annotations
15-
from typing import Sequence, Optional, TYPE_CHECKING
15+
from typing import Any, Dict, Optional, Sequence, TYPE_CHECKING
1616

1717
import numpy
1818
from numpy import uint32
@@ -65,6 +65,12 @@ def __init__(self, allow_self_connections: bool = True, safe: bool = True,
6565
super().__init__(safe, callback, verbose)
6666
self.__allow_self_connections = allow_self_connections
6767

68+
@overrides(AbstractGenerateConnectorOnMachine.get_parameters)
69+
def get_parameters(self) -> Dict[str, Any]:
70+
parameters = self._get_parameters()
71+
parameters["allow_self_connections"] = self.allow_self_connections
72+
return parameters
73+
6874
@overrides(AbstractConnector.get_delay_maximum)
6975
def get_delay_maximum(self, synapse_info: SynapseInformation) -> float:
7076
return self._get_delay_maximum(
@@ -152,10 +158,6 @@ def allow_self_connections(self) -> bool:
152158
"""
153159
return self.__allow_self_connections
154160

155-
@allow_self_connections.setter
156-
def allow_self_connections(self, new_value: bool) -> None:
157-
self.__allow_self_connections = new_value
158-
159161
@property
160162
@overrides(AbstractGenerateConnectorOnMachine.gen_connector_id)
161163
def gen_connector_id(self) -> int:

spynnaker/pyNN/models/neural_projections/connectors/array_connector.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414

1515
from __future__ import annotations
16-
from typing import Sequence, Optional, TYPE_CHECKING
16+
from typing import Any, Dict, Optional, Sequence, TYPE_CHECKING
1717

1818
import numpy
1919
from numpy import uint8
@@ -76,6 +76,12 @@ def __init__(self, array: NDArray[uint8], safe: bool = True,
7676
self.__n_total_connections = n_total_connections
7777
self.__array_dims = dims
7878

79+
@overrides(AbstractConnector.get_parameters)
80+
def get_parameters(self) -> Dict[str, Any]:
81+
parameters = self._get_parameters()
82+
parameters["array"] = self.__array
83+
return parameters
84+
7985
@overrides(AbstractConnector.get_delay_maximum)
8086
def get_delay_maximum(self, synapse_info: SynapseInformation) -> float:
8187
return self._get_delay_maximum(

spynnaker/pyNN/models/neural_projections/connectors/convolution_connector.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from __future__ import annotations
1818
from collections.abc import (Iterable, Sequence)
1919
from typing import (
20-
List, Optional, Sequence as TSequence, Tuple, Union,
20+
Any, Dict, List, Optional, Sequence as TSequence, Tuple, Union,
2121
cast, overload, TYPE_CHECKING)
2222

2323
import numpy
@@ -169,10 +169,34 @@ def __init__(self, kernel_weights: _Weights,
169169
self.__pool_stride = self.__pool_shape
170170
if self.__pool_shape is not None:
171171
self.__kernel_weights /= numpy.prod(self.__pool_shape)
172-
173172
self.__positive_receptor_type = positive_receptor_type
174173
self.__negative_receptor_type = negative_receptor_type
175174

175+
@overrides(AbstractConnector.get_parameters)
176+
def get_parameters(self) -> Dict[str, Any]:
177+
parameters = self._get_parameters()
178+
if self.__pool_shape is None:
179+
parameters["kernel_weights"] = self.__kernel_weights
180+
else:
181+
parameters["kernel_weights"] = (
182+
self.__kernel_weights * numpy.prod(self.__pool_shape))
183+
# Now included in weights
184+
parameters["kernel_shape"] = None
185+
parameters["strides"] = tuple(self.__strides)
186+
parameters["padding"] = tuple(self.__padding_shape)
187+
if self.__pool_shape is None:
188+
parameters["pool_shape"] = None
189+
else:
190+
parameters["pool_shape"] = tuple(self.__pool_shape)
191+
if self.__pool_stride is None:
192+
parameters["pool_stride"] = None
193+
else:
194+
parameters["pool_stride"] = tuple(self.__pool_stride)
195+
parameters["positive_receptor_type"] = self.__positive_receptor_type
196+
parameters["negative_receptor_type"] = self.__negative_receptor_type
197+
parameters["filter_edges"] = self.__filter_edges
198+
return parameters
199+
176200
@property
177201
def positive_receptor_type(self) -> str:
178202
"""

spynnaker/pyNN/models/neural_projections/connectors/csa_connector.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
from __future__ import annotations
15-
from typing import List, Optional, Tuple, TYPE_CHECKING, Sequence
15+
from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING, Sequence
1616

1717
import numpy
1818
from numpy.typing import NDArray
@@ -81,6 +81,12 @@ def __init__(self, cset: CSet, safe: bool = True, callback: None = None,
8181
self.__full_connection_set: Optional[List[CSet]] = None
8282
self.__full_cset: Optional[List[CSet]] = None
8383

84+
@overrides(AbstractConnector.get_parameters)
85+
def get_parameters(self) -> Dict[str, Any]:
86+
parameters = self._get_parameters()
87+
parameters["cset"] = self.__cset
88+
return parameters
89+
8490
@overrides(AbstractConnector.get_delay_maximum)
8591
def get_delay_maximum(self, synapse_info: SynapseInformation) -> float:
8692
n_conns_max = synapse_info.n_pre_neurons * synapse_info.n_post_neurons

0 commit comments

Comments
 (0)