Example #1
0
    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
        ]
Example #2
0
    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)
Example #3
0
    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
Example #4
0
    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?
Example #5
0
    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)
Example #6
0
    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")
Example #7
0
    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)
Example #8
0
    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
Example #9
0
    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)
Example #10
0
    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))
Example #11
0
    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)
Example #12
0
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