Skip to main content

omnibias.discrete.proposers

0.1.0a2AlphaPython >=3.10AGPL / commercial

Shared discrete-problem contracts, annealed relaxations, hard decoders, and optimality-gap evidence.

import omnibias.discrete.proposers
Module contract & mathematical conventions

Optional discovery proposers that wrap anneal_descent.

Not registered on omnibias.core.proof.discovery.get_proposer. Pass an instance to ~omnibias.core.proof.discovery.run_discovery. Missing torch or jax makes AnnealDescentProposer.propose yield nothing so the caller stays BLOCKED.

Shared formulas do not imply universal floating-point identity. Verify dtype, shape, derivative-order support, and the stated numerical assumptions for the path you use.

CLASS

AnnealDescentProposer​

omnibias.discrete.AnnealDescentProposerSource ↗
class AnnealDescentProposer

Relax -score with anneal_descent, then snap to a 0/1 vertex.

Parameters

NameType & defaultContract
backendkeyword-onlystrDefault: 'torch'See the operation contract and implementation below.
seedkeyword-onlyintDefault: 0See the operation contract and implementation below.
Executed regression · anneal proposer hits toy via fallback

Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.

def test_anneal_proposer_hits_toy_via_fallback() -> None:
    pytest.importorskip("torch")
    family = IntegerIntervalFamily(lo=-3, hi=3, target_square=4)
    result = run_discovery(
        family.statement,
        family,
        AnnealDescentProposer(),
        budget=16,
    )
    assert result.status == "PROVED"
    assert result.proposer == "anneal_descent"
    assert result.candidate in (-2, 2)
python -m pytest "packages/omnibias-discrete/tests/test_proposers.py::test_anneal_proposer_hits_toy_via_fallback" -q

Fields & methods

__init__method
__init__(self, *, backend: str='torch', seed: int=0) -> None

See the class contract above and the exact method implementation below.

Parameters

NameType & defaultContract
backendkeyword-onlystrDefault: 'torch'See the operation contract and implementation below.
seedkeyword-onlyintDefault: 0See the operation contract and implementation below.

Returns: None

Executed regression · anneal proposer hits toy via fallback

Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.

def test_anneal_proposer_hits_toy_via_fallback() -> None:
    pytest.importorskip("torch")
    family = IntegerIntervalFamily(lo=-3, hi=3, target_square=4)
    result = run_discovery(
        family.statement,
        family,
        AnnealDescentProposer(),
        budget=16,
    )
    assert result.status == "PROVED"
    assert result.proposer == "anneal_descent"
    assert result.candidate in (-2, 2)
python -m pytest "packages/omnibias-discrete/tests/test_proposers.py::test_anneal_proposer_hits_toy_via_fallback" -q
Method implementation
    def __init__(self, *, backend: str = "torch", seed: int = 0) -> None:
        self.backend = backend
        self.seed = seed
View source ↗
proposemethod
propose(self, family: FiniteFamily, budget: int) -> Iterator[Candidate]

See the class contract above and the exact method implementation below.

Parameters

NameType & defaultContract
familypositional-or-keywordFiniteFamilyRequiredSee the operation contract and implementation below.
budgetpositional-or-keywordintRequiredSee the operation contract and implementation below.

Returns: Iterator[Candidate]

Executed regression · anneal proposer hits toy via fallback

Recorded coverage confirms this test executed the API body. This example belongs to the pinned upstream test suite. It may use fixtures and imports from its full file. Run it from that checkout with its test dependencies installed.

def test_anneal_proposer_hits_toy_via_fallback() -> None:
    pytest.importorskip("torch")
    family = IntegerIntervalFamily(lo=-3, hi=3, target_square=4)
    result = run_discovery(
        family.statement,
        family,
        AnnealDescentProposer(),
        budget=16,
    )
    assert result.status == "PROVED"
    assert result.proposer == "anneal_descent"
    assert result.candidate in (-2, 2)
python -m pytest "packages/omnibias-discrete/tests/test_proposers.py::test_anneal_proposer_hits_toy_via_fallback" -q
Method implementation
    def propose(self, family: FiniteFamily, budget: int) -> Iterator[Candidate]:
        if budget <= 0:
            return
        origin = family.origin()
        bits = _bit_tuple(family, origin)
        if bits is None:
            yield from ScoreGuidedWalk().propose(family, budget)
            return
        snapped = self._anneal_bits(family, bits)
        if snapped is None:
            return
        seen: set[Candidate] = set()
        start = _from_bits(family, snapped, origin)
        for candidate in (origin, start, *family.neighbors(start)):
            if candidate in seen:
                continue
            seen.add(candidate)
            yield candidate
            if len(seen) >= budget:
                return
        leftover = budget - len(seen)
        if leftover > 0:
            for candidate in ScoreGuidedWalk().propose(family, leftover + len(seen)):
                if candidate in seen:
                    continue
                seen.add(candidate)
                yield candidate
                if len(seen) >= budget:
                    return
