def add_edge(self, from_index, to_index,
                 weight=None, warn_duplicates=True,
                 edge_properties=None):
        """
        Add edge to graph.

        Since physically a 'bond' (or other connection
        between sites) doesn't have a direction, from_index,
        from_jimage can be swapped with to_index, to_jimage.

        However, images will always always be shifted so that
        from_index < to_index and from_jimage becomes (0, 0, 0).

        :param from_index: index of site connecting from
        :param to_index: index of site connecting to
        :param weight (float): e.g. bond length
        :param warn_duplicates (bool): if True, will warn if
        trying to add duplicate edges (duplicate edges will not
        be added in either case)
        :param edge_properties (dict): any other information to
        store on graph edges, similar to Structure's site_properties
        :return:
        """

        # this is not necessary for the class to work, but
        # just makes it neater
        if to_index < from_index:
            to_index, from_index = from_index, to_index

        # sanitize types
        from_index, to_index = int(from_index), int(to_index)

        # check we're not trying to add a duplicate edge
        # there should only ever be at most one edge
        # between two sites
        existing_edge_data = self.graph.get_edge_data(from_index, to_index)
        if existing_edge_data and warn_duplicates:
            warnings.warn("Trying to add an edge that already exists from "
                            "site {} to site {}.".format(from_index,
                                                         to_index))
            return

        # generic container for additional edge properties,
        # similar to site properties
        edge_properties = edge_properties or {}

        if weight:
            self.graph.add_edge(from_index, to_index,
                                weight=weight,
                                **edge_properties)
        else:
            self.graph.add_edge(from_index, to_index,
                                **edge_properties)