def add_connection(self, from_interface, to_interface, **kwargs): """ Specifies interfaces on subcomponents to be connected Args: from_interface (tuple(str, str)): a tuple containing the name of the subcomponent, and the name of the interface the connection comes from to_interface (tuple(str, str)): a tuple containing the name of the subcomponent, and the name of the interface the connection goes to kwargs (dict): arguments for the connection Raises: KeyError: a connection between the two interfaces already exists """ name = "{} -> {}".format( prefix_string(from_interface[0], from_interface[1]), prefix_string(to_interface[0], to_interface[1])) if name in self.connections: raise KeyError("Connection {} already exists") # self.connections[name] = [self.get_subcomponent_interface(from_interface[0], from_interface[1]), # self.get_subcomponent_interface(to_interface[0], to_interface[1]), kwargs] # print 'the value of connections is', self.connections[name] from_int = self.get_subcomponent_interface(from_interface[0], from_interface[1]) to_int = self.get_subcomponent_interface(to_interface[0], to_interface[1]) self.connections[name] = [ Interface(from_int.get_name(), from_int.get_ports(), from_interface), Interface(to_int.get_name(), to_int.get_ports(), to_interface), kwargs ]
def inherit_parameters(self, other, prefix): """Adds parameters from another parameterized object to the current component. Overrides original fucntion in parameterized to account for attribute parameters Args: other (Parameterized): the parameterized object to inherit parameters from prefix (str): a prefix string to be added to the name of inherited parameters """ attribute_params = {} try: attribute_params = other.get_attribute_params() except: pass for name, variable in other.all_parameters(): if isinstance(variable, Variable): variable.set_name(prefix_string(prefix, variable.get_name())) if name in attribute_params.keys(): self.add_attribute_param(prefix_string(prefix, name), variable, is_literal=True, desc=attribute_params[name]) else: self.add_parameter(prefix_string(prefix, name), variable, is_literal=True)
def prefix(self, prefix): """ Prefixes all edges and faces of this graph object Args: prefix (str): the string to prefix all faces and edges with """ for e in self.edges: e.rename(prefix_string(prefix, e.name)) for f in self.faces: f.rename(prefix_string(prefix, f.name)) self.prefixed = True
def inherit_parameters(self, other, prefix): """Adds parameters from another parameterized object to the current object Args: other (Parameterized): the parameterized object to inherit parameters from prefix (str): a prefix string to be added to the name of inherited parameters """ for name, variable in other.all_parameters(): if isinstance(variable, Variable): variable.set_name(prefix_string(prefix, variable.get_name())) self.add_parameter( prefix_string(prefix, name), variable, is_literal=True) # Is this how we want to do it?
def resolve_subcomponent(self, name): """ Creates subcomponent object and adds it to the current component Args: name: name of subcomponent to be created """ sc = self.subcomponents[name] try: if sc["component"]: ## 'component' is none. why do we need to do it? ## return except KeyError: pass c = sc["class"] ## sc['class'] is the object_type. ## try: kwargs = sc[ "constants"] ## in case the 'constants' dose not exist. ## except KeyError: kwargs = {} obj = get_subcomponent_object(c, name=prefix_string( self.get_name(), name), **kwargs) ## Prefix_string = Prefix ## self.subcomponents[name]["component"] = obj self.inherit_parameters(obj, name) self.inherit_constraints(obj)
def del_connection(self, from_interface, to_interface): """ Deletes the connection that consists of the two ordered interfaces Args: from_interface (tuple(str, str)): a tuple containing the name of the subcomponent, and the name of the interface the connection comes from to_interface (tuple(str, str)): a tuple containing the name of the subcomponent, and the name of the interface the connection goes to Raises: KeyError: a connection between the two interface does not exist """ name = "{} -> {}".format( prefix_string(from_interface[0], from_interface[1]), prefix_string(to_interface[0], to_interface[1])) if name not in self.connections: raise KeyError("Connection {} does not exist")
def attach_face(self, from_edge, new_face, new_edge, prefix=None, angle=0, edge_type=None, joints=None, tab_width=None): """ Attaches a face to the graph object, merging edges if necessary. Args: from_edge (HyperEdge): edge from the graph object that the new face is being connected to new_face (Face): the new face being attached new_edge (HyperEdge): the edge on the new face that is being connected to from_edge prefix (str): name prefix angle (numeric): the angle of connection between the edges edge_type (str): the type of edge("FOLD", "CUT", "JOINT") joints (list): list of joints to add to the new edge tab_width (numeric): the width of a tab to add or None """ # XXX should set angle from a face, not absolute angle of the face self.add_face(new_face, prefix) if from_edge is not None: new_edge = prefix_string(prefix, new_edge) self.merge_edge(from_edge, new_edge, tab_width=tab_width, angle=angle, edge_type=edge_type, joints=joints)
def inherit_all_interfaces(self, subcomponent, prefix=""): """Adds all interfaces from subcomponent to current component Args: subcomponent (Component): Component object from which all the interfaces will be inherited. prefix (str): name of component, will automatically work if ignored or left as "" (an empty string). """ self.resolve_subcomponent(subcomponent) obj = self.get_subcomponent(subcomponent) if prefix == "": prefix = name for name, value in obj.interfaces.iteritems(): if name in self.interfaces: raise ValueError("Interface %s already exists" % name) new_interface = Interface(prefix_string(prefix, name), value) self.add_interface(prefix_string(prefix, name), new_interface) return self
def prefix(self, prefix=""): """Adds a prefix to the edge name Args: prefix (str): The prefix string """ # if self.placed: # return self.edge_name = prefix_string(prefix, self.edge_name)
def prefix_edges(self, prefix): """Prefixes all edges contained by this Face Args: prefix (str): prefix to add to edge names """ for e in self.edges: e.rename(prefix_string(prefix, e.name))
def prefix(self, prefix): """Prefixes the name and all the edge names of this Face Args: prefix (str): prefix to add to names of edges and itself. """ self.name = prefix_string(prefix, self.name) self.prefix_edges(prefix)
class Component(Parameterized): """The base class that all components derive from. A component is an abstract representation of an element of a device. Attributes: subcomponents (dict): dictionary of component objects that make up the overall component where the key is the name. connections (list): list of connection definitions from an interface to another interface with arguments associated. interfaces (dict): dictionary of interfaces where the key is the name composables (OrderedDict): an ordered dictionary of composables that define the output of the component. """ def __init__(self, yaml_file=None, name=None, **kwargs): """Constructs a new Component object. Creates a Component that is either blank or loaded from a yaml file. Args: yaml_file (str): The optional yaml file to load the component information from. **kwargs: Arbitrary keyword arguments to control construction. """ Parameterized.__init__(self, name=name) self.subcomponents = {} ## Initially, there is no subcomponent. ## self.connections = {} self.tabs = [ ] ## tabs can add tab and slot to two faces to connect them. ## self.interfaces = {} self._prefixed = {} self.composables = OrderedDict( ) ## the OrderedDict can memberize the order that items are input.## self.attribute_params = {} self.hierarchical_constraints = {} if yaml_file: self._from_yaml( yaml_file ) ## '_from_yaml' can import yaml file from sources other than library. ## # Override to define actual component self.define(**kwargs) ## doesn't any thing.## self.make() ## don't know 'make()' ## def _make_test(self, protobuf=False, display=True): """Constructs a test version of the Component. Sets test parameters as defined by the Component and creates output. Args: protobuf (Boolean): Whether to construct a protobuf or not. display (Boolean): Whether to display the output or not. """ if not hasattr(self, '_test_params'): raise NotImplementedError for key, val in self._test_params.iteritems(): self.set_parameter(key, val) name = self.__class__.__name__ self.make_output('output/%s' % name, protobuf=protobuf, display=display) def _str_to_sympy(self, string): """Converts string to sympy expression Uses this Component's parameters to convert a string to a sympy expression. Args: string (str): The string to convert Returns: The sympy expression. """ try: if string.lower() == "false" or string.lower() == "true": return string.lower() == "true" expr = math.sympify(string) subs = [] for a in expr.atoms(math.Symbol): subs.append((a, self.get_parameter(repr(a)))) expr = expr.subs(subs) return expr except: return string def _from_yaml(self, file_name): """Loads in component information from a YAML file. Args: file_name (str): The name of the yaml file. """ definition = load_yaml(file_name) try: for name, value in definition["subcomponents"].iteritems(): try: # XXX Can these be sympy functions as well? kwargs = value["constants"] except AttributeError: kwargs = {} self.add_subcomponent(name, value["class"], **kwargs) except AttributeError: pass # keys are (parameters, constants, subcomponents, constraints, connections, interfaces) try: for name, default in definition["parameters"].iteritems(): if not name in self.parameters: self.add_parameter(name, default) except AttributeError: pass try: for name, default in definition["constants"].iteritems(): self.add_constant(name, default) except AttributeError: pass try: for name, value in definition["subcomponents"].iteritems(): try: for param, pvalue in value["parameters"].iteritems(): self.constrain_subcomponent_parameter( (name, param), self._str_to_sympy(pvalue)) except AttributeError: pass except AttributeError: pass try: for value in definition["constraints"]: self.add_constraint(self._str_to_sympy(value)) except (AttributeError, KeyError): pass try: for value in definition["hierarchical_constraints"]: eqn = self._str_to_sympy(value) self.hierarchical_constraints[eqn.lhs] = eqn.rhs except AttributeError: pass try: for from_port, to_port, kwargs in definition["connections"]: for param, pvalue in kwargs.iteritems(): try: pvaluetup = make_tuple(pvalue) if isinstance(pvaluetup, tuple): kwargs[param] = tuple( self._str_to_sympy(x) for x in pvaluetup) else: kwargs[param] = self._str_to_sympy(pvalue) except: kwargs[param] = self._str_to_sympy(pvalue) self.add_connection(from_port, to_port, **kwargs) except AttributeError as e: pass try: for name, value in definition["interfaces"].iteritems(): self.inherit_interface(name, value) except AttributeError: pass def define(self, **kwargs): """Function for overriding interfaces. Args: **kwargs: Arbitrary keyword arguments """ pass def add_subcomponent(self, name, object_type, **kwargs): """Adds a subcomponent to this Component. Args: name (str): unique identifier to refer to this subcomponent by object_type (str or type): code name of the subcomponent should be python file/class or yaml name. For example, you want to add a rectangle. You should call instance.add_subcomponent('r1','Rectangle'). """ if name in self.subcomponents: raise ValueError( "Subcomponent with name {} already exists".format(name)) sc = { "class": object_type, "parameters": {}, "constants": kwargs, "component": None } self.subcomponents.setdefault(name, sc) self.resolve_subcomponent(name) if 'flip' in kwargs and kwargs['flip']: self.subcomponents[name]['component'].flip() def flip(self): if 'graph' in self.composables: self.composables['graph'].flip() def del_subcomponent(self, name): """Deletes a subcomponent to this Component and performs any cleanup necessary Args: name (str): unique identifier of subcomponent to delete """ to_delete = [] # delete edges connecting components for (key, (from_comp, _), (to_comp, _), _) in self.connections: if name in (from_comp, to_comp): to_delete.append(key) for key in reversed(to_delete): self.connections.pop(key) if self.subcomponents[name][ 'component'] and 'graph' in self.subcomponents[name][ 'component'].composables: self.subcomponents[name]['component'].composables[ 'graph'].split_merged_edges() self.subcomponents.pop(name) if "graph" in self.composables.keys(): del self.composables['graph'] if name in self._prefixed: del self._prefixed[name] for sc in self.subcomponents: if 'graph' in self.subcomponents[sc]['component'].composables: self.subcomponents[sc]['component'].composables[ 'graph'].placed = False def add_attribute_param(self, name, value, is_literal=False, desc="", **kwargs): """Adds an attribute parameter to the component. Attributes are special parameters which describe some inherent characteristic of the component, which may be often variable between different instances of the component, but can/should not be changed between makes of the same component instance. Thus, it is recommended these be set before calling make or adding connections to the component. Added Attributes will be returned by get_attribute_params, but they are merely a soft restriction for the user, and behave otherwise identically to parameters. Args: name (str): the parameter name value (int): an integer representing the default value for the parameter is_literal (bool): if True, the parameter's value will be stored as is. Else, it will be stored in a variable whose value can be changed. desc (str): a description of the attributes purpose **kwargs (dict): kwargs for the creation of the Dummy Returns: The newly added parameter Raises: KeyError: A parameter called name has already been created ValueError: Invalid characters in name """ self.attribute_params[name] = desc return self.add_parameter(name, value, is_literal, **kwargs) def get_attribute_params(self): return self.attribute_params def add_hierarchical_constraint(self, (subcomponent, parameter), value): """Adds a hierarchical constraint to component Args: subcomponent (str): component name to constrain parameter (str): parameter of subcomponent to constrain value (Expression): expression to constrain to """ self.hierarchical_constraints[self.get_parameter( prefix_string(subcomponent, parameter))] = value