View source ↗
backendattribute
backend: str = backend

Public instance attribute assigned by __init__. The source assignment is backend = backend; it describes instance state, not a literal constructor default.

View source ↗
seedattribute
seed: int = seed

Public instance attribute assigned by __init__. The source assignment is seed = seed; it describes instance state, not a literal constructor default.

View source ↗
Read the implementation
class AnnealDescentProposer:
    """Relax ``-score`` with ``anneal_descent``, then snap to a 0/1 vertex."""

    name = "anneal_descent"

    def __init__(self, *, backend: str = "torch", seed: int = 0) -> None:
        self.backend = backend
        self.seed = seed

    def propose(self, family: FiniteFamily, budget: int) -> Iterator[Candidate]:
        if budget <= 0:
            return
        origin = family.origin()
        bits = _bit_tuple(family, origin)
        if bits is None:
            yield from ScoreGuidedWalk().propose(family, budget)
            return
        snapped = self._anneal_bits(family, bits)
        if snapped is None:
            return
        seen: set[Candidate] = set()
        start = _from_bits(family, snapped, origin)
        for candidate in (origin, start, *family.neighbors(start)):
            if candidate in seen:
                continue
            seen.add(candidate)
            yield candidate
            if len(seen) >= budget:
                return
        leftover = budget - len(seen)
        if leftover > 0:
            for candidate in ScoreGuidedWalk().propose(family, leftover + len(seen)):
                if candidate in seen:
                    continue
                seen.add(candidate)
                yield candidate
                if len(seen) >= budget:
                    return

    def _anneal_bits(self, family: FiniteFamily, bits: tuple[int, ...]) -> tuple[int, ...] | None:
        n = len(bits)
        schedule = AnnealSchedule(beta0=0.5, beta_growth=2.0, stages=3, steps=4)

        def energy_of(values: tuple[int, ...]) -> float:
            origin = family.origin()
            candidate = _from_bits(family, values, origin)
            value = family.score(candidate)
            score = value if isinstance(value, Fraction) else Fraction(value)
            return -float(score)

        if self.backend == "jax":
            return self._anneal_jax(family, n, schedule, energy_of)
        return self._anneal_torch(family, n, schedule, energy_of)

    def _anneal_torch(
        self,
        family: FiniteFamily,
        n: int,
        schedule: AnnealSchedule,
        energy_of: Any,
    ) -> tuple[int, ...] | None:
        try:
            import torch
            from omnibias.discrete.torch import anneal_descent
        except ImportError:
            return None

        def grad_x_fn(x: Any) -> Any:
            grads = []
            snapped = tuple(1 if float(v) >= 0.5 else 0 for v in x.detach().tolist())
            base = energy_of(snapped)
            for i in range(n):
                flipped = list(snapped)
                flipped[i] = 1 - flipped[i]
                delta = energy_of(tuple(flipped)) - base
                grads.append(delta)
            return torch.tensor(grads, dtype=x.dtype)

        vertex = anneal_descent(grad_x_fn, scale=1.0, n=n, schedule=schedule)
        return tuple(1 if float(v) >= 0.5 else 0 for v in vertex.detach().tolist())

    def _anneal_jax(
        self,
        family: FiniteFamily,
        n: int,
        schedule: AnnealSchedule,
        energy_of: Any,
    ) -> tuple[int, ...] | None:
        try:
            import jax.numpy as jnp
            from omnibias.discrete.jax import anneal_descent
        except ImportError:
            return None

        def grad_x_fn(x: Any) -> Any:
            snapped = tuple(1 if float(v) >= 0.5 else 0 for v in list(x))
            base = energy_of(snapped)
            grads = []
            for i in range(n):
                flipped = list(snapped)
                flipped[i] = 1 - flipped[i]
                grads.append(energy_of(tuple(flipped)) - base)
            return jnp.asarray(grads, dtype=x.dtype)

        vertex = anneal_descent(grad_x_fn, scale=1.0, n=n, schedule=schedule)
        return tuple(1 if float(v) >= 0.5 else 0 for v in list(vertex))
Other public import paths
  • omnibias.discrete.AnnealDescentProposer
  • omnibias.discrete.proposers.AnnealDescentProposer