Compares two StructureGraphs. Returns dict with
        keys 'self', 'other', 'both' with edges that are
        present in only one StructureGraph ('self' and
        'other'), and edges that are present in both.

        The Jaccard distance is a simple measure of the
        dissimilarity between two StructureGraphs (ignoring
        edge weights), and is defined by 1 - (size of the
        intersection / size of the union) of the sets of
        edges. This is returned with key 'dist'.

        Important note: all node indices are in terms
        of the StructureGraph this method is called
        from, not the 'other' StructureGraph: there
        is no guarantee the node indices will be the
        same if the underlying Structures are ordered
        differently.

        :param other: StructureGraph
        :param strict: if False, will compare bonds
        from different Structures, with node indices
        replaced by Specie strings, will not count
        number of occurrences of bonds
        :return:

def diff(self, other, strict=True):
        """
        Compares two StructureGraphs. Returns dict with
        keys 'self', 'other', 'both' with edges that are
        present in only one StructureGraph ('self' and
        'other'), and edges that are present in both.

        The Jaccard distance is a simple measure of the
        dissimilarity between two StructureGraphs (ignoring
        edge weights), and is defined by 1 - (size of the
        intersection / size of the union) of the sets of
        edges. This is returned with key 'dist'.

        Important note: all node indices are in terms
        of the StructureGraph this method is called
        from, not the 'other' StructureGraph: there
        is no guarantee the node indices will be the
        same if the underlying Structures are ordered
        differently.

        :param other: StructureGraph
        :param strict: if False, will compare bonds
        from different Structures, with node indices
        replaced by Specie strings, will not count
        number of occurrences of bonds
        :return:
        """

        if self.structure != other.structure and strict:
            return ValueError("Meaningless to compare StructureGraphs if "
                              "corresponding Structures are different.")

        if strict:

            # sort for consistent node indices
            # PeriodicSite should have a proper __hash__() value,
            # using its frac_coords as a convenient key
            mapping = {tuple(site.frac_coords):self.structure.index(site) for site in other.structure}
            other_sorted = other.__copy__()
            other_sorted.sort(key=lambda site: mapping[tuple(site.frac_coords)])

            edges = {(u, v, d['to_jimage'])
                     for u, v, d in self.graph.edges(keys=False, data=True)}

            edges_other = {(u, v, d['to_jimage'])
                           for u, v, d in other_sorted.graph.edges(keys=False, data=True)}

        else:

            edges = {(str(self.structure[u].specie),
                      str(self.structure[v].specie))
                     for u, v, d in self.graph.edges(keys=False, data=True)}

            edges_other = {(str(other.structure[u].specie),
                            str(other.structure[v].specie))
                           for u, v, d in other.graph.edges(keys=False, data=True)}

        if len(edges) == 0 and len(edges_other) == 0:
            jaccard_dist = 0  # by definition
        else:
            jaccard_dist = 1 - len(edges.intersection(edges_other)) / len(edges.union(edges_other))

        return {
            'self': edges - edges_other,
            'other': edges_other - edges,
            'both': edges.intersection(edges_other),
            'dist': jaccard_dist
        }