Skip to content

Commit

Permalink
sagemathgh-38692: Add make_set function for DisjointSets
Browse files Browse the repository at this point in the history
    
<!-- ^ Please provide a concise and informative title. -->
<!-- ^ Don't put issue numbers in the title, do this in the PR
description below. -->
<!-- ^ For example, instead of "Fixes sagemath#12345" use "Introduce new method
to calculate 1 + 2". -->
<!-- v Describe your changes below in detail. -->
<!-- v Why is this change required? What problem does it solve? -->
<!-- v If this PR resolves an open issue, please link to it here. For
example, "Fixes sagemath#12345". -->

This fixes sagemath#35599  by adding a `make_set` function to `DisjointSet`
using `OrbitPartitions`. The documentation links to wikipedia.
From wikipedia, the method should be done in place and therefore there
is no return

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->

- [x] The title is concise and informative.
- [x] The description explains in detail what this PR is about.
- [x] I have linked a relevant issue or discussion.
- [x] I have created tests covering the changes.
- [x] I have updated the documentation and checked the documentation
preview.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on. For example,
-->
<!-- - sagemath#12345: short description why this is a dependency -->
<!-- - sagemath#34567: ... -->

sagemath#35599
    
URL: sagemath#38692
Reported by: Aram Dermenjian
Reviewer(s): Aram Dermenjian, David Coudert
  • Loading branch information
Release Manager committed Sep 26, 2024
2 parents afee159 + 598ccfd commit b751bb9
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/sage/groups/perm_gps/partn_ref/data_structures.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = <int *> 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.
Expand Down
57 changes: 57 additions & 0 deletions src/sage/sets/disjoint_set.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -834,6 +854,43 @@ cdef class DisjointSet_of_hashables(DisjointSet_class):
cdef int j = <int> 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
Expand Down

0 comments on commit b751bb9

Please sign in to comment.