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.1.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.1-py3-none-any.whl (24.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pycsp3_explain-0.1.1.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.1.tar.gz
Algorithm Hash digest
SHA256 9ac157b7db165022daa0c95b027933468ebea28797bd3aa007137f88d9bbd305
MD5 95f72620039155850b23ee87bdc768af
BLAKE2b-256 b17e3d0885bdef7ac80ff0489828e090a9bbac7fa8c77b0aa84bc6b6ecc93b8c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pycsp3_explain-0.1.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: pycsp3_explain-0.1.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b098ebce87e4a2d054d12c73bed8ea63103446af49a457f0f110aa9826755e95
MD5 20d96c76960bc78dd1fbb539f95f15ac
BLAKE2b-256 7292f16e06dcff8b4baf0f5a9d5ceab4c886cdf0c00dbca4c51add0d2f7fcb2c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pycsp3_explain-0.1.1-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