Skip to main content

Python bindings for the D4 model counter and compiler

Project description

py-d4

Python bindings for the D4 compiler and model counter, supporting option structures, CNF files, custom clause vectors, logic circuits, weighted model counting, and d-DNNF queries. Built with nanobind and scikit-build-core.


🚀 Users Guide

1. Installation

Install the package directly from your GitLab PyPI package registry (typically configured in your CI or local .pip/pip.conf):

pip install d4Solver --extra-index-url https://gitlab.univ-artois.fr/api/v4/projects/<PROJECT_ID>/packages/pypi/simple

2. Usage Examples

2.1 Basic Model Counting

You can instantiate a Solver using a CNF filepath or raw Python clause structures (list of lists/tuples of literals, 1-based indexing):

import py_d4

# 1. Option A: Load from a DIMACS CNF file
solver = py_d4.Solver("path/to/formula.cnf")

# 2. Option B: Pass raw Python clauses and total variable count
# Formula: (x1 or x2) and (not x2 or x3)
clauses = [
    [1, 2],
    [-2, 3]
]
nb_vars = 3
solver = py_d4.Solver(clauses, nb_vars)

# Run model counting
count_res = solver.count()
print(f"Number of models: {count_res.getResult()}")     # Large integer as string (GMP support)
print(f"As Python integer: {count_res.getIntResult()}")  # Safe python int

2.2 Compilation to d-DNNF

py-d4 can compile CNF formulas and circuits into Decision Diagram / Deterministic Decomposable Negation Normal Form (d-DNNF):

import py_d4

clauses = [[1, 2], [-2, 3]]
solver = py_d4.Solver(clauses, 3)

# Compile
compile_res = solver.compile()

# Access compiled graph statistics
print(f"Nodes in d-DNNF: {compile_res.getNbNodes()}")
print(f"Edges in d-DNNF: {compile_res.getNbEdges()}")

# Get the compiled NNF circuit string (in standard d-DNNF format)
nnf_str = compile_res.getNNFString()
print("NNF String:\n", nnf_str)

2.3 Querying the Compiled d-DNNF

Once compiled, you can run multiple queries (SAT checks or model counting) under different literal assumptions:

# Check if the formula is satisfiable (no assumptions)
is_sat = compile_res.isSAT([])  # True/False

# Check satisfiability assuming x1 is True (1) and x2 is False (-2)
is_sat_under_assumptions = compile_res.isSAT([1, -2])

# Count models under literal assumptions
# E.g., model count assuming x1 is True
count_under_x1 = compile_res.count([1])
print(f"Models satisfying x1: {count_under_x1}")

2.4 Weighted Model Counting (WMC)

You can assign weights to literals for exact weighted model counting:

import py_d4

# Formula: (x1 or x2)
solver = py_d4.Solver([[1, 2]], nb_vars=2)

# Define weights for literals (keys are 1-based literals, values are string representations)
weights = {
    1: "0.3",
    -1: "0.7",
    2: "0.4",
    -2: "0.6"
}
# Set weights (WeightType can be FLOAT or GMP)
solver.setWeights(weights, py_d4.WeightType.FLOAT)

# Compute WMC directly
count_res = solver.count()
print("WMC Result:", float(count_res.getResult()))  # Output: 0.58

# Or compile and query WMC under assumptions
compile_res = solver.compile()
print("WMC under x1=True:", float(compile_res.count([1])))  # Output: 0.3

2.5 Logic Gates / Circuit Compilation

Instead of CNF, you can initialize the solver with logic gates to compile or count structured circuits:

import py_d4

# Create a gate representing: x3 = x1 AND (not x2)
gate = py_d4.Gate()
gate.gateType = py_d4.GateType.AND
gate.inputs = [1, -2]
gate.output = 3

# Instantiate solver from gate specifications
solver = py_d4.Solver([gate], nb_vars=3)
print("Models for circuit:", solver.count().getIntResult())

2.6 Solver Configuration & Options

Fine-tune the behavior of D4 by mutating native C++ option structures. Documentation and description of settings are exposed natively as Python docstrings:

import py_d4

# Instantiate default options
opt = py_d4.OptionDpllStyleMethod()

# 1. Read Option Descriptions (C++ docstrings exposed to Python)
print(py_d4.OptionDpllStyleMethod.exploitModel.__doc__)
# Output: "If we exploit model during search"

# 2. Modify properties directly (with type safety)
opt.precision = 30
opt.exploitModel = False
opt.optionSolver.solverName = 0  # 0: glucose, 1: minisat

# 3. Modify nested option group settings
opt.optionBranchingHeuristic.freqDecay = 98

# 4. Pass options to the Solver
solver = py_d4.Solver("formula.cnf", opt)

# 5. Serialize options to/from standard Python Dictionaries
config_dict = py_d4.dump_options_to_dict(opt)
opt_restored = py_d4.load_options_from_dict(config_dict)

# 6. Serialize options to/from raw JSON Strings (via native C++ bindings)
json_str = py_d4._py_d4.dump_options_to_json(opt)
opt_restored_json = py_d4._py_d4.load_options_from_json(json_str)

🛠️ Developers Guide

1. Requirements

Before building locally, ensure the following system-level dependencies are installed on your host:

  • C++20 compatible compiler (e.g. GCC >= 10, Clang >= 10)
  • CMake (>= 3.15)
  • GMP development headers (libgmp-dev / gmp-devel)
  • Zlib development headers (zlib1g-dev / zlib-devel)

2. Local Build Pipeline

To compile the C++ extension module and deploy it directly inside your local Python package tree, run:

# 1. Provide your GitLab access token to clone the D4 dependency
export GITLAB_TOKEN_LOGICAL="your_gitlab_token"

# 2. Configure, generate bindings, compile, and deploy shared library
./build.sh

Alternatively, you can install the package in editable mode via pip:

pip install -e .

3. Re-Generating Bindings

If D4 option headers change, you can automatically parse the new C++ classes and inline constructor descriptions to rebuild the nanobind bindings:

python3 scripts/generate_bindings.py /path/to/local/d4

(If /path/to/local/d4 is omitted, the script automatically searches the CMake FetchContent directory).

4. Running Tests

To execute the test suite and verify the integrity of the wrapper:

LD_PRELOAD=$(gcc -print-file-name=libstdc++.so.6) PYTHONPATH=. python3 tests/test_options.py

5. GitLab CI/CD Pipeline

The project includes an automated multi-stage .gitlab-ci.yml pipeline:

  • Build Stage: Uses cibuildwheel to compile optimized, standalone Linux wheels for Python 3.8 to 3.13. It automatically routes the group-level GITLAB_TOKEN_LOGICAL CI variable to authenticate both the py-d4 and internal d4/optree sub-project checkouts.
  • Deploy Stage: Triggered on pushing Git tags. Automatically publishes the generated wheel packages directly to the GitLab project PyPI package registry using twine.

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

d4solver-0.1.0-cp313-cp313-win_amd64.whl (6.0 MB view details)

Uploaded CPython 3.13Windows x86-64

d4solver-0.1.0-cp312-cp312-win_amd64.whl (6.0 MB view details)

Uploaded CPython 3.12Windows x86-64

d4solver-0.1.0-cp311-cp311-win_amd64.whl (6.0 MB view details)

Uploaded CPython 3.11Windows x86-64

d4solver-0.1.0-cp310-cp310-win_amd64.whl (6.0 MB view details)

Uploaded CPython 3.10Windows x86-64

d4solver-0.1.0-cp39-cp39-win_amd64.whl (6.0 MB view details)

Uploaded CPython 3.9Windows x86-64

File details

Details for the file d4solver-0.1.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: d4solver-0.1.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 6.0 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for d4solver-0.1.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 642d668383220181f0e1c169d4c8df83d951e6272152198db1df0479240b69f9
MD5 7ba1a338e1a8442e582652171e21b6e1
BLAKE2b-256 6e249c57a77e71f7e962b074c226f837d7caa9004626ddccc6951ca3c4cfc3f9

See more details on using hashes here.

File details

Details for the file d4solver-0.1.0-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: d4solver-0.1.0-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 6.0 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for d4solver-0.1.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 870e92148bdb9ce06d38c0e9866bd6ec48969d379d6073ab501655a4ea04e9b7
MD5 a96079fedcde1699e812c654bb9111be
BLAKE2b-256 c22771df9ad348e4dbba7fba5cd1d056ce0f82b249ef4d31d4e3ac1df95acb55

See more details on using hashes here.

File details

Details for the file d4solver-0.1.0-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: d4solver-0.1.0-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 6.0 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for d4solver-0.1.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 cdac5121cd9d04bcc9a23ac021220d8d0988cef755766d401a91bdaa767e6f09
MD5 e59eaf88239844c147d91ecc65b3f196
BLAKE2b-256 dceaeb3ed25bf8dcbdca162114ba221f1b22f904d480d759a59d2009ee01e0ee

See more details on using hashes here.

File details

Details for the file d4solver-0.1.0-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: d4solver-0.1.0-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 6.0 MB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for d4solver-0.1.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 2ed28b3d1521487b465ce5adf2a8333df339fddc43fd6c5033334fd3ebcca64f
MD5 c9170ece5c2407bfc26936acf321e816
BLAKE2b-256 295d14e44b00d186ffe407f7d07d8ce7f02285045bc242b2328f7b03e23c5699

See more details on using hashes here.

File details

Details for the file d4solver-0.1.0-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: d4solver-0.1.0-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 6.0 MB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for d4solver-0.1.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 eb4b19525b643b62ef5d427b4c59e3c5dbfcf1c38d2dc444bce689dde13c9b69
MD5 2f5c8739d7806b4806ca4b6d48fca84f
BLAKE2b-256 d0cd520c1b95f0b1cc6ce7c7fb092240c1f6a27b1fd29871d2f4b1e609338ccf

See more details on using hashes here.

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