diff --git a/parchmint/benchmarking.py b/parchmint/benchmarking.py index fc11f20..388ad4b 100644 --- a/parchmint/benchmarking.py +++ b/parchmint/benchmarking.py @@ -34,7 +34,9 @@ def characterize_devices(devices: List[Device]) -> npt.NDArray[Any]: # Save yes if the device has a layer of type CONTROL file_info[index, 5] = ( - "YES" if "CONTROL" in [layer.type for layer in device.layers] else "NO" + "YES" + if "CONTROL" in [layer.layer_type for layer in device.layers] + else "NO" ) # Save the max connectiveity of the connection in the device diff --git a/parchmint/component.py b/parchmint/component.py index 6b74ef2..b4e2328 100644 --- a/parchmint/component.py +++ b/parchmint/component.py @@ -147,9 +147,9 @@ def rotation(self) -> float: """ try: return self.params.get_param("rotation") - except Exception: - print("Could not find rotation for component") - raise KeyError + except Exception as error: + print("Could not find rotation for component", error) + raise Exception("Could not find rotation for component") from error @rotation.setter def rotation(self, value): @@ -258,15 +258,16 @@ def rotate_point( Returns: Tuple[float, float]: A tuple containing the rotated coordinates """ + # pylint: disable=invalid-name, too-many-locals # Setup the center to be used the translation matrices center_x = self.xspan / 2 center_y = self.yspan / 2 # Setup all the corner points - old_topLeft = np.array((0, 0, 1)).transpose() - old_topRight = np.array((self.xspan, 0, 1)).transpose() - old_bottomLeft = np.array((0, self.yspan, 1)).transpose() - old_bottomRight = np.array((self.xspan, self.yspan, 1)).transpose() + old_topleft = np.array((0, 0, 1)).transpose() + old_topright = np.array((self.xspan, 0, 1)).transpose() + old_bottomleft = np.array((0, self.yspan, 1)).transpose() + old_bottomright = np.array((self.xspan, self.yspan, 1)).transpose() pos = np.array(((xpos), (ypos), (1))) @@ -278,23 +279,23 @@ def rotate_point( T2 = np.array(((1, 0, center_x), (0, 1, center_y), (0, 0, 1))) # Rotate the topRight corner and the bottomLeft corner about the center - rotated_topLeft = T2.dot(R.dot(T1.dot(old_bottomLeft))) - rotated_topRight = T2.dot(R.dot(T1.dot(old_topLeft))) - rotated_bottomRight = T2.dot(R.dot(T1.dot(old_topRight))) - rotated_bottomLeft = T2.dot(R.dot(T1.dot(old_bottomRight))) + rotated_topleft = T2.dot(R.dot(T1.dot(old_bottomleft))) + rotated_topright = T2.dot(R.dot(T1.dot(old_topleft))) + rotated_bottomright = T2.dot(R.dot(T1.dot(old_topright))) + rotated_bottomleft = T2.dot(R.dot(T1.dot(old_bottomright))) # Find the new position of the topleft corner by finding the min of all the corner points xmin = min( - rotated_topLeft[0], - rotated_topRight[0], - rotated_bottomLeft[0], - rotated_bottomRight[0], + rotated_topleft[0], + rotated_topright[0], + rotated_bottomleft[0], + rotated_bottomright[0], ) ymin = min( - rotated_topLeft[1], - rotated_topRight[1], - rotated_bottomLeft[1], - rotated_bottomRight[1], + rotated_topleft[1], + rotated_topright[1], + rotated_bottomleft[1], + rotated_bottomright[1], ) T3 = np.array(((1, 0, -xmin), (0, 1, -ymin), (0, 0, 1))) @@ -315,6 +316,8 @@ def rotate_point_around_center( Returns: Tuple[float, float]: A tuple containing the rotated coordinates """ + # pylint: disable=invalid-name,too-many-locals + # Setup the center to be used the translation matrices center_x = self.xpos + self.xspan / 2 center_y = self.ypos + self.yspan / 2 @@ -340,23 +343,23 @@ def get_rotated_component_definition(self, angle: int) -> Component: Returns: Component: [description] """ - new_topLeft = self.rotate_point(0, 0, angle) - new_topRight = self.rotate_point(self.xspan, 0, angle) - new_bottomLeft = self.rotate_point(0, self.yspan, angle) - new_bottomRight = self.rotate_point(self.xspan, self.yspan, angle) + new_topleft = self.rotate_point(0, 0, angle) + new_topright = self.rotate_point(self.xspan, 0, angle) + new_bottomleft = self.rotate_point(0, self.yspan, angle) + new_bottomright = self.rotate_point(self.xspan, self.yspan, angle) # Find xmin, ymin, xmax, ymax for all the corner points xmin = min( - new_topLeft[0], new_topRight[0], new_bottomLeft[0], new_bottomRight[0] + new_topleft[0], new_topright[0], new_bottomleft[0], new_bottomright[0] ) ymin = min( - new_topLeft[1], new_topRight[1], new_bottomLeft[1], new_bottomRight[1] + new_topleft[1], new_topright[1], new_bottomleft[1], new_bottomright[1] ) xmax = max( - new_topLeft[0], new_topRight[0], new_bottomLeft[0], new_bottomRight[0] + new_topleft[0], new_topright[0], new_bottomleft[0], new_bottomright[0] ) ymax = max( - new_topLeft[1], new_topRight[1], new_bottomLeft[1], new_bottomRight[1] + new_topleft[1], new_topright[1], new_bottomleft[1], new_bottomright[1] ) # Find the new xspan and yspan @@ -408,31 +411,31 @@ def rotate_component(self) -> None: port.x = new_location[0] port.y = new_location[1] - new_topLeft = self.rotate_point_around_center( + new_topleft = self.rotate_point_around_center( self.xpos + 0, self.ypos + 0, self.rotation ) - new_topRight = self.rotate_point_around_center( + new_topright = self.rotate_point_around_center( self.xpos + self.xspan, self.ypos + 0, self.rotation ) - new_bottomLeft = self.rotate_point_around_center( + new_bottomleft = self.rotate_point_around_center( self.xpos + 0, self.ypos + self.yspan, self.rotation ) - new_bottomRight = self.rotate_point_around_center( + new_bottomright = self.rotate_point_around_center( self.xpos + self.xspan, self.ypos + self.yspan, self.rotation ) # Find xmin, ymin, xmax, ymax for all the corner points xmin = min( - new_topLeft[0], new_topRight[0], new_bottomLeft[0], new_bottomRight[0] + new_topleft[0], new_topright[0], new_bottomleft[0], new_bottomright[0] ) ymin = min( - new_topLeft[1], new_topRight[1], new_bottomLeft[1], new_bottomRight[1] + new_topleft[1], new_topright[1], new_bottomleft[1], new_bottomright[1] ) xmax = max( - new_topLeft[0], new_topRight[0], new_bottomLeft[0], new_bottomRight[0] + new_topleft[0], new_topright[0], new_bottomleft[0], new_bottomright[0] ) ymax = max( - new_topLeft[1], new_topRight[1], new_bottomLeft[1], new_bottomRight[1] + new_topleft[1], new_topright[1], new_bottomleft[1], new_bottomright[1] ) # Find the new xspan and yspan diff --git a/parchmint/device.py b/parchmint/device.py index 0310981..5269e52 100644 --- a/parchmint/device.py +++ b/parchmint/device.py @@ -201,17 +201,17 @@ def remove_valve(self, valve_id) -> None: self.remove_component(valve_id) - def compare(self, device: Device, ignore_parameter_diffs: bool = True) -> bool: + def compare(self, device: Device, compare_params: bool = False) -> bool: """compare against the input device. Return true if they are semnatcally feasible. Args: device (Device): expected device - ignore_parameter_diffs (bool): ignore parameter differences. Defaults to True. + compare_params (bool): comparision includes parameter differences. Defaults to False. Returns: bool: If semntically feasible, return true. Else false. """ - matcher = SimilarityMatcher(self, device) + matcher = SimilarityMatcher(self, device, compare_params=compare_params) is_same = matcher.is_isomorphic() matcher.print_params_diff() @@ -384,7 +384,7 @@ def remove_layer(self, layer_id: str) -> None: # Remove all the components and connections associated with the layer for component in self.components: - if set([layer.ID for layer in component.layers]) == set(layer_to_delete.ID): + if {[layer.ID for layer in component.layers]} == set(layer_to_delete.ID): self.remove_component(component.ID) else: warn( @@ -429,7 +429,8 @@ def merge_netlist(self, netlist: Device) -> None: self.add_layer(layer) layer_mapping[layer] = layer else: - assert layer.ID is not None + if layer.ID is None: + raise Exception("Layer ID is None, cannot merge the layers") layer_mapping[layer] = self.get_layer(layer.ID) for component in netlist.components: @@ -634,14 +635,16 @@ def to_parchmint_v1_2(self) -> Dict: ret["version"] = "1.2" # Add the valvemap information - valve_map = {} - valve_type_map = {} + valve_objects = [] for valve, connection in self._valve_map.items(): - valve_map[valve.ID] = connection.ID - ret["valveMap"] = valve_map - for valve, valve_type in self._valve_type_map.items(): - valve_type_map[valve.ID] = str(valve_type) - ret["valveTypeMap"] = valve_type_map + valve_object = { + "componentid": valve.ID, + "connectionid": connection.ID, + "type": str(self._valve_type_map[valve]), + } + valve_objects.append(valve_object) + ret["valves"] = valve_objects + return ret @staticmethod @@ -727,7 +730,7 @@ def from_parchmint_v1(json_data: Dict) -> Device: # First always add the layers if "layers" in json_data.keys(): for layer in json_data["layers"]: - device_ref.add_layer(Layer(layer)) + device_ref.add_layer(Layer(json_data=layer)) else: print("no layers found") @@ -799,10 +802,16 @@ def from_parchmint_v1_2(json_data: Dict) -> Device: # First always add the layers if "layers" in json_data.keys(): for layer in json_data["layers"]: - device_ref.add_layer(Layer(layer)) + device_ref.add_layer(Layer(json_data=layer)) else: print("no layers found") + # Second add all the features + if "features" in json_data.keys(): + for feature_json in json_data["features"]: + feature = Feature.from_parchmint_v1_2(feature_json, device_ref) + device_ref.add_feature(feature) + # Loop through the components if "components" in json_data.keys(): for component_json in json_data["components"]: @@ -829,23 +838,28 @@ def from_parchmint_v1_2(json_data: Dict) -> Device: else: print("no params found") - def get_valve_type(value: str): - if value is ValveType.NORMALLY_OPEN: + def get_valve_type(value: str) -> ValveType: + if value == ValveType.NORMALLY_OPEN: return ValveType.NORMALLY_OPEN - elif value is ValveType.NORMALLY_CLOSED: + elif value == ValveType.NORMALLY_CLOSED: return ValveType.NORMALLY_CLOSED else: raise Exception("Unknown valve type {}".format(value)) - if "valveMap" in json_data.keys(): - valve_map = json_data["valveMap"] - valve_type_map = json_data["valveTypeMap"] + if "valves" in json_data.keys(): + valve_objects = json_data["valves"] - for key, value in valve_map.items(): + for valve_object in valve_objects: + componentid = valve_object["componentid"] + connectionid = valve_object["connectionid"] + # Note - Sets it to default normally open if nothign is specified + valve_type = valve_object["type"] if "type" in valve_object else None device_ref.map_valve( - device_ref.get_component(key), - device_ref.get_connection(value), - get_valve_type(valve_type_map[key]), + device_ref.get_component(componentid), + device_ref.get_connection(connectionid), + get_valve_type(valve_type) + if valve_type is not None + else ValveType.NORMALLY_OPEN, ) return device_ref diff --git a/parchmint/layer.py b/parchmint/layer.py index 4b79f0e..40976f0 100644 --- a/parchmint/layer.py +++ b/parchmint/layer.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Dict, Optional from parchmint.params import Params @@ -9,17 +9,25 @@ class Layer: Used to define a layer object that can be used in the device model. """ - def __init__(self, json_data=None) -> None: + def __init__( + self, + layer_id: Optional[str] = None, + name: Optional[str] = None, + layer_type: Optional[str] = None, + group: Optional[str] = None, + params: Optional[Params] = None, + json_data: Optional[Dict] = None, + ) -> None: """Creates a new instance Layer Args: json (dict, optional): json dict after json.loads(). Defaults to None. """ - self._id: str = "" - self.name: str = "" - self.type: str = "" - self.group: str = "" - self.params: Params = Params() + self._id: str = "" if layer_id is None else layer_id + self.name: str = "" if name is None else name + self.layertype: str = "" if layer_type is None else layer_type + self.group: str = "" if group is None else group + self.params: Params = Params() if params is None else params if json_data: self.parse_from_json(json_data) @@ -45,6 +53,24 @@ def ID(self, value: str) -> None: """ self._id = value + @property + def layer_type(self) -> str: + """Returns the layer type + + Returns: + str: layer type + """ + return self.layertype + + @layer_type.setter + def layer_type(self, value: str) -> None: + """Sets the layer type + + Args: + value (str): layer type + """ + self.layertype = value + def parse_from_json(self, json_data): """Loads instance data json dict from json.loads() @@ -53,7 +79,7 @@ def parse_from_json(self, json_data): """ self.name = json_data["name"] self.ID = json_data["id"] - self.type = json_data["type"] + self.layertype = json_data["type"] self.group = json_data["group"] self.params = Params(json_data["params"]) @@ -66,7 +92,7 @@ def to_parchmint_v1(self): return { "name": self.name, "id": self.ID, - "type": self.type, + "type": self.layertype, "params": self.params.to_parchmint_v1(), "group": self.group, } diff --git a/parchmint/port.py b/parchmint/port.py index 701e29a..c2cdb49 100644 --- a/parchmint/port.py +++ b/parchmint/port.py @@ -10,7 +10,7 @@ def __init__( layer: Optional[str] = None, x: float = -1, y: float = -1, - json_data: Dict = {}, + json_data: Optional[Dict] = None, ): """Creates a ComponentPort which is used to represent the points where a connection connects on the component diff --git a/parchmint/target.py b/parchmint/target.py index 81b9585..d70022a 100644 --- a/parchmint/target.py +++ b/parchmint/target.py @@ -8,7 +8,7 @@ def __init__( self, component_id: Optional[str] = None, port: Optional[str] = None, - json_data: Dict = {}, + json_data: Optional[Dict] = None, ): """Creates a Target object that describes where the connection will connect to diff --git a/pylintrc b/pylintrc index 091dd6c..e4b7504 100644 --- a/pylintrc +++ b/pylintrc @@ -17,7 +17,7 @@ extension-pkg-whitelist= fail-on= # Specify a score threshold to be exceeded before program exits with error. -fail-under=10.0 +fail-under=9.95 # Files or directories to be skipped. They should be base names, not paths. ignore=CVS @@ -96,7 +96,8 @@ disable=raw-checker-failed, consider-using-f-string, consider-using-enumerate, too-many-branches, - too-many-public-methods + too-many-public-methods, + too-many-locals, # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/schemas/parchmint_v1_2.json b/schemas/parchmint_v1_2.json index c0c2880..7419d55 100644 --- a/schemas/parchmint_v1_2.json +++ b/schemas/parchmint_v1_2.json @@ -1,11 +1,6 @@ { - "$schema": "http://json-schema.org/schema#", - "$id": "https://parchmint.org/schema/parchmint_v1_2.json", "type": "object", "properties": { - "name": { - "type": "string" - }, "layers": { "type": "array", "items": { @@ -29,12 +24,6 @@ "items": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "id": { - "type": "string" - }, "layer": { "type": "string" }, @@ -72,55 +61,16 @@ } }, "paths": { + "type": "array", "items": { - "type": "object", - "source": { - "type": "object", - "properties": { - "component": { - "type": "string" - }, - "port": { - "type": "string" - } - }, - "required": [ - "component", - "port" - ] - }, - "sink": { - "type": "object", - "properties": { - "component": { - "type": "string" - }, - "port": { - "type": "string" - } - }, - "required": [ - "component", - "port" - ] - }, - "wayPoints": { - "type": "\"array\"" - } - }, - "required": [ - "source", - "sink", - "wayPoints" - ] + "type": "object" + } } }, "required": [ - "id", "layer", - "name", - "sinks", - "source" + "source", + "sinks" ] } }, @@ -215,24 +165,46 @@ } }, "valveMap": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "type": "object" }, "valveTypeMap": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "type": "object" }, "version": { "type": "string", "pattern": "1.2" + }, + "valves": { + "type": "array", + "items": { + "type": "object", + "properties": { + "componentid": { + "type": "string" + }, + "connectionid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "NORMALLY_OPEN", + "NORMALLY_CLOSED" + ] + } + }, + "required": [ + "componentid", + "connectionid", + "type" + ] + } } }, "required": [ - "name", - "layers" + "layers", + "connections", + "components", + "valves" ] } \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index f17f8e1..18f27be 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,5 @@ import pytest -from parchmint.component import Component from parchmint.device import Device from parchmint.feature import Feature from parchmint.layer import Layer @@ -177,14 +176,14 @@ def device_dict( "connections": [connection_dict], "features": [feature_dict], "layers": [layer_dict], - "valveMap": { - "valve1": "con1", - "valve2": "con1", - }, - "valveTypeMap": { - "valve1": "NORMALLY_OPEN", - "valve2": "NORMALLY_CLOSED", - }, + "valves": [ + {"componentid": "valve1", "connectionid": "con1", "type": "NORMALLY_OPEN"}, + { + "componentid": "valve2", + "connectionid": "con1", + "type": "NORMALLY_CLOSED", + }, + ], "version": "1.2", } return ret diff --git a/tests/parchmint/test_component.py b/tests/parchmint/test_component.py index c1aeb43..cbcd329 100644 --- a/tests/parchmint/test_component.py +++ b/tests/parchmint/test_component.py @@ -67,7 +67,7 @@ def test_set_component_spacing(component_for_rotation): def test_to_parchmint_v1_2(params_dict, layer_dict, port_dict, component_dict): - layer = Layer(layer_dict) + layer = Layer(json_data=layer_dict) device = Device() device.layers.append(layer) @@ -85,7 +85,7 @@ def test_to_parchmint_v1_2(params_dict, layer_dict, port_dict, component_dict): def test_from_parchmint_v1_2(layer_dict, component_dict): - layer = Layer(layer_dict) + layer = Layer(json_data=layer_dict) device = Device() device.layers.append(layer) # Test to see if the loading from dictionary is working correctly @@ -212,3 +212,10 @@ def test_rotate_component(component_for_rotation, component2_for_rotation): assert component2_for_rotation.ypos == 14000 port = component2_for_rotation.get_port("top") assert (port.x, port.y) == (15000, 500) + + +def test_set_xpos_ypos(component_for_rotation): + component_for_rotation.xpos = 1000 + component_for_rotation.ypos = 1000 + assert component_for_rotation.xpos == 1000 + assert component_for_rotation.ypos == 1000 diff --git a/tests/parchmint/test_device.py b/tests/parchmint/test_device.py index 90cdb1f..ac0f165 100644 --- a/tests/parchmint/test_device.py +++ b/tests/parchmint/test_device.py @@ -217,3 +217,8 @@ def test_to_parchmint_v1_2( device.map_valve(valve1, con1, ValveType.NORMALLY_OPEN) device.map_valve(valve2, con1, ValveType.NORMALLY_CLOSED) assert device.to_parchmint_v1_2() == device_dict + + +def test_from_parchmint_v1_2(device_dict): + device = Device.from_parchmint_v1_2(json_data=device_dict) + assert device.to_parchmint_v1_2() == device_dict diff --git a/tests/parchmint/test_layer.py b/tests/parchmint/test_layer.py index 32b052d..8f009db 100644 --- a/tests/parchmint/test_layer.py +++ b/tests/parchmint/test_layer.py @@ -5,7 +5,7 @@ def test_to_parchmint_v1(params_dict, layer_dict): layer = Layer() layer.ID = "FLOW_1" layer.name = "flow_1" - layer.type = "FLOW" + layer.layertype = "FLOW" layer.group = "" layer.params = Params(params_dict) assert layer.to_parchmint_v1() == layer_dict