Skip to main content

Explanation tools for PyCSP3 constraint models

Project description

PyCSP3-Explain

Explanation tools for PyCSP3 constraint models. Find minimal unsatisfiable subsets (MUS), maximal satisfiable subsets (MSS), and minimal correction sets (MCS) to debug and understand infeasible constraint problems.

Features

  • MUS (Minimal Unsatisfiable Subset): Find the minimal set of conflicting constraints
    • mus() - Assumption-based using ACE core extraction
    • mus_naive() - Deletion-based (works with any solver)
    • quickxplain_naive() - Preferred MUS based on constraint ordering
  • Optimal MUS (SMUS/OCUS): Prefer smaller or lower-weight explanations
    • smus() - Smallest MUS (fewest constraints)
    • optimal_mus() - Minimum total weight MUS
    • ocus() - OCUS with subset constraints/predicates
    • ocus_naive() - Naive OCUS (alias for weighted MUS)

    Note: IHS uses a small CP model in PyCSP3 and falls back to enumeration if needed.

  • MSS (Maximal Satisfiable Subset): Find the maximum satisfiable portion
    • mss() - Assumption-based with core extraction
    • mss_naive() - Greedy growing algorithm
  • Weighted MSS/MCS: Optimize which constraints to keep/remove
    • mss_opt() - Maximize total weight of kept constraints
    • mcs_opt() - Minimize total weight of removed constraints
  • MCS (Minimal Correction Set): Find the minimal changes needed to restore satisfiability
    • mcs() - Via assumption-based MSS complement
    • mcs_naive() - Via naive MSS complement
  • MARCO: Enumerate all MUSes and MCSes
    • marco() - Generator over MUS/MCS
    • marco_naive() - Naive MARCO implementation
    • all_mus() / all_mcs() - Convenience wrappers
    • all_mus_naive() - Naive MUS enumeration

Installation

# Clone the repository
git clone https://github.com/sohaibafifi/pycsp3-explain.git
cd pycsp3-explain

# Install dependencies
pip install -e .

Requirements

  • Python 3.10+
  • PyCSP3 (>= 2.5)
  • lxml (>= 4.9)
  • Java runtime (for ACE/Choco)

Quick Start

Using satisfy() with Explain Tools

from pycsp3 import *
from pycsp3_explain import *


x = VarArray(size=2, dom=range(10))

satisfy( [
    x[0] == 5,
    x[0] == 7,  # conflicts with x[0] == 5
    x[1] >= 3,
])

constraints  = flatten_constraints(posted())
if solve() == UNSAT:
    print("MUS:", mus(constraints))
    print("Optimal MUS:", optimal_mus(constraints, weights=[1, 1, 1]))
    for kind, subset in marco(constraints):
        print(kind, subset)

    # or use the helper function
    mus_result = explain_unsat("mus", soft=constraints, check=False)
    print("MUS:", mus_result)

    optimal = explain_unsat("optimal_mus", soft=constraints, check=False, weights=[1] * len(constraints))
    print("Optimal MUS:", optimal)

    for kind, subset in explain_unsat("marco", soft=constraints, check=False):
        print(kind, subset)

Notes

  • mus() and mss() use ACE core extraction for efficiency; they fall back to naive versions for non-ACE solvers.
  • MCS is the complement of MSS: MCS = Soft \ MSS
  • Removing MCS constraints from soft constraints leaves MSS, which is satisfiable.

How It Works

Constraint Explanation Problem

Given an infeasible constraint satisfaction problem (CSP), explanation tools help identify:

Concept Question Description
MUS Why is it infeasible? Minimal Unsatisfiable Subset - the smallest set of constraints that conflict
MSS What can be satisfied? Maximal Satisfiable Subset - the largest set of constraints that can hold together
MCS What to fix? Minimal Correction Set - the smallest set of constraints to remove for satisfiability

Relationships

  • Every MUS and every MCS share at least one constraint (hitting set duality)
  • MCS = Soft \ MSS (MCS is the complement of MSS)
  • Multiple MUSes/MSSes/MCSes may exist for a given problem

