Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions examples/transversals.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Minimal transversals\n",
"\n",
"Let $\\mathcal{S}$ be a family of sets. A set $T$ is a *transversal* (or *hitting set*) of $\\mathcal{S}$ if $T$ intersects every $S\\in\\mathcal{S}$. The family of minimal transversals of $\\mathcal{S}$ is denoted by $\\text{Tr}(\\mathcal{S})$.\n",
"\n",
"The minimality of $T$ can be characterized by the following condition:\n",
"If $x\\in T$, then $S\\cap T= \\{x\\}$ for some $S\\in\\mathcal{S}$. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\"\"\"\n",
"Author: Nandor Sieben (https://github.com/nandorsieben)\n",
"\"\"\"\n",
"\n",
"import cpmpy as cp\n",
"from typing import List"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"def Tr(sets:List):\n",
" \"\"\"\n",
" Given a family of sets, returns all minimal transversals.\n",
" \"\"\"\n",
" X = {s for S in sets for s in S} # all elements across all sets, deduplicated\n",
" \n",
" # Decision Variables\n",
" t = {x:cp.boolvar() for x in X} # whether to inlude an element into the transversal\n",
"\n",
" # Model\n",
" model = cp.Model()\n",
"\n",
" # Constraints\n",
" # 1) transversal\n",
" for S in sets:\n",
" model += cp.any([t[s] for s in S]) # must hit each set by intersecting with at least one element\n",
" # 2) minimal transversal\n",
" # for each element x, if it is included in our transversal T, \n",
" # there must exist a set S which intersects with T in only that single element x\n",
" for x in X: \n",
" model += t[x].implies(\n",
" cp.any(\n",
" [cp.all([~t[s] for s in S if s!=x]) \n",
" for S in sets if x in S]\n",
" )\n",
" )\n",
" \n",
" # Solve and collect results\n",
" result = []\n",
" model.solveAll(display=lambda: result.append({a for a in t if t[a].value()}))\n",
" return result "
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{2}, {1, 3}]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Tr([{1,2},{2,3}])"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{2, 3}, {1, 2}]"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Tr([{2},{1,3}])"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{1, 4, 5}, {1, 3, 4}, {1, 5, 8}, {1, 5, 7}, {2, 7}, {2, 8}, {2, 4}]"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Tr([{1,2},{2,4,5},{2,3,5},{4,7,8}])"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.8"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading