Skip to content

improvement of method vertex_separation_BAB#41458

Merged
vbraun merged 1 commit intosagemath:developfrom
dcoudert:graphs/smaller_frozen_prefix_for_pathwidth
Feb 1, 2026
Merged

improvement of method vertex_separation_BAB#41458
vbraun merged 1 commit intosagemath:developfrom
dcoudert:graphs/smaller_frozen_prefix_for_pathwidth

Conversation

@dcoudert
Copy link
Copy Markdown
Collaborator

Method vertex_separation_BAB implements a branch and bound algorithm for the vertex separation of graphs. it uses the concept of memoization to cut some branches of the exploration tree of the branch and bound. Roughly, it stores some prefixes (sets of vertices) to avoid exploring multiple times branches starting with prefixes on the same set of vertices.
Previously, this was implemented by using a set of frozensets, each containing the set of vertices of a prefix.
This PR stores instead the bitset representation of a prefix as a tuple of integers. Hence, it uses less memory per stored prefix. In addition, the running time is slightly improved.

Before:

sage: for i in range(2, 7):
....:     G = graphs.MycielskiGraph(i)
....:     print(f"{G}: {G.order()} vertices; vs = {vertex_separation_BAB(G)[0]}")
....:     timeit("vs = vertex_separation_BAB(G)[0]")
....: 
Mycielski Graph 2: 2 vertices; vs = 1
625 loops, best of 3: 2.79 μs per loop
Mycielski Graph 3: 5 vertices; vs = 2
625 loops, best of 3: 4.58 μs per loop
Mycielski Graph 4: 11 vertices; vs = 5
625 loops, best of 3: 15.4 μs per loop
Mycielski Graph 5: 23 vertices; vs = 10
625 loops, best of 3: 353 μs per loop
Mycielski Graph 6: 47 vertices; vs = 20
5 loops, best of 3: 85.2 ms per loop

After:

Mycielski Graph 2: 2 vertices; vs = 1
625 loops, best of 3: 2.57 μs per loop
Mycielski Graph 3: 5 vertices; vs = 2
625 loops, best of 3: 4.23 μs per loop
Mycielski Graph 4: 11 vertices; vs = 5
625 loops, best of 3: 13.5 μs per loop
Mycielski Graph 5: 23 vertices; vs = 10
625 loops, best of 3: 277 μs per loop
Mycielski Graph 6: 47 vertices; vs = 20
5 loops, best of 3: 56.8 ms per loop

Before

sage: for i in range(5, 11):
....:     G = graphs.Grid2dGraph(i, i)
....:     print(f"{G}: {G.order()} vertices; vs = {vertex_separation_BAB(G)[0]}")
....:     timeit("vs = vertex_separation_BAB(G)[0]")
....: 
2D Grid Graph for [5, 5]: 25 vertices; vs = 5
625 loops, best of 3: 99.7 μs per loop
2D Grid Graph for [6, 6]: 36 vertices; vs = 6
625 loops, best of 3: 629 μs per loop
2D Grid Graph for [7, 7]: 49 vertices; vs = 7
125 loops, best of 3: 3.9 ms per loop
2D Grid Graph for [8, 8]: 64 vertices; vs = 8
25 loops, best of 3: 24.4 ms per loop
2D Grid Graph for [9, 9]: 81 vertices; vs = 9
5 loops, best of 3: 182 ms per loop
2D Grid Graph for [10, 10]: 100 vertices; vs = 10
5 loops, best of 3: 67.7 s per loop

After:

2D Grid Graph for [5, 5]: 25 vertices; vs = 5
625 loops, best of 3: 85.2 μs per loop
2D Grid Graph for [6, 6]: 36 vertices; vs = 6
625 loops, best of 3: 489 μs per loop
2D Grid Graph for [7, 7]: 49 vertices; vs = 7
125 loops, best of 3: 2.88 ms per loop
2D Grid Graph for [8, 8]: 64 vertices; vs = 8
25 loops, best of 3: 17.6 ms per loop
2D Grid Graph for [9, 9]: 81 vertices; vs = 9
5 loops, best of 3: 142 ms per loop
2D Grid Graph for [10, 10]: 100 vertices; vs = 10
5 loops, best of 3: 64.4 s per loop

📝 Checklist

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

⌛ Dependencies

@github-actions
Copy link
Copy Markdown

Documentation preview for this PR (built with commit 1bf81a4; changes) is ready! 🎉
This preview will update shortly after each push to this PR.

Copy link
Copy Markdown
Contributor

@fchapoton fchapoton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice. Looks so simple..

@dcoudert
Copy link
Copy Markdown
Collaborator Author

Indeed. I don't know why I didn't thought about it before. I found it while working on a different code.

vbraun pushed a commit to vbraun/sage that referenced this pull request Jan 30, 2026
sagemathgh-41458: improvement of method vertex_separation_BAB
    
Method `vertex_separation_BAB` implements a branch and bound algorithm
for the vertex separation of graphs. it uses the concept of memoization
to cut some branches of the exploration tree of the branch and bound.
Roughly, it stores some prefixes (sets of vertices) to avoid exploring
multiple times branches starting with prefixes on the same set of
vertices.
Previously, this was implemented by using a set of frozensets, each
containing the set of vertices of a prefix.
This PR stores instead the bitset representation of a prefix as a tuple
of integers. Hence, it uses less memory per stored prefix. In addition,
the running time is slightly improved.

Before:
```sage
sage: for i in range(2, 7):
....:     G = graphs.MycielskiGraph(i)
....:     print(f"{G}: {G.order()} vertices; vs =
{vertex_separation_BAB(G)[0]}")
....:     timeit("vs = vertex_separation_BAB(G)[0]")
....:
Mycielski Graph 2: 2 vertices; vs = 1
625 loops, best of 3: 2.79 μs per loop
Mycielski Graph 3: 5 vertices; vs = 2
625 loops, best of 3: 4.58 μs per loop
Mycielski Graph 4: 11 vertices; vs = 5
625 loops, best of 3: 15.4 μs per loop
Mycielski Graph 5: 23 vertices; vs = 10
625 loops, best of 3: 353 μs per loop
Mycielski Graph 6: 47 vertices; vs = 20
5 loops, best of 3: 85.2 ms per loop
```

After:
```sage
Mycielski Graph 2: 2 vertices; vs = 1
625 loops, best of 3: 2.57 μs per loop
Mycielski Graph 3: 5 vertices; vs = 2
625 loops, best of 3: 4.23 μs per loop
Mycielski Graph 4: 11 vertices; vs = 5
625 loops, best of 3: 13.5 μs per loop
Mycielski Graph 5: 23 vertices; vs = 10
625 loops, best of 3: 277 μs per loop
Mycielski Graph 6: 47 vertices; vs = 20
5 loops, best of 3: 56.8 ms per loop
```

Before
```sage
sage: for i in range(5, 11):
....:     G = graphs.Grid2dGraph(i, i)
....:     print(f"{G}: {G.order()} vertices; vs =
{vertex_separation_BAB(G)[0]}")
....:     timeit("vs = vertex_separation_BAB(G)[0]")
....:
2D Grid Graph for [5, 5]: 25 vertices; vs = 5
625 loops, best of 3: 99.7 μs per loop
2D Grid Graph for [6, 6]: 36 vertices; vs = 6
625 loops, best of 3: 629 μs per loop
2D Grid Graph for [7, 7]: 49 vertices; vs = 7
125 loops, best of 3: 3.9 ms per loop
2D Grid Graph for [8, 8]: 64 vertices; vs = 8
25 loops, best of 3: 24.4 ms per loop
2D Grid Graph for [9, 9]: 81 vertices; vs = 9
5 loops, best of 3: 182 ms per loop
2D Grid Graph for [10, 10]: 100 vertices; vs = 10
5 loops, best of 3: 67.7 s per loop
```

After:
```sage
2D Grid Graph for [5, 5]: 25 vertices; vs = 5
625 loops, best of 3: 85.2 μs per loop
2D Grid Graph for [6, 6]: 36 vertices; vs = 6
625 loops, best of 3: 489 μs per loop
2D Grid Graph for [7, 7]: 49 vertices; vs = 7
125 loops, best of 3: 2.88 ms per loop
2D Grid Graph for [8, 8]: 64 vertices; vs = 8
25 loops, best of 3: 17.6 ms per loop
2D Grid Graph for [9, 9]: 81 vertices; vs = 9
5 loops, best of 3: 142 ms per loop
2D Grid Graph for [10, 10]: 100 vertices; vs = 10
5 loops, best of 3: 64.4 s per loop
```



### 📝 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.
- [ ] I have linked a relevant issue or discussion.
- [ ] I have created tests covering the changes.
- [ ] 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: ... -->
    
URL: sagemath#41458
Reported by: David Coudert
Reviewer(s): Frédéric Chapoton
@vbraun vbraun merged commit 2f1ddd5 into sagemath:develop Feb 1, 2026
23 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants