.. _nsatz_chapter:

Nsatz: a solver for equalities in integral domains
===========================================================

:Author: Loïc Pottier, Laurent Thery and Lionel Blatter

.. note::
   The tactics described in this chapter require the Stdlib library.

This chapter presents the tactics dedicated to deal with equalities in integral
domains.

What does this tactics do?
------------------------------

On a commutative ring :math:`A` with no zero divisors,
if a polynomial :math:`P` in
:math:`A[X_1,\ldots,X_n]` verifies

.. math::
   c P^r = \sum_{i=1}^{s} S_i P_i,

with :math:`c \in A`, :math:`c \not = 0`, :math:`r` a positive integer, and the
:math:`S_i` s in :math:`A[X_1,\ldots,X_n ]`, then :math:`P` is zero whenever
polynomials :math:`P_1,\ldots,P_s` are zero (the converse is also true when
:math:`A` is an algebraically closed field: the method is complete).

In the same setting, if a polynomial :math:`P` in
:math:`A[X_1,\ldots,X_n]` verifies

.. math:: c P = \sum_{i=1}^{s} S_i P_i,

with :math:`c \in A`, :math:`c = 1` or :math:`c = -1`, then
:math:`\exists Y_1, \dots, Y_m, P = \sum_{i=1}^{m} Y_i P_i`

The :tacn:`nsatz` and :tacn:`ensatz` tactics finds :math:`S_1, \ldots, S_s`,
:math:`c` and :math:`r` by the computation of a Gröbner basis
of the ideal generated by :math:`P_1,...,P_s`.
This is done using an adapted version of the Buchberger algorithm.
The witnesses returned by the Buchberger algorithm are checked to be correct
solutions to the inital problem.

This computation is done after a step of *reification*.

Concrete usage
---------------------

To use the tactic :tacn:`nsatz` described in this section, load the ``Nsatz``
module with the command ``Require Import Nsatz``.  Alternatively, if you prefer
not to transitively depend on the files that declare the axioms used to define
the real numbers, you can ``Require Import NsatzTactic`` instead; this will
still allow :tacn:`nsatz` to solve goals defined about :math:`\mathbb{Z}`,
:math:`\mathbb{Q}` and any user-registered rings.

To use the tactic :tacn:`ensatz` described in this section, use in
addition the command ``Require Import ENsatzTactic``.

.. tacn:: nsatz {? with radicalmax := @one_term strategy := @one_term parameters := @one_term variables := @one_term }

   This tactic is for solving goals of the form

   .. math:: P(\bar{X}) = Q(\bar{X}),

   given the premises :math:`P_i(\bar{X}) = Q_i(\bar{X})`, which may be part
   of the goal or already in the hypotheses or a mix of both,
   :math:`A` an integral  domain, i.e. a commutative ring with no zero divisors,
   :math:`\bar{X} \in A^n`, and all :math:`P` and :math:`Q` are polynomials.
   For example, :math:`A`
   can be :math:`\mathbb{R}`, :math:`\mathbb{Z}`, or :math:`\mathbb{Q}`.
   Note that the equality :math:`=` used in these goals can be
   any setoid equality (see :ref:`tactics-enabled-on-user-provided-relations`) ,
   not only Leibniz equality.

   `radicalmax`
     bound when searching for r such that
     :math:`c (P−Q)^r = \sum_{i=1..s} S_i (P_i − Q_i)`.
     This argument must be of type `N` (natural numbers).

   `strategy`
     gives the order on variables :math:`X_1,\ldots,X_n` and the strategy
     used in Buchberger algorithm (see :cite:`sugar` for details):

       * `strategy := 0%Z`: reverse lexicographic order and newest s-polynomial.
       * `strategy := 1%Z`: reverse lexicographic order and sugar strategy.
       * `strategy := 2%Z`: pure lexicographic order and newest s-polynomial.
       * `strategy := 3%Z`: pure lexicographic order and sugar strategy.

   `parameters`
     a list of parameters of type `R`, containing the variables
     :math:`X_{i_1},\ldots,X_{i_k}` among
     :math:`X_1,\ldots,X_n`.  Computation will be performed with
     rational fractions in these parameters, i.e. polynomials have
     coefficients in :math:`R(X_{i_1},\ldots,X_{i_k})`. In this case,
     the coefficient :math:`c` can be a nonconstant polynomial in
     :math:`X_{i_1},\ldots,X_{i_k}`, and the tactic
     produces a goal which states that :math:`c` is not zero.

   `variables`
     a list of variables of type `R` in the decreasing order in
     which they will be used in the Buchberger algorithm. If the list is empty,
     then `lvar` is replaced by all the variables which are not in
     `parameters`.

   .. example::

    .. rocqtop:: in extra-stdlib

       From Stdlib Require Import Znumtheory.
       From Stdlib Require Import ZArith.
       From Stdlib Require Import ZNsatz.

       Goal forall (x y z : Z), (
           x + y + z = 0 ->
           x * y + x * z + y * z = 0 ->
           x * y * z = 0 ->
           x * x * x = 0)%Z.
       Proof.
         nsatz.
       Qed.

   See the file `Nsatz.v <https://github.com/rocq-prover/stdlib/blob/master/test-suite/success/Nsatz.v>`_
   for examples, especially in geometry.

.. tacn:: ensatz {? with strategy := @one_term }

   Solves goals of the form

   .. math::
      \exists Y_1, \ldots, Y_m \in A,
      P(\bar{X}) = Q(\bar{X}) + \sum_{i=1}^{m} Y_i * I_i(\bar{X})

   given the premises :math:`P_i(\bar{X}) = Q_i(\bar{X})`, which may be part
   of the goal or already in the hypotheses or a mix of both,
   :math:`A` an integral domain, i.e. a commutative ring with no zero divisors,
   :math:`\bar{X} \in A^n`, and all :math:`P`, :math:`Q` and :math:`I` are
   polynomials. For example, :math:`A`
   can be :math:`\mathbb{R}`, :math:`\mathbb{Z}`, or :math:`\mathbb{Q}`.
   Note that the equality :math:`=` used in these goals can be
   any setoid equality (see :ref:`tactics-enabled-on-user-provided-relations`),
   not only Leibniz equality.

   For the `strategy` parameter, see the desciption for the `nsatz` tactic.


   .. example::

    .. rocqtop:: in extra-stdlib

       From Stdlib Require Import Znumtheory.
       From Stdlib Require Import ZArith.
       From Stdlib Require Import ZNsatz.
       From Stdlib Require Import ENsatzTactic.

       Goal forall a b n j x y z : Z,
           a - j = x * n ->
           b - y = z * n ->
           exists k : Z, a * b - j * y = k * n.
       Proof.
         ensatz.
       Qed.

   The tactic can also solve goals with existential variables.

   .. example::

     .. rocqtop:: in extra-stdlib

       From Stdlib Require Import Znumtheory.
       From Stdlib Require Import ZArith.
       From Stdlib Require Import ZNsatz.
       From Stdlib Require Import ENsatzTactic.

       Goal forall a b n j x y z : Z,
           a - j = x * n ->
           b - y = z * n ->
           exists k : Z, a * b - j * y = k * n.
       Proof.
         intros.
         eexists.
         ensatz.
       Qed.


   See the file
   `ENsatz.v <https://github.com/rocq-prover/stdlib/blob/master/test-suite/success/ENsatz.v>`_
   and
   `EENsatz.v <https://github.com/rocq-prover/stdlib/blob/master/test-suite/success/EENsatz.v>`_
   for examples.

.. tacn:: nsatz_compute @one_term
   :undocumented:
