ommx_openjij_adapter
====================

.. py:module:: ommx_openjij_adapter


Submodules
----------

.. toctree::
   :maxdepth: 1

   /autoapi/ommx_openjij_adapter/adapter/index


Classes
-------

.. autoapisummary::

   ommx_openjij_adapter.OMMXOpenJijSAAdapter


Functions
---------

.. autoapisummary::

   ommx_openjij_adapter.decode_to_samples


Package Contents
----------------

.. py:class:: OMMXOpenJijSAAdapter(ommx_instance: ommx.Instance, *, beta_min: float | None = None, beta_max: float | None = None, num_sweeps: int | None = None, num_reads: int | None = None, schedule: list | None = None, initial_state: list | dict | None = None, updater: str | None = None, sparse: bool | None = None, reinitialize_state: bool | None = None, seed: int | None = None)



   Sample optimization candidates with OpenJij simulated annealing.

   Install ``ommx-openjij-adapter`` alongside a compatible OMMX SDK. The example
   below needs no other Adapter, external data, or earlier Notebook state.
   :attr:`INPUT_CLASS` describes the exact input accepted by the constructor
   and preparation-free methods: used decision variables must be Binary, the
   objective must be a polynomial minimization, and no regular or special
   constraints may remain active. Polynomial degree is not limited to two:
   OpenJij's QUBO and Binary-HUBO paths are supported.

   :meth:`sample` returns an evaluated :class:`ommx.SampleSet`; :meth:`solve`
   selects its best feasible candidate as a :class:`ommx.Solution`. Both easy
   paths prepare an isolated copy with a fresh recommended policy. To choose
   a penalty weight, prepare an Instance explicitly and call
   :meth:`sample_without_preparation` or :meth:`solve_without_preparation`.

   **Build a problem and choose its penalty weight**

   Choose exactly one of two options and maximize its score. A OneHot
   constraint expresses that exactly one of the Binary variables is one:

   >>> import copy
   >>> from ommx import FixedPenaltyPreparation, Instance, OneHotConstraint, Sense
   >>> from ommx_openjij_adapter import OMMXOpenJijSAAdapter
   >>> source = Instance.maximize()
   >>> x = [source.new_binary("x", subscripts=[i]) for i in range(2)]
   >>> source.objective = 3 * x[0] + 2 * x[1]
   >>> _ = source.add_one_hot_constraint(OneHotConstraint(variables=x))
   >>> target = OMMXOpenJijSAAdapter.INPUT_CLASS
   >>> target.contains(source)
   False

   The source is a constrained maximization, so it is not a direct OpenJij
   input. Take the Adapter's recommended policy and add an application-chosen
   penalty weight. The recommendation deliberately leaves that weight unset.
   :meth:`ommx.Instance.prepare` changes its receiver in place; retain a copy
   of the source when trying different choices:

   >>> prepared = copy.copy(source)
   >>> policy = OMMXOpenJijSAAdapter.recommended_preparation_policy()
   >>> policy.fixed_penalty = (
   ...     FixedPenaltyPreparation.uniform_penalty_method_with_fixed_weight(weight=4.0)
   ... )
   >>> prepared.prepare(target, policy)
   >>> target.contains(prepared)
   True
   >>> assert not target.contains(source)

   Here preparation lowers OneHot to an equality, changes maximization to
   minimization, and penalizes the equality violation with weight 4. Choosing
   both options gains two points over choosing the first alone, but incurs a
   penalty of four. This weight is suitable for this small example; it is not
   a general recipe for choosing sufficient penalties. See
   :meth:`ommx.FixedPenaltyPreparation.uniform_penalty_method_with_fixed_weight`
   for the exact penalty contract, including its treatment of inequalities.

   Reaching :attr:`INPUT_CLASS` establishes the representation accepted by
   OpenJij. It does not guarantee that sampling will find a feasible candidate
   or prove optimality for the original problem. To change the weight, prepare
   a new copy of ``source``. Changing ``policy`` and preparing the already
   applicable ``prepared`` object does not replace the penalty already stored.

   **Sample and read evaluated candidates**

   Pass the explicitly prepared input to the preparation-free method.
   ``num_reads`` is the number of sampling trials; ``seed`` controls the
   sampler's random input. The candidate distribution can vary with the
   backend version and execution environment:

   >>> sample_set = OMMXOpenJijSAAdapter.sample_without_preparation(
   ...     prepared, num_reads=10, seed=42
   ... )
   >>> summary = sample_set.summary
   >>> assert len(summary) == 10
   >>> assert sample_set.sense == Sense.Maximize

   Inspect ``summary`` to see one row per ``sample_id``, with ``objective`` and
   ``feasible`` columns. Different IDs may have identical assignments.
   Feasible candidates appear first, then the reported objective orders each
   feasibility group according to the problem's reporting sense. In this
   example, the reported objective is the original score
   ``3*x[0] + 2*x[1]`` and larger is better. Feasibility includes the retained
   OneHot condition, even though OpenJij receives no active constraints.

   The table is not raw OpenJij energy: sense conversion, penalties, and a
   constant omitted from the sampler coefficients can make the search energy
   differ from the reported objective. Decoding evaluates candidates through
   the prepared Instance, including its retained evaluation information.
   ``extract_decision_variables("x")`` selects variables named ``x``; dictionary
   keys ``(0,)`` and ``(1,)`` are the subscripts assigned while modeling:

   >>> for sample_id in sample_set.sample_ids():
   ...     candidate = sample_set.get(sample_id)
   ...     values = candidate.extract_decision_variables("x")
   ...     assert candidate.objective == 3 * values[(0,)] + 2 * values[(1,)]
   ...     assert candidate.feasible == (sum(values.values()) == 1)

   **Select among the obtained feasible candidates**

   :attr:`ommx.SampleSet.best_feasible` selects by the reported objective among
   the feasible candidates actually obtained. The names and subscripts set
   while modeling identify the selected values:

   >>> solution = sample_set.best_feasible
   >>> selected = solution.extract_decision_variables("x")
   >>> assert solution.feasible and sum(selected.values()) == 1
   >>> assert solution.objective == 3 * selected[(0,)] + 2 * selected[(1,)]
   >>> details = solution.decision_variables_df()[["name", "subscripts", "value"]]

   This selection is not a global optimality certificate. If no sampled
   candidate is feasible, ``best_feasible`` raises :class:`ValueError`.
   Inspect the feasibility column and reconsider the model, weight, or
   sampling settings. :meth:`solve_without_preparation` performs the same
   sampling and selection in one call and can raise the same error; use the
   sampling path when you need the unsuccessful candidates too.

   Calling :meth:`sample` or :meth:`solve` obtains a new recommended policy;
   neither accepts the edited ``policy`` above. Explicit preparation followed
   by a preparation-free method keeps the application's penalty choice.
   The :class:`ommx.SampleSet` Reference explains result inspection and
   selection in full. For an independent application, see the
   :doc:`TSP sampling example </tutorial/tsp_sampling_with_openjij_adapter>`.


   .. py:method:: check_applicability(ommx_instance: ommx.Instance) -> ommx.InstanceClassMembershipReport
      :classmethod:


      Check ``INPUT_CLASS`` membership without mutation.



   .. py:method:: decode(data: openjij.Response) -> ommx.Solution

      Decode sampler output and return its best feasible solution.



   .. py:method:: decode_to_samples(data: openjij.Response) -> ommx.Samples

      Convert `openjij.Response <https://openjij.github.io/OpenJij/reference/openjij/index.html#openjij.Response>`_ to :class:`ommx.Samples`

      There is a static method :meth:`decode_to_samples` that does the same thing.



   .. py:method:: decode_to_sampleset(data: openjij.Response) -> ommx.SampleSet


   .. py:method:: recommended_preparation_policy() -> ommx.PreparationPolicy
      :classmethod:


      Recommend the model changes commonly needed by OpenJij.

      The recommendation lowers every special-constraint family, converts the
      active objective to minimization, adds Integer slack while permitting an
      inequality to remain when exact equality conversion is unavailable,
      and log-encodes every used Integer variable. Both Integer slack ranges
      use 32.

      Fixed penalty magnitudes remain explicit caller parameters because
      sufficient values depend on the application. The shared ``Instance``
      owner operation validates their nonnegative-with-tolerance domain. Set
      ``fixed_penalty`` on the fresh returned policy when active constraints
      must be removed.



   .. py:method:: require_applicable(ommx_instance: ommx.Instance) -> ommx.InstanceClassMembershipReport
      :classmethod:


      Return the membership report or raise ``AdapterNotApplicableError``.



   .. py:method:: sample(ommx_instance: ommx.Instance, *, beta_min: float | None = None, beta_max: float | None = None, num_sweeps: int | None = None, num_reads: int | None = None, schedule: list | None = None, updater: str | None = None, sparse: bool | None = None, reinitialize_state: bool | None = None, seed: int | None = None, diagnostics: ommx.adapter.DiagnosticsSink | None = None) -> ommx.SampleSet
      :classmethod:


      Prepare and sample an isolated copy of ``ommx_instance``.

      This obtains a fresh recommended policy. For a complete example with
      an explicit penalty weight, see
      :class:`ommx_openjij_adapter.OMMXOpenJijSAAdapter`.

      OpenJij ``initial_state`` values are defined against the solver-variable
      representation of an exact Adapter input, so they are accepted only by
      :meth:`sample_without_preparation`.



   .. py:method:: sample_without_preparation(ommx_instance: ommx.Instance, *, beta_min: float | None = None, beta_max: float | None = None, num_sweeps: int | None = None, num_reads: int | None = None, schedule: list | None = None, initial_state: list | dict | None = None, updater: str | None = None, sparse: bool | None = None, reinitialize_state: bool | None = None, seed: int | None = None, diagnostics: ommx.adapter.DiagnosticsSink | None = None) -> ommx.SampleSet
      :classmethod:


      Sample an exact OpenJij Adapter input without preparing it.

      See :class:`ommx_openjij_adapter.OMMXOpenJijSAAdapter` for a complete
      example from an explicitly prepared constrained model to candidate
      evaluation and selection.

      ``initial_state`` is defined against this exact input's solver-variable
      representation.



   .. py:method:: solve(ommx_instance: ommx.Instance, *, beta_min: float | None = None, beta_max: float | None = None, num_sweeps: int | None = None, num_reads: int | None = None, schedule: list | None = None, updater: str | None = None, sparse: bool | None = None, reinitialize_state: bool | None = None, seed: int | None = None, diagnostics: ommx.adapter.DiagnosticsSink | None = None) -> ommx.Solution
      :classmethod:


      Prepare, sample, and return the best feasible result.

      Selects from the obtained candidates and does not prove optimality.
      Raises :class:`ValueError` if no sampled candidate is feasible. Use
      :meth:`sample` to retain all candidates for inspection.

      OpenJij ``initial_state`` values are defined against the solver-variable
      representation of an exact Adapter input, so they are accepted only by
      :meth:`solve_without_preparation`.



   .. py:method:: solve_without_preparation(ommx_instance: ommx.Instance, *, beta_min: float | None = None, beta_max: float | None = None, num_sweeps: int | None = None, num_reads: int | None = None, schedule: list | None = None, initial_state: list | dict | None = None, updater: str | None = None, sparse: bool | None = None, reinitialize_state: bool | None = None, seed: int | None = None, diagnostics: ommx.adapter.DiagnosticsSink | None = None) -> ommx.Solution
      :classmethod:


      Return the best feasible result from :meth:`sample_without_preparation`.

      Selection uses the reported objective and retained feasibility checks.
      It does not prove optimality and raises :class:`ValueError` when no
      feasible candidate was obtained. Use :meth:`sample_without_preparation`
      to inspect all candidates, as shown in
      :class:`ommx_openjij_adapter.OMMXOpenJijSAAdapter`.

      ``initial_state`` is defined against the exact Adapter input's
      solver-variable representation.



   .. py:attribute:: INPUT_CLASS
      :type:  ClassVar[ommx.InstanceClass]

      Required condition for an exact Adapter input.



   .. py:attribute:: MAX_OPENJIJ_VARIABLE_ID
      :type:  ClassVar[int]
      :value: 9223372036854775807



   .. py:attribute:: beta_max
      :type:  float | None
      :value: None


      maximum value of inverse temperature 



   .. py:attribute:: beta_min
      :type:  float | None
      :value: None


      minimal value of inverse temperature 



   .. py:attribute:: initial_state
      :type:  list | dict | None
      :value: None


      initial state (parameter only used if problem is QUBO)



   .. py:attribute:: num_reads
      :type:  int | None
      :value: None


      number of reads 



   .. py:attribute:: num_sweeps
      :type:  int | None
      :value: None


      number of sweeps 



   .. py:attribute:: ommx_instance
      :type:  ommx.Instance

      Isolated copy of the exact Adapter input used to evaluate returned samples.



   .. py:attribute:: reinitialize_state
      :type:  bool | None
      :value: None


      if true reinitialize state for each run (parameter only used if problem is QUBO)



   .. py:property:: sampler_input
      :type: dict[tuple[int, ...], float]



   .. py:attribute:: schedule
      :type:  list | None
      :value: None


      list of inverse temperature (parameter only used if problem is QUBO)



   .. py:attribute:: seed
      :type:  int | None
      :value: None


      seed for Monte Carlo algorithm 



   .. py:property:: solver_input
      :type: dict[tuple[int, ...], float]


      Expose :attr:`sampler_input` through the SolverAdapter interface.



   .. py:attribute:: sparse
      :type:  bool | None
      :value: None


      use sparse matrix or not (parameter only used if problem is QUBO)



   .. py:attribute:: updater
      :type:  str | None
      :value: None


      updater algorithm 



.. py:function:: decode_to_samples(response: openjij.Response) -> ommx.Samples

   Convert `openjij.Response <https://openjij.github.io/OpenJij/reference/openjij/index.html#openjij.Response>`_ to :class:`ommx.Samples`


