diff --git a/src/sage/groups/perm_gps/partn_ref/data_structures.pxd b/src/sage/groups/perm_gps/partn_ref/data_structures.pxd index a6841f43f9f..1cbb95231d5 100644 --- a/src/sage/groups/perm_gps/partn_ref/data_structures.pxd +++ b/src/sage/groups/perm_gps/partn_ref/data_structures.pxd @@ -14,6 +14,8 @@ from libc.string cimport memcpy from libc.stdlib cimport rand from sage.libs.gmp.mpz cimport * +from cysignals.memory cimport sig_free + cdef enum: # The following is for the automorphism group computation, says what the @@ -136,6 +138,39 @@ cdef inline void OP_join(OrbitPartition *OP, int m, int n) noexcept: if m_root != n_root: OP.num_cells -= 1 + +cdef inline void OP_make_set(OrbitPartition *OP) noexcept: + cdef int i, n = OP.degree + cdef int *new_parent, *new_rank, *new_mcr, *new_size + + cdef int *int_array = sig_malloc(4*(n+1) * sizeof(int)) + if int_array is NULL: + raise MemoryError("MemoryError allocating int_array in make_set method") + + OP.degree = n + 1 + OP.num_cells = OP.num_cells + 1 + new_parent = int_array + new_rank = int_array + (n + 1) + new_mcr = int_array + (2*n + 2) + new_size = int_array + (3 * n + 3) + + memcpy(new_parent, OP.parent, n * sizeof(int)) + memcpy(new_rank, OP.rank, n * sizeof(int)) + memcpy(new_mcr, OP.mcr, n * sizeof(int)) + memcpy(new_size, OP.size, n * sizeof(int)) + + new_parent[n] = n + new_rank[n] = 0 + new_mcr[n] = n + new_size[n] = 1 + + sig_free(OP.parent) + + OP.parent = new_parent + OP.rank = new_rank + OP.mcr = new_mcr + OP.size = new_size + cdef inline int OP_merge_list_perm(OrbitPartition *OP, int *gamma) noexcept: """ Joins the cells of OP which intersect the same orbit of gamma. diff --git a/src/sage/sets/disjoint_set.pyx b/src/sage/sets/disjoint_set.pyx index 02cf77fbdd7..b685c361e19 100644 --- a/src/sage/sets/disjoint_set.pyx +++ b/src/sage/sets/disjoint_set.pyx @@ -537,6 +537,26 @@ cdef class DisjointSet_of_integers(DisjointSet_class): raise ValueError('j must be between 0 and %s (%s given)' % (card - 1, j)) OP_join(self._nodes, i, j) + def make_set(self): + r""" + Add a new element into a new set containing only the new element. + + According to :wikipedia:`Disjoint-set_data_structure#Making_new_sets` the + `make_set` operation adds a new element into a new set containing only + the new element. The new set is added at the end of `self`. + + EXAMPLES:: + sage: d = DisjointSet(5) + sage: d.union(1, 2) + sage: d.union(0, 1) + sage: d.make_set() + sage: d + {{0, 1, 2}, {3}, {4}, {5}} + sage: d.find(1) + 1 + """ + OP_make_set(self._nodes) + cpdef root_to_elements_dict(self): r""" Return the dictionary where the keys are the roots of ``self`` and the @@ -834,6 +854,43 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): cdef int j = self._el_to_int[f] OP_join(self._nodes, i, j) + def make_set(self, new_elt=None): + r""" + Add a new element into a new set containing only the new element. + + According to :wikipedia:`Disjoint-set_data_structure#Making_new_sets` + the `make_set` operation adds a new element into a new set containing + only the new element. The new set is added at the end of `self`. + + INPUT: + + - ``new_elt`` -- (optional) element to add. If `None`, then an integer + is added. + + EXAMPLES:: + + sage: e = DisjointSet('abcde') + sage: e.union('d', 'c') + sage: e.union('c', 'e') + sage: e.make_set('f') + sage: e + {{'a'}, {'b'}, {'c', 'd', 'e'}, {'f'}} + sage: e.union('f', 'b') + sage: e + {{'a'}, {'b', 'f'}, {'c', 'd', 'e'}} + sage: e.make_set('e'); e + {{'a'}, {'b', 'f'}, {'c', 'd', 'e'}} + sage: e.make_set(); e + {{'a'}, {'b', 'f'}, {'c', 'd', 'e'}, {6}} + """ + if new_elt is None: + new_elt = self._nodes.degree + if new_elt not in self._int_to_el: + d = self._nodes.degree + self._int_to_el.append(new_elt) + self._el_to_int[new_elt] = d + OP_make_set(self._nodes) + cpdef root_to_elements_dict(self): r""" Return the dictionary where the keys are the roots of ``self`` and the