API Reference

MUS Functions

  • mus(soft, hard=None, solver="ace") - Assumption-based MUS
  • mus_naive(soft, hard=None, solver="ace") - Deletion-based MUS
  • quickxplain_naive(soft, hard=None, solver="ace") - Preferred MUS
  • is_mus(subset, hard=None, solver="ace") - Verify MUS validity
  • all_mus_naive(soft, hard=None, solver="ace") - Enumerate MUSes (naive)
  • optimal_mus(soft, hard=None, weights=None, solver="ace") - Minimum-weight MUS
  • optimal_mus_naive(soft, hard=None, weights=None, solver="ace") - Naive minimum-weight MUS
  • smus(soft, hard=None, solver="ace") - Smallest MUS (fewest constraints)
  • ocus(soft, hard=None, weights=None, solver="ace", ...) - OCUS with subset constraints
  • ocus_naive(soft, hard=None, weights=None, solver="ace") - Naive OCUS
  • OCUSException - Exception for optimal MUS/OCUS routines

MSS/MCS Functions

  • mss(soft, hard=None, solver="ace") - Assumption-based MSS
  • mss_naive(soft, hard=None, solver="ace") - Greedy growing MSS
  • mss_opt(soft, hard=None, weights=None, solver="ace") - Weighted MSS
  • is_mss(subset, soft, hard=None, solver="ace") - Verify MSS validity
  • mcs(soft, hard=None, solver="ace") - Assumption-based MCS
  • mcs_naive(soft, hard=None, solver="ace") - Naive MCS
  • mcs_opt(soft, hard=None, weights=None, solver="ace") - Weighted MCS
  • mcs_from_mss(mss, soft) - Complement of MSS
  • is_mcs(subset, soft, hard=None, solver="ace") - Verify MCS validity

MARCO Enumeration

  • marco(soft, hard=None, solver="ace") - Generator over MUS/MCS
  • marco_naive(soft, hard=None, solver="ace") - Naive MARCO
  • all_mus(soft, hard=None, solver="ace") - Collect all MUSes
  • all_mcs(soft, hard=None, solver="ace") - Collect all MCSes

License

MIT License

References

  • PyCSP3 - Python library for constraint programming
  • CPMpy - Constraint Programming and Modeling in Python
  • Liffiton et al. (2016) - "Fast, flexible MUS enumeration"
  • Junker (2004) - "QuickXplain: Preferred explanations and relaxations"

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pycsp3_explain-0.1.2.tar.gz (91.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pycsp3_explain-0.1.2-py3-none-any.whl (24.6 kB view details)

Uploaded Python 3

File details

Details for the file pycsp3_explain-0.1.2.tar.gz.

File metadata

  • Download URL: pycsp3_explain-0.1.2.tar.gz
  • Upload date:
  • Size: 91.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pycsp3_explain-0.1.2.tar.gz
Algorithm Hash digest
SHA256 7053d4b926fc62e85383f325c3e64fdea077a49d46f2a645e892f22014ca8701
MD5 ef4d1aab5670b7c04ac90d57705769b0
BLAKE2b-256 101ebab9b48e146b1884273ebcc8c019d715306804eb15a086f3ece861708b58

See more details on using hashes here.

Provenance

The following attestation bundles were made for pycsp3_explain-0.1.2.tar.gz:

Publisher: publish.yml on sohaibafifi/pycsp3-explain

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pycsp3_explain-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: pycsp3_explain-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 24.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pycsp3_explain-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 268dce12ea4321fba16aff881429bdf7e95d5e2f2ae7adab8a879bd7e3acdae1
MD5 2320d8829edefb3a6217757d077c9985
BLAKE2b-256 e969bd3b684a8c5078c62466351fc08d510aa43234de36794ee19207edcce99a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pycsp3_explain-0.1.2-py3-none-any.whl:

Publisher: publish.yml on sohaibafifi/pycsp3-explain

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page