#include "bad_selection_strategy.h"
#include "bad_reduction.h"
#include "bad_regularize.h"
#include "bad_quadruple.h"
#include "bad_Rosenfeld_Groebner.h"
#include "bad_global.h"
#include "bad_base_field.h"
#include "bad_stats.h"

/*
 * blad_indent: -l120
 */

/*
 * texinfo: bad_Rosenfeld_Groebner
 * Apply a version of the @dfn{RosenfeldGrobner} algorithm.
 *
 * This version handles as well differential systems as non differential
 * ones. For a better legibility, this documentation assumes that the
 * system is differential.
 *
 * Assign to @var{ideal} a set of differential regular chains.
 * These differential regular chains define differential ideals whose
 * intersection is equal to the radical of the differential ideal
 * @math{[P \cup A_0]:(S \cup H_{A_0})^\infty}. 
 *
 * The argument @var{A0} provides a starting regular differential chain.
 * If it is nonempty then all computed regular differential
 * chains are obtained by extending it.
 * 
 * The function @code{bad_fast_primality_test_regchain} is applied
 * over each component of @var{ideal}. Thus some output regular
 * differential chains may have the prime ideal property set.
 * 
 * The intersection may involve redundant components.
 * The function @code{bad_remove_redundant_components_intersectof_regchain},
 * which may detect and remove some of them is not called.
 * 
 * The argument @var{S} may be zero.
 * 
 * If different from zero, @var{K0} contains a description
 * of the base field of the differential polynomials. In this case,
 * every nonzero polynomial @var{p} lying in the base field is
 * considered as nonzero by @dfn{RosenfeldGroebner}: the 
 * case @math{p = 0} is not discussed.
 * If @var{K0} involves a non trivial regular differential
 * chain then the elements of this chain are incorporated to each
 * output regular differential chain.
 * If @var{K0} is zero then the base field is supposed to be
 * the purely transcendental extension of the field of the 
 * rational numbers with the independent variables.
 * 
 * The properties of @var{ideal} are supposed to be set by the calling
 * function. Exception @code{BAD_ERRIBF} is raised if the properties
 * of the regular chain of @var{K0} are not compatible with those
 * of @var{ideal}. Exceptions @code{BAD_ERRIAC} or @code{BAD_ERRCRC}
 * are raised if the regular chain @var{A0} is not compatible with
 * the one of @var{K0} or with the properties of @var{ideal}.
 *
 * The argument @var{C}, which may be zero, permits to control the
 * splitting mechanism of @dfn{RosenfeldGroebner}.
 *
 * The argument @var{T}, which may be zero, permits to compute
 * and return a description of the splitting tree implicitly 
 * generated by @dfn{RosenfeldGroebner}.
 * When @dfn{RosenfeldGroebner} is used to perform the differential
 * elimination stage of the @dfn{DenefLipshitz} algorithm, the
 * field @code{DenefLipshitz} of @var{C} should be set to @code{true} 
 * and the activity of @var{tree} should be either 
 * @code{bad_quiet_splitting_tree} or @code{bad_verbose_splitting_tree}.
 */

BAD_DLL void
bad_Rosenfeld_Groebner (
    struct bad_intersectof_regchain *ideal,
    struct bad_splitting_tree *T,
    struct bap_tableof_polynom_mpz *P,
    struct bap_tableof_polynom_mpz *S,
    struct bad_base_field *K0,
    struct bad_regchain *A0,
    struct bad_splitting_control *C)
{
  struct bad_regchain *A;
  struct bad_base_field *K;
  struct bad_selection_strategy *strategy;
  struct bad_splitting_control *control;
  struct bad_splitting_tree *tree;

  struct bad_tableof_quadruple tabG;

  enum bad_typeof_reduction type_red;
  struct bap_tableof_polynom_mpz ineqs;
  struct bap_tableof_product_mpz factored_ineqs;
  struct bap_product_mpz prod;
  struct bap_tableof_polynom_mpz tabP;
  struct bap_polynom_mpz *p = (struct bap_polynom_mpz *) 0;
  struct bav_tableof_term *thetas;
  struct bav_tableof_tableof_variable tabTL;
  struct bav_tableof_variable *leaders, *tabL1, *tabL2;
  ba0_int_p counter;
  struct ba0_mark M;
/*
 * The two next variables are local to the main loop but are declared here to avoid a warning
 */
  ba0_int_p i, numberof_input_equations = 0;
  bool use_dimlb = false;
  bool discarded_branch;

  ba0_push_another_stack ();
  ba0_record (&M);
/*
 * Initialize stats
 */
  bad_init_stats ();
  bad_global.stats.begin = time (0);
/*
 * Resulting regular chains get the properties automatically derived from that of ideal
 */
  ideal->inter.size = 0;
  bad_set_automatic_properties_attchain (&ideal->attrib);
/*
 * The type of reduction
 */
  if (bad_has_property_attchain (&ideal->attrib, bad_differential_ideal_property))
    type_red = bad_full_reduction;
  else
    type_red = bad_algebraic_reduction;
/*
 * From now on, use control
 */
  if (C == (struct bad_splitting_control *) 0)
    control = bad_new_splitting_control ();
  else
    control = C;
/*
 * From now on, use base field K
 */
  if (K0 == (struct bad_base_field *) 0)
    K = bad_new_base_field ();
  else
    {
      if (!bad_is_a_compatible_base_field (K0, &ideal->attrib))
        BA0_RAISE_EXCEPTION (BAD_ERRIBF);
      if (bad_has_property_attchain (&ideal->attrib, bad_autoreduced_property))
        {
/*
 * If ideal holds the autoreduced property, set K->assume_reduced 
 */
          if (K0->assume_reduced)
            K = K0;
          else
            {
              K = bad_new_base_field ();
              bad_set_base_field (K, K0);
              K->assume_reduced = true;
            }
        }
      else
        K = K0;
    }
/*
 * From now on use regular chain A
 */
  if (A0 == (struct bad_regchain *) 0)
    A = bad_new_regchain ();
  else
    {
      if (!bad_is_a_compatible_regchain (A0, &ideal->attrib))
        BA0_RAISE_EXCEPTION (BAD_ERRIAC);
      A = A0;
    }
/*
 * tabP and tabTL are used by bad_gcd_mod_quadruple
 */
  ba0_init_table ((struct ba0_table *) &tabP);
  ba0_realloc2_table ((struct ba0_table *) &tabP, 1, (ba0_new_function *) & bap_new_polynom_mpz);
  ba0_init_table ((struct ba0_table *) &tabTL);
  ba0_realloc2_table ((struct ba0_table *) &tabTL, 1, (ba0_new_function *) & ba0_new_table);
/*
 * ineqs and factored_ineqs are used when some simplification (factorization) of some inequation is discovered
 */
  ba0_init_table ((struct ba0_table *) &ineqs);
  ba0_init_table ((struct ba0_table *) &factored_ineqs);
/*
 * The new equation as a polynomial / product
 */
  p = bap_new_polynom_mpz ();
  bap_init_product_mpz (&prod);
/*
 * The selection strategy is the default one
 */
  strategy = bad_new_selection_strategy ();
/*
 * main initializations
 */
  ba0_init_table ((struct ba0_table *) &tabG);
/*
 * From now on, use tree, which is supposed to belong to the same stack as ideal
 */
  if (T == (struct bad_splitting_tree *) 0)
    tree = bad_new_splitting_tree ();
  else
    tree = T;
/*
 * The bad_first_quadruple function stores P and S in the components P and S of quadruples and stores them in tabG
 * The base field defining equations are removed from P
 */
  bad_first_quadruple (&tabG, &discarded_branch, tree, &ideal->attrib, P, S, type_red, K, A);

  ba0_pull_stack ();
/*
 * All quadruples generated by bad_first_quadruple are first quadruples
 */
  for (i = tabG.size - 1; i >= 0; i--)
    {
      ba0_int_p father = 0;     // the root vertex number
      ba0_int_p child = bad_get_number_quadruple (tabG.tab[i]);
      if (child == BAD_NOT_A_NUMBER || child == father)
        BA0_RAISE_EXCEPTION (BA0_ERRALG);
      bad_set_first_vertex_splitting_tree (tree, child, true);
      bad_add_edge_novar_splitting_tree (tree, bad_zero_nonzero_first_edge, father, child);
    }

  if (tree->activity == bad_verbose_splitting_tree)
    ba0_printf ("Number of first quadruples : %d\n", tabG.size);

  ba0_push_another_stack ();
/*
 * thetas, leaders, tabL are used by the splitting tree
 */
  if (tree->activity != bad_inactive_splitting_tree)
    {
      thetas = (struct bav_tableof_term *) ba0_new_table ();
      leaders = (struct bav_tableof_variable *) ba0_new_table ();
    }
  else
    {
      thetas = (struct bav_tableof_term *) 0;
      leaders = (struct bav_tableof_variable *) 0;
    }
/*
 * tabL is initialized anyway
 */
  tabL1 = (struct bav_tableof_variable *) ba0_new_table ();
  tabL2 = (struct bav_tableof_variable *) ba0_new_table ();
/*
 * MAIN LOOP
 *
 * Stop if there is not any quadruple to process anymore or if the splitting control variable tells us to do so
 */
  counter = 0;
  while (tabG.size > 0 && (!control->first_leaf_only || ideal->inter.size == 0))
    {
      struct bad_quadruple *G = tabG.tab[tabG.size - 1];
      ba0_int_p father = bad_get_number_quadruple (G);

      counter += 1;

      if (tree->activity == bad_verbose_splitting_tree)
        {
          ba0_printf ("------------------------------------------------\n");
          ba0_printf ("Round %d, |tabG| = %d\n", counter, tabG.size);
          ba0_printf ("Handling quadruple %d\n", father);
          ba0_printf ("%quadruple\n", G);
        }
      if (bad_is_first_vertex_splitting_tree (tree, bad_get_number_quadruple (G)))
        {
/*
 * use_dimlb and numberof_input_equations get new values each time a first quadruple is processed
 */
          bool differential = bad_defines_a_differential_ideal_attchain (&ideal->attrib);
          use_dimlb = bad_apply_dimension_lower_bound_splitting_control (control, A, G->P, K,
              differential, &numberof_input_equations);
        }
/*
 * The dimension lower bound can be applied to reject quadruples
 */
      if (use_dimlb && bad_codimension_regchain (&G->A, K) > numberof_input_equations)
        {
          if (tree->activity == bad_verbose_splitting_tree)
            ba0_printf ("Rejecting quadruple %d (dimension argument)\n", father);
          bad_set_vertex_consistency_splitting_tree (tree, father, bad_rejected_vertex, bad_none_argument);
          tabG.size -= 1;
        }
/*
 * A regular system has been obtained
 */
      else if (bad_is_a_listof_rejected_critical_pair (G->D) && G->P == (struct bap_listof_polynom_mpz *) 0)
        {
          ba0_int_p i, c = ideal->inter.size;
/*
 * The purely algebraic treatment. G is pulled out of the stack
 * The reg_characteristic algorithm transforms it as finitely many regchains which are stacked over ideal
 */
          if (tree->activity == bad_verbose_splitting_tree)
            ba0_printf ("Calling reg_characteristic on quadruple %d\n", father);

          tabG.size -= 1;

          ba0_pull_stack ();

          bad_reg_characteristic_quadruple (ideal, G, (struct bad_regchain *) 0, K);

          if (tree->activity == bad_verbose_splitting_tree)
            ba0_printf ("|ideal| = %d\n", ideal->inter.size);

          if (c == ideal->inter.size)
            bad_set_vertex_consistency_splitting_tree (tree, father, bad_inconsistent_vertex,
                bad_reg_characteric_argument);
          else
            {
              for (i = c; i < ideal->inter.size; i++)
                {
                  ba0_int_p child = bad_next_number_splitting_tree (tree);
                  bad_set_number_regchain (ideal->inter.tab[i], child);
                  bad_add_edge_novar_splitting_tree (tree, bad_reg_characteristic_edge, father, child);
                  bad_set_vertex_consistency_splitting_tree (tree, child, bad_consistent_vertex, bad_none_argument);
                }
            }

          ba0_push_another_stack ();
        }
/*
 * A new equation p = 0 needs be processed
 */
      else
        {
          struct bad_critical_pair *pair;
          bool reduced_to_zero_by_A;

          bad_pick_and_remove_quadruple (p, G, &pair, strategy);

          if (tree->activity != bad_inactive_splitting_tree && pair != (struct bad_critical_pair *) 0)
            {
              struct bav_variable *v, *w;
              ba0_int_p child = bad_next_number_splitting_tree (tree);

              bad_thetas_and_leaders_critical_pair (thetas, leaders, pair);

              ba0_pull_stack ();

              bad_set_number_quadruple (G, child);

              if (!bap_is_numeric_polynom_mpz (p) && bad_is_a_reduction_critical_pair (pair, &v))
                {
                  w = bap_leader_polynom_mpz (p);
                  bad_add_edge_splitting_tree (tree, bad_critical_pair_edge, father, v, child, w);
                }
              else
                bad_add_edge_novar_splitting_tree (tree, bad_critical_pair_novar_edge, father, child);

              bad_merge_thetas_leaders_vertex_splitting_tree (tree, father, thetas, leaders);

              ba0_push_another_stack ();
              father = bad_get_number_quadruple (G);

              if (tree->activity == bad_verbose_splitting_tree)
                ba0_printf ("Current quadruple is now Quadruple %d\n", father);
            }

          if (tree->activity == bad_verbose_splitting_tree)
            ba0_printf ("New equation from quadruple %d: %Az\n", father, p);
/*
 * If the reduction to zero test is probabilistic, apply it before the actual reduction
 */
          if (bad_initialized_global.reduction.redzero_strategy == bad_probabilistic_redzero_strategy &&
              bad_is_a_reduced_to_zero_polynom_by_regchain (p, &G->A, type_red))
            {
              ba0_int_p child = bad_next_number_splitting_tree (tree);
/*
 * Beware: the splitting tree is not correctly updated if we enter here
 */
              if (tree->activity == bad_verbose_splitting_tree)
                ba0_printf ("New equation is reduced to zero\n");

              ba0_pull_stack ();

              bad_set_number_quadruple (G, child);
              bad_add_edge_novar_splitting_tree (tree, bad_redzero_edge, father, child);

              ba0_push_another_stack ();
              father = bad_get_number_quadruple (G);

              reduced_to_zero_by_A = true;
              bad_global.stats.reductions_to_zero += 1;
            }
          else
            reduced_to_zero_by_A = false;
/*
 * reduced_to_zero_by_A may be set to false with p equal to zero (case of a critical pair whose delta-poly is zero)
 *
 * If reduced_to_zero_by_A is false, reduce the new equation p
 */
          if (!reduced_to_zero_by_A)
            {
              bad_reduce_polynom_by_regchain (&prod, (struct bap_product_mpz *) 0, thetas, p,
                  &G->A, type_red, bad_all_derivatives_to_reduce);

              if (tree->activity != bad_inactive_splitting_tree)
                {
                  bad_leaders_of_regchain (leaders, &G->A);
                  ba0_pull_stack ();
                  bad_merge_thetas_leaders_vertex_splitting_tree (tree, father, thetas, leaders);
                  ba0_push_another_stack ();
                }
/*
 * The new equation p = 0 has now become a product prod = 0
 */
              if (bap_is_zero_product_mpz (&prod))
                {
                  ba0_int_p child = bad_next_number_splitting_tree (tree);

                  if (tree->activity == bad_verbose_splitting_tree)
                    ba0_printf ("New equation is reduced to zero\n");

                  ba0_pull_stack ();

                  bad_set_number_quadruple (G, child);
                  bad_add_edge_novar_splitting_tree (tree, bad_redzero_edge, father, child);

                  ba0_push_another_stack ();
                  father = bad_get_number_quadruple (G);

                  reduced_to_zero_by_A = true;
                  bad_global.stats.reductions_to_zero += 1;
                }
            }
/*
 * The new equation is now reduced. The result is in the product prod
 */
          if (!reduced_to_zero_by_A)
            {
/*
 * The factors in prod may lead to simplifications in the inequations of all quadruples
 * The factors which belong to the base field are removed
 */
              bad_preprocess_equation_quadruple (&prod, &ineqs, &factored_ineqs, &discarded_branch, G, K);

              if (discarded_branch && tree->activity != bad_inactive_splitting_tree)
                {
                  ba0_pull_stack ();
                  bad_set_discarded_branch_splitting_tree (tree, father, discarded_branch);
                  ba0_push_another_stack ();
                }

              bad_report_simplification_of_inequations_quadruple (&tabG, &ineqs, &factored_ineqs);

              if (tree->activity == bad_verbose_splitting_tree)
                ba0_printf ("new equation after reduction: %Pz\n", &prod);
/*
 * If the new equation is a constant, reject the quadruple
 */
              if (prod.size == 0)
                {
                  if (tree->activity == bad_verbose_splitting_tree)
                    ba0_printf ("Rejecting inconsistent quadruple %d\n", father);
                  bad_set_vertex_consistency_splitting_tree (tree, father, bad_inconsistent_vertex,
                      bad_nonzero_base_field_equation_argument);
                  tabG.size -= 1;
                }
/*
 * The new equation involves at least one nontrivial factor
 */
              else
                {
                  struct bav_variable *v;
                  ba0_int_p k;
/*
 * Assume prod is f1 ... fn = 0
 * The bad_split_on_factors_of_equations_quadruple function performs:
 * 	for i = 1 to n-1 do
 * 	    H = G, "fi = 0"
 * 	    G = G, "fi != 0"
 * 	done
 * So that, afterwards, G involves f1 <> 0, ..., f{n-1} <> 0 and we only have to deal with the case fn = 0
 */
                  {
                    ba0_int_p i, g = tabG.size - 1;
/*
 * This case distinction is only meant to avoid vertices with a single zero_nonzero edge
 */
                    if (prod.size > 1)
                      {
                        v = bap_leader_product_mpz (&prod);

                        prod.size -= 1;
                        bad_split_on_factors_of_equations_quadruple (&tabG, tabL1, (struct bav_tableof_variable *) 0,
                            tree, &prod, (struct bap_product_mpz *) 0, true);
                        prod.size += 1;

                        ba0_pull_stack ();

                        tabL1->tab[tabL1->size] = bap_leader_polynom_mpz (&prod.tab[prod.size - 1].factor);
                        tabL1->size += 1;

                        for (i = g; i < tabG.size; i++)
                          {
                            struct bav_variable *w = tabL1->tab[i - g];
                            ba0_int_p child = bad_get_number_quadruple (tabG.tab[i]);
                            bad_add_edge_splitting_tree (tree, bad_zero_nonzero_factor_edge, father, v, child, w);
                          }

                        ba0_push_another_stack ();
                        father = bad_get_number_quadruple (G);

                        if (tree->activity == bad_verbose_splitting_tree)
                          ba0_printf ("Current quadruple is now Quadruple %d\n", father);
                      }
                  }
/*
 * The last case to be processed is the vanishing of the last factor of prod which is now in p
 */
                  BA0_SWAP (struct bap_polynom_mpz,
                      *p,
                      prod.tab[prod.size - 1].factor);

                  v = bap_leader_polynom_mpz (p);
/*
 * Splittings on the separant and the initial of p
 */
                  {
/*
 * Split cases by considering the possible vanishing of the separant
 */
                    if (bad_has_property_regchain (&G->A, bad_squarefree_property))
                      {
                        ba0_int_p i, g = tabG.size - 1;

                        bad_split_on_separant_quadruple (&tabG, tabL1, tabL2, &discarded_branch, tree, p, K);

                        if (discarded_branch && tree->activity != bad_inactive_splitting_tree)
                          {
                            ba0_pull_stack ();
                            bad_set_discarded_branch_splitting_tree (tree, father, discarded_branch);
                            ba0_push_another_stack ();
                          }

                        ba0_pull_stack ();

                        for (i = g; i < tabG.size; i++)
                          {
                            ba0_int_p child = bad_get_number_quadruple (tabG.tab[i]);
                            if (i < tabG.size - 1)
                              {
                                struct bav_variable *w1 = tabL1->tab[i - g];
                                struct bav_variable *w2 = tabL2->tab[i - g];
                                bad_add_edge_splitting_tree (tree, bad_zero_nonzero_separant_edge, father, v, child,
                                    w1);
                                bad_add_edge_splitting_tree (tree, bad_zero_nonzero_separant_edge, father, v, child,
                                    w2);
                              }
                            else
                              bad_add_edge_splitting_tree (tree, bad_zero_nonzero_separant_edge, father, v, child, v);
                          }

                        ba0_push_another_stack ();
                        father = bad_get_number_quadruple (G);
                      }
/*
 * Split cases by considering the possible vanishing of the initial (but separant nonzero)
 */
                    if (!bad_has_property_regchain (&G->A, bad_squarefree_property) ||
                        bap_leading_degree_polynom_mpz (p) > 1)
                      {
                        ba0_int_p i, g = tabG.size - 1;

                        bad_split_on_initial_quadruple (&tabG, tabL1, tabL2, &discarded_branch, tree, p, K);

                        if (discarded_branch && tree->activity != bad_inactive_splitting_tree)
                          {
                            ba0_pull_stack ();
                            bad_set_discarded_branch_splitting_tree (tree, father, discarded_branch);
                            ba0_push_another_stack ();
                          }

                        ba0_pull_stack ();
/*
 * Including G in which the separant is zero
 */
                        for (i = g; i < tabG.size; i++)
                          {
                            ba0_int_p child = bad_get_number_quadruple (tabG.tab[i]);
                            if (i < tabG.size - 1)
                              {
                                struct bav_variable *w1 = tabL1->tab[i - g];
                                struct bav_variable *w2 = tabL2->tab[i - g];
                                bad_add_edge_splitting_tree (tree, bad_zero_nonzero_initial_edge, father, v, child, w1);
                                bad_add_edge_splitting_tree (tree, bad_zero_nonzero_initial_edge, father, v, child, w2);
                              }
                            else
                              bad_add_edge_splitting_tree (tree, bad_zero_nonzero_initial_edge, father, v, child, v);
                          }

                        ba0_push_another_stack ();
                        father = bad_get_number_quadruple (G);
                      }

                    if (tree->activity == bad_verbose_splitting_tree)
                      ba0_printf ("Current quadruple is now Quadruple %d\n", father);
                  }
/*
 * Process the irreducible equation p = 0, with leader v, (initial and separant nonzero)
 * Insert p in G->A
 */
                  if (!bad_is_leader_of_regchain (v, &G->A, &k))
                    {
                      ba0_int_p i, g = tabG.size - 1;
                      struct bav_rank rg = bap_rank_polynom_mpz (p);

                      bad_complete_quadruple (&tabG, thetas, &discarded_branch, tree, p, (struct bad_regchain *) 0, K,
                          strategy);

                      if (discarded_branch && tree->activity != bad_inactive_splitting_tree)
                        {
                          ba0_pull_stack ();
                          bad_set_discarded_branch_splitting_tree (tree, father, discarded_branch);
                          ba0_push_another_stack ();
                        }

                      if (tree->activity != bad_inactive_splitting_tree)
                        {
                          bad_leaders_of_regchain (leaders, &G->A);
                          ba0_pull_stack ();
                          bad_merge_thetas_leaders_vertex_splitting_tree (tree, father, thetas, leaders);
                          ba0_push_another_stack ();
                        }

                      ba0_pull_stack ();

                      if (g == tabG.size)
                        {
/*
 * bad_complete_quadruple has concluded that G is inconsistent
 */
                          if (tree->activity == bad_verbose_splitting_tree)
                            ba0_printf ("quadruple %d removed by bad_complete_quadruple\n", father);
                          bad_set_vertex_consistency_splitting_tree (tree, father, bad_inconsistent_vertex,
                              bad_complete_argument);
                        }
                      else
                        {
/*
 * bad_complete_quadruple has generated at least one quadruple
 */
                          for (i = g; i < tabG.size; i++)
                            {
                              ba0_int_p child = bad_get_number_quadruple (tabG.tab[i]);
                              bad_add_edge_novar_splitting_tree (tree, bad_regularize_edge, father, child);
                            }
                        }

                      ba0_push_another_stack ();
                    }
/*
 * p has the same leader as G->A[k] - gcd computations
 */
                  else
                    {
                      struct bap_polynom_mpz *q;
                      ba0_int_p i, g = tabG.size - 1;
/*
 * The bad_gcd_mod_quadruple function transforms G as finitely many 
 * quadruples G1, ..., Gn overwriting G at the top of tabG
 * It computes also the corresponding gcds g1, ..., gn of p and
 * G->A.decision_system.tab [k] which overwrite the top element of tabV.
 *
 * complete (Gi, gi) is performed afterwards for i = 1 ... n.
 */
                      q = G->A.decision_system.tab[k];
                      if (tree->activity == bad_verbose_splitting_tree)
                        ba0_printf ("\ncomputing gcd (%Az, %Az) mod quadruple %d\n", q, p, father);

                      tabP.size = 1;
                      tabTL.size = 1;
                      ba0_reset_table ((struct ba0_table *) tabTL.tab[0]);

                      bad_gcd_mod_quadruple (&tabP, &tabG, &tabTL, &discarded_branch, tree, q, p, v, K);

                      if (discarded_branch && tree->activity != bad_inactive_splitting_tree)
                        {
                          ba0_pull_stack ();
                          bad_set_discarded_branch_splitting_tree (tree, father, discarded_branch);
                          ba0_push_another_stack ();
                        }

                      ba0_pull_stack ();

                      for (i = 0; i < tabP.size; i++)
                        {
                          struct bav_tableof_variable *L;
                          ba0_int_p j, child;

                          child = bad_get_number_quadruple (tabG.tab[i + g]);
                          bad_add_edge_splitting_tree (tree, bad_zero_nonzero_gcd_edge, father, v, child, v);

                          L = tabTL.tab[i];
                          for (j = 0; j < L->size; j++)
                            bad_add_edge_splitting_tree (tree, bad_zero_nonzero_gcd_edge, father, v, child, L->tab[j]);

                          if (tree->activity == bad_verbose_splitting_tree)
                            ba0_printf ("gcd = %Az mod quadruple %d\n", tabP.tab[i], child);
                        }

                      ba0_push_another_stack ();
/*
 * Finitely many gcd have been computed. In each case, these gcd may replace G->A[k]
 */
                      for (i = tabP.size - 1; i >= 0; i--)
                        {
                          struct bav_rank rg = bap_rank_polynom_mpz (tabP.tab[i]);
                          ba0_int_p j, h;
/*
 * At each loop the quadruple to be moved at the tail of the table is located in tabG[g] !
 */
                          ba0_move_to_tail_table ((struct ba0_table *) &tabG, (struct ba0_table *) &tabG, i + g);

                          h = tabG.size - 1;
                          father = bad_get_number_quadruple (tabG.tab[h]);

                          bad_complete_quadruple (&tabG, thetas, &discarded_branch, tree, tabP.tab[i],
                              (struct bad_regchain *) 0, K, strategy);

                          if (discarded_branch && tree->activity != bad_inactive_splitting_tree)
                            {
                              ba0_int_p father = bad_get_number_quadruple (G);
                              ba0_pull_stack ();
                              bad_set_discarded_branch_splitting_tree (tree, father, discarded_branch);
                              ba0_push_another_stack ();
                            }

                          if (tree->activity != bad_inactive_splitting_tree)
                            {
                              ba0_int_p father = bad_get_number_quadruple (G);
                              bad_leaders_of_regchain (leaders, &G->A);
                              ba0_pull_stack ();
                              bad_merge_thetas_leaders_vertex_splitting_tree (tree, father, thetas, leaders);
                              ba0_push_another_stack ();
                            }

                          ba0_pull_stack ();

                          for (j = h; j < tabG.size; j++)
                            {
                              ba0_int_p child = bad_get_number_quadruple (tabG.tab[j]);
                              bad_add_edge_novar_splitting_tree (tree, bad_regularize_edge, father, child);
                            }

                          ba0_push_another_stack ();
                        }
/*
 * Eventually ...
 */
                      if (g == tabG.size)
                        {
/*
 * bad_complete_quadruple has concluded that G is inconsistent for all gcds
 */
                          if (tree->activity == bad_verbose_splitting_tree)
                            ba0_printf ("quadruple %d removed by bad_complete_quadruple\n", father);
                          bad_set_vertex_consistency_splitting_tree (tree, father, bad_inconsistent_vertex,
                              bad_gcd_complete_argument);
                        }

                    }
                }
            }
        }
    }
/*
 * End of MAIN LOOP
 */
  ba0_pull_stack ();
/*
 * All explicit regchains get the prime attribute
 */
  bad_fast_primality_test_intersectof_regchain (ideal);
  ba0_restore (&M);
  bad_global.stats.end = time (0);
}

/*
 * texinfo: bad_split_on_separant_quadruple
 * Generate in @var{tabG} the quadruples obtained from the top quadruple
 * @var{G} of @var{tabG} considering the vanishing of the separant of @var{p}.
 * Eventually, @var{G} itself appears at the top of the resulting @var{tabG}.
 *
 * Store moreover the leaders of the factors of
 * the separant in @var{tabL1} in such a way that, denoting @var{g} the index 
 * of @var{G} when the function is called, the leader of the factor of the separant
 * corresponding to @var{tabG->tab[h]} is stored
 * in @var{tabL1->tab[h-g]} for all @math{g \leq h < @var{tabG->size}}.
 * Store in a similar way the leaders of the factors of the sepuctum in @var{tabL2}.
 * Eventually, @var{tabL1} and @var{tabL2} have the same size but the entries
 * of @var{tabL2} are equal to @code{BAV_NOT_A_VARIABLE} if the sepuctum is zero.
 *
 * The argument @var{discarded_branch} is set to @code{true} if at least one
 * branch has been discarded because the corresponding factor is incompatible
 * with the inequations.
 *
 * The argument @var{tree} is only used to assign @emph{numbers} to all the
 * generated quadruples. A quadruple covering a case @math{p = 0} has a lower
 * number than any quadruple containing the inequation @math{p \neq 0}.
 */

BAD_DLL void
bad_split_on_separant_quadruple (
    struct bad_tableof_quadruple *tabG,
    struct bav_tableof_variable *tabL1,
    struct bav_tableof_variable *tabL2,
    bool *discarded_branch,
    struct bad_splitting_tree *tree,
    struct bap_polynom_mpz *p,
    struct bad_base_field *K)
{
  struct bad_quadruple *G;
  struct bap_tableof_product_mpz factored_ineqs;
  struct bap_tableof_polynom_mpz ineqs;
  struct bap_product_mpz prod_sep, prod_sepuctum;
  struct bap_polynom_mpz sep, sepuctum;
  struct ba0_mark M;
  ba0_int_p g;
  bool constant_separant, or_discarded, discarded;
/*
 * or_discarded detects if some branch has been discarded at some point
 */
  or_discarded = false;

  g = tabG->size - 1;
  G = tabG->tab[g];

  ba0_push_another_stack ();
  ba0_record (&M);
/*
 * To manage exhibited factorizations of inequations
 */
  ba0_init_table ((struct ba0_table *) &ineqs);
  ba0_init_table ((struct ba0_table *) &factored_ineqs);

  bap_init_polynom_mpz (&sep);
  bap_init_polynom_mpz (&sepuctum);
  bap_separant_and_sepuctum_polynom_mpz (&sep, &sepuctum, p);
/*
 * Discard obviously useless splittings
 */
  constant_separant = bap_leading_degree_polynom_mpz (p) == 1 && bad_member_nonzero_polynom_base_field (&sep, K);

  if (!constant_separant && !bad_member_nonzero_polynom_base_field (&sepuctum, K))
    {
      bap_init_product_mpz (&prod_sep);
      bap_init_product_mpz (&prod_sepuctum);

      baz_factor_easy_polynom_mpz (&prod_sep, &sep, G->S);
      bad_preprocess_equation_quadruple (&prod_sep, &ineqs, &factored_ineqs, &discarded, G, K);
      or_discarded = or_discarded || discarded;
      if (ineqs.size > 0)
        {
          ba0_pull_stack ();
          bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
          ba0_push_another_stack ();
        }
      if (prod_sep.size > 0)
        {
          baz_factor_easy_polynom_mpz (&prod_sepuctum, &sepuctum, G->S);
          bad_preprocess_equation_quadruple (&prod_sepuctum, &ineqs, &factored_ineqs, &discarded, G, K);
          or_discarded = or_discarded || discarded;
          if (ineqs.size > 0)
            {
              ba0_pull_stack ();
              bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
              ba0_push_another_stack ();
            }
          if (prod_sepuctum.size > 0 || bap_is_zero_product_mpz (&prod_sepuctum))
            {
              ba0_pull_stack ();
              bad_split_on_factors_of_equations_quadruple (tabG, tabL1, tabL2, tree, &prod_sep, &prod_sepuctum, false);
              ba0_push_another_stack ();
            }
        }
    }
  else
    or_discarded = false;
/*
 * the last quadruple was not assigned any number by bad_split_on_factors_of_equations_quadruple
 */
  bad_set_next_number_quadruple (G, tree);

  ba0_pull_stack ();
  ba0_restore (&M);

  if (discarded_branch)
    *discarded_branch = or_discarded;
}

/*
 * texinfo: bad_split_on_initial_quadruple
 * Generate in @var{tabG} the quadruples obtained from the top quadruple
 * @var{G} of @var{tabG} considering the vanishing of the initial of @var{p}.
 * Eventually, @var{G} itself appears at the top of the resulting @var{tabG}.
 *
 * Store moreover the leaders of the factors of
 * the initial in @var{tabL1} in such a way that, denoting @var{g} the index 
 * of @var{G} when the function is called, the leader of the factor of the initial
 * corresponding to @var{tabG->tab[h]} is stored
 * in @var{tabL1->tab[h-g]} for all @math{g \leq h < @var{tabG->size}}.
 * Store in a similar way the leaders of the factors of the reductum in @var{tabL2}.
 * Eventually, @var{tabL1} and @var{tabL2} have the same size but the entries
 * of @var{tabL2} are equal to @code{BAV_NOT_A_VARIABLE} if the reductum is zero.
 *
 * The argument @var{discarded_branch} is set to @code{true} if at least one
 * branch has been discarded because the corresponding factor is incompatible
 * with the inequations.
 *
 * The argument @var{tree} is only used to assign @emph{numbers} to all the
 * generated quadruples. A quadruple covering a case @math{p = 0} has a lower
 * number than any quadruple containing the inequation @math{p \neq 0}.
 */

BAD_DLL void
bad_split_on_initial_quadruple (
    struct bad_tableof_quadruple *tabG,
    struct bav_tableof_variable *tabL1,
    struct bav_tableof_variable *tabL2,
    bool *discarded_branch,
    struct bad_splitting_tree *tree,
    struct bap_polynom_mpz *p,
    struct bad_base_field *K)
{
  struct bad_quadruple *G;
  struct bap_tableof_product_mpz factored_ineqs;
  struct bap_tableof_polynom_mpz ineqs;
  struct bap_product_mpz prod_init, prod_reductum;
  struct bap_polynom_mpz init, reductum;
  struct ba0_mark M;
  ba0_int_p g;
  bool constant_initial, or_discarded, discarded;
/*
 * or_discarded detects if some branch has been discarded at some point
 */
  or_discarded = false;

  g = tabG->size - 1;
  G = tabG->tab[g];

  ba0_push_another_stack ();
  ba0_record (&M);
/*
 * To manage exhibited factorizations of inequations
 */
  ba0_init_table ((struct ba0_table *) &ineqs);
  ba0_init_table ((struct ba0_table *) &factored_ineqs);
/*
 * First the initial
 */
  bap_init_readonly_polynom_mpz (&init);
  bap_init_readonly_polynom_mpz (&reductum);
  bap_initial_and_reductum_polynom_mpz (&init, &reductum, p);

  bap_init_product_mpz (&prod_init);
  bap_init_product_mpz (&prod_reductum);
/*
 * Discard obviously useless splittings
 */
  constant_initial = bad_member_nonzero_polynom_base_field (&init, K);

  if (!constant_initial && !bad_member_nonzero_polynom_base_field (&reductum, K))
    {
      baz_factor_easy_polynom_mpz (&prod_init, &init, G->S);
      bad_preprocess_equation_quadruple (&prod_init, &ineqs, &factored_ineqs, &discarded, G, K);
      or_discarded = or_discarded || discarded;
      if (ineqs.size > 0)
        {
          ba0_pull_stack ();
          bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
          ba0_push_another_stack ();
        }
      if (prod_init.size > 0)
        {
/*
 * The initial is never identically zero but the reductum can be identically zero.
 */
          baz_factor_easy_polynom_mpz (&prod_reductum, &reductum, G->S);
          bad_preprocess_equation_quadruple (&prod_reductum, &ineqs, &factored_ineqs, &discarded, G, K);
          or_discarded = or_discarded || discarded;
          if (ineqs.size > 0)
            {
              ba0_pull_stack ();
              bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
              ba0_push_another_stack ();
            }
          if (prod_reductum.size > 0 || bap_is_zero_product_mpz (&prod_reductum))
            {
              ba0_pull_stack ();
              bad_split_on_factors_of_equations_quadruple (tabG, tabL1, tabL2, tree, &prod_init, &prod_reductum, false);
              ba0_push_another_stack ();
            }
        }
    }
  else
    or_discarded = false;
/*
 * the last quadruple was not assigned any number by bad_split_on_factors_of_equations_quadruple
 */
  bad_set_next_number_quadruple (G, tree);

  ba0_pull_stack ();
  ba0_restore (&M);

  if (discarded_branch)
    *discarded_branch = or_discarded;
}

/*
 * texinfo: bad_first_quadruple
 * Initialize the field @code{A} of the first quadruple of @var{tabG} with the 
 * defining equations of @var{K}, extended with the polynomials of @var{A}.
 * Initialize the field @code{P} with @var{P}.
 * Initialize the field @code{S} with @var{S} and the initials of @var{A} 
 * (plus the separants if @var{attrib} holds the squarefree property).
 * The process may lead to splittings (there may be many different
 * first quadruples).
 *
 * The argument @var{tree} is only used to assign @emph{numbers} to all the
 * generated quadruples. A quadruple covering a case @math{p = 0} has a lower
 * number than any quadruple containing the inequation @math{p \neq 0}.
 */

BAD_DLL void
bad_first_quadruple (
    struct bad_tableof_quadruple *tabG,
    bool *discarded_branch,
    struct bad_splitting_tree *tree,
    struct bad_attchain *attrib,
    struct bap_tableof_polynom_mpz *P,
    struct bap_tableof_polynom_mpz *S,
    enum bad_typeof_reduction type_red,
    struct bad_base_field *K,
    struct bad_regchain *A)
{
  struct bad_quadruple *G;
  struct bap_tableof_polynom_mpz ineqs;
  struct bap_tableof_product_mpz factored_ineqs;
  struct bap_product_mpz prod;
  struct ba0_mark M;
  ba0_int_p i, j, k;
  bool base_field;
  bool or_discarded, discarded;

  or_discarded = false;

  if (tabG->size != 0)
    BA0_RAISE_EXCEPTION (BA0_ERRALG);

  ba0_realloc2_table ((struct ba0_table *) tabG, 1, (ba0_new_function *) bad_new_quadruple);
  G = tabG->tab[0];
  tabG->size = 1;
/*
 * The relations of K are directly stored in G->A.
 * Overwrite the attributes of K->relations.attrib with attrib.
 */
  base_field = K != (struct bad_base_field *) 0;
  if (base_field)
    bad_set_regchain (&G->A, &K->relations);
/*
 * Append the polynomials of A to G->A
 * Insert in G->S the initials (and separants) of A
 * Setting G->A.attrib is necessary to have the squarefree property correctly set
 */
  bad_set_attchain (&G->A.attrib, attrib);
  if (A != (struct bad_regchain *) 0)
    bad_extend_quadruple_regchain (G, A, K);
/*
 * Do it again because the above call may have erased G->A.attrib
 */
  bad_set_attchain (&G->A.attrib, attrib);

  ba0_push_another_stack ();
  ba0_record (&M);

  ba0_init_table ((struct ba0_table *) &ineqs);
  ba0_init_table ((struct ba0_table *) &factored_ineqs);
  bap_init_product_mpz (&prod);
/*
 * First process the inequations.
 * No splitting occurs since "p*q != 0" is just "p != 0", "q != 0".
 * However, the quadruple G may be proved inconsistent and discarded.
 */
  if (S)
    {
      for (i = 0; i < S->size && tabG->size > 0; i++)
        {
/*
 * An inequation might be reduced to zero by a base field equation
 * factor_easy does not expect zero polynomials.
 */
          if (base_field)
            bad_reduce_polynom_by_regchain (&prod, (struct bap_product_mpz *) 0,
                (struct bav_tableof_term *) 0, S->tab[i], &G->A, type_red, bad_all_derivatives_to_reduce);
          else if (bap_is_numeric_polynom_mpz (S->tab[i]))
            bap_set_product_polynom_mpz (&prod, S->tab[i], 1);
          else
            baz_factor_easy_polynom_mpz (&prod, S->tab[i], G->S);
/*
 * In the case "0 != 0", remove the quadruple G from the stack.
 */
          if (bap_is_zero_product_mpz (&prod))
            tabG->size -= 1;
          else
            {
              bad_preprocess_equation_quadruple (&prod, &ineqs, &factored_ineqs, &discarded, G, K);
              or_discarded = or_discarded || discarded;
              ba0_pull_stack ();
              bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
              for (j = 0; j < prod.size; j++)
                G->S = bad_insert_in_listof_polynom_mpz (&prod.tab[j].factor, G->S);
              ba0_push_another_stack ();
            }
        }
    }
/*
 * Then process the equations
 * Splittings can occur, since "p*q = 0" is "p = 0" or "q = 0, p != 0" 
 */
  if (tabG->size > 0)
    {
      for (i = 0; i < P->size; i++)
        {
/*
 * Loop invariant: quadruples in tabG->tab [k+1 .. tabG->size-1]
 *                 have already received the new equation P->tab[i]
 */
          for (k = tabG->size - 1; k >= 0; k--)
            {
/*
 * The kth quadruple is moved at the tail of tabG
 * This simplifies the management of splittings
 */
              ba0_move_to_tail_table ((struct ba0_table *) tabG, (struct ba0_table *) tabG, k);
              G = tabG->tab[tabG->size - 1];
              if (base_field)
                bad_reduce_polynom_by_regchain (&prod, (struct bap_product_mpz *) 0,
                    (struct bav_tableof_term *) 0, P->tab[i], &G->A, type_red, bad_all_derivatives_to_reduce);
              else if (bap_is_numeric_polynom_mpz (P->tab[i]))
                bap_set_product_polynom_mpz (&prod, P->tab[i], 1);
              else
                baz_factor_easy_polynom_mpz (&prod, P->tab[i], G->S);

              if (bap_is_numeric_product_mpz (&prod))
                {
/*
 * The top quadruple is discarded
 */
                  if (!bap_is_zero_product_mpz (&prod))
                    tabG->size -= 1;
                }
              else
                {
                  bad_preprocess_equation_quadruple (&prod, &ineqs, &factored_ineqs, &discarded, G, K);
                  or_discarded = or_discarded || discarded;

                  ba0_pull_stack ();
                  bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
                  if (prod.size == 0)
                    {
/*
 * The top quadruple is discarded
 */
                      tabG->size -= 1;
                    }
                  else
                    {
/*
 * Apply bad_split_on_factors_of_equations_quadruple for all factors but the last one
 */
                      prod.size -= 1;
                      bad_split_on_factors_of_equations_quadruple (tabG, (struct bav_tableof_variable *) 0,
                          (struct bav_tableof_variable *) 0, tree, &prod, (struct bap_product_mpz *) 0, false);
/*
 * Store the last factor in G manually and set its number
 * The goal is to avoid generating a quadruple with all factors in S
 */
                      bad_set_next_number_quadruple (G, tree);
                      G->P = bad_insert_in_listof_polynom_mpz (&prod.tab[prod.size].factor, G->P);
                    }
                  ba0_push_another_stack ();
                }
            }
        }
    }

  if (tabG->size == 1)
    {
      ba0_int_p number = bad_get_number_quadruple (G);
/*
 * this may happen if there are no equations
 */
      if (number == BAD_NOT_A_NUMBER)
        bad_set_next_number_quadruple (G, tree);
    }

  ba0_pull_stack ();
  ba0_restore (&M);

  if (discarded_branch)
    *discarded_branch = or_discarded;
}

/*
 * texinfo: bad_gcd_mod_quadruple
 * The polynomial @var{A} has positive degree in @var{v}.
 * The polynomial @var{B} has degree less than @var{A} in @var{v} (possibly zero).
 * Let @var{g} denote the index of the last quadruple @var{G} of @var{tabG}.
 * Compute the gcds of @var{A} and @var{B}, viewed as
 * polynomials in @var{v} with coefficients taken modulo the ideal defined by @var{G}. 
 * These gcd computations lead to new quadruples, which are stored in @var{tabG}
 * at indices starting at @var{g} (so that @var{G} is rewritten)
 * For each new quadruple, a gcd is stored in @var{tabP} so that the @math{i}th
 * entry of @var{tabP} corresponds to the @math{g+i} entry of @var{tabG}.
 * In each new quadruple, some polynomials are assumed to vanish.
 * The leaders of these polynomials are stored in @var{tabTL} so that the @math{i}th
 * entry of @var{tabTL} contains the leaders associated to the @math{g+i} entry of @var{tabG}.
 *
 * The argument @var{discarded_branch} is set to @code{true} if at least one
 * branch has been discarded because the corresponding factor is incompatible
 * with the inequations.
 *
 * The argument @var{tree} is only used to assign @emph{numbers} to all the
 * generated quadruples. A quadruple covering a case @math{p = 0} has a lower
 * number than any quadruple containing the inequation @math{p \neq 0}.
 */

BAD_DLL void
bad_gcd_mod_quadruple (
    struct bap_tableof_polynom_mpz *tabP,
    struct bad_tableof_quadruple *tabG,
    struct bav_tableof_tableof_variable *tabTL,
    bool *discarded_branch,
    struct bad_splitting_tree *tree,
    struct bap_polynom_mpz *A,
    struct bap_polynom_mpz *B,
    struct bav_variable *v,
    struct bad_base_field *K)
{
  struct bad_quadruple *G;
  ba0_int_p g, p, delta;
  bool or_discarded, discarded;

  or_discarded = false;
/*
 * g = the index of G in tabG
 * p = the index in tabP and tabTL corresponding to G
 * delta is used for debugging
 */
  g = tabG->size - 1;
  p = tabP->size - 1;
  delta = g - p;
  G = tabG->tab[g];

  if (bad_get_number_quadruple (G) == BAD_NOT_A_NUMBER)
    BA0_RAISE_EXCEPTION (BA0_ERRALG);

  if (bap_is_zero_polynom_mpz (B))
    {
/*
 * If B is zero, the gcd is A
 */
      bad_set_next_number_quadruple (G, tree);
      bap_set_polynom_mpz (tabP->tab[p], A);
    }
  else if (!bap_depend_polynom_mpz (B, v))
    {
/*
 * if B does not depend on v, then it is stored in P and thus implicitly becomes equal to zero, whence the gcd is A
 */
      struct bav_tableof_variable *L;
      struct bav_variable *u;

      bad_set_next_number_quadruple (G, tree);
      G->P = bad_insert_in_listof_polynom_mpz (B, G->P);

      bap_set_polynom_mpz (tabP->tab[p], A);

      L = tabTL->tab[p];
      u = bap_leader_polynom_mpz (B);
      if (!ba0_member_table (u, (struct ba0_table *) L))
        {
          ba0_realloc_table ((struct ba0_table *) L, L->size + 1);
          L->tab[L->size] = u;
          L->size += 1;
        }
    }
  else
    {
      struct bap_product_mpz prod, prod_init, prod_reductum;
      struct bap_polynom_mpz R, init, reductum;
      struct bap_tableof_product_mpz factored_ineqs;
      struct bap_tableof_polynom_mpz ineqs;
      struct ba0_mark M;

      ba0_push_another_stack ();
      ba0_record (&M);

      bap_init_polynom_mpz (&R);
      bap_init_product_mpz (&prod);
      ba0_init_table ((struct ba0_table *) &ineqs);
      ba0_init_table ((struct ba0_table *) &factored_ineqs);
      bap_init_readonly_polynom_mpz (&init);
      bap_init_readonly_polynom_mpz (&reductum);
      bap_init_product_mpz (&prod_init);
      bap_init_product_mpz (&prod_reductum);
/*
 * R = remainder (A, B, v)
 */
      baz_gcd_prem_polynom_mpz (&R, (struct bap_product_mpz *) 0, A, B, v);
/*
 * Get rid of the two special cases: R = 0 and R cannot vanish.
 */
      if (bap_is_zero_polynom_mpz (&R))
        {
          ba0_pull_stack ();
          bad_gcd_mod_quadruple (tabP, tabG, tabTL, &discarded, tree, B, &R, v, K);
          or_discarded = or_discarded || discarded;
          ba0_push_another_stack ();
        }
      else if (bad_member_nonzero_polynom_base_field (&R, K))
        {
          tabP->size -= 1;
          tabG->size -= 1;
          tabTL->size -= 1;
        }
      else
        {
/*
 * R can vanish. Preprocess it.
 */
          baz_factor_easy_polynom_mpz (&prod, &R, G->S);
          bad_preprocess_equation_quadruple (&prod, &ineqs, &factored_ineqs, &discarded, G, K);
          or_discarded = or_discarded || discarded;
          if (ineqs.size > 0)
            {
              ba0_pull_stack ();
              bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
              ba0_push_another_stack ();
            }
          if (prod.size == 0)
            {
/*
 * This case may happen if prod only involve factors which occur in G->S
 */
              tabP->size -= 1;
              tabG->size -= 1;
              tabTL->size -= 1;
            }
          else
            {
              struct bav_tableof_variable tabL;
              ba0_int_p i;

              ba0_init_table ((struct ba0_table *) &tabL);

              for (i = 0; i < prod.size; i++)
                {
                  struct bad_quadruple *H;
                  struct bap_polynom_mpz *poly;
                  ba0_int_p h, q;

/*
 * For each factor poly of R (index is i)
 */
                  poly = &prod.tab[i].factor;

                  ba0_pull_stack ();
/*
 * H = G
 * G = G + "ith factor of R != 0"
 * except for the last factor, in which case H = G.
 *
 * h = the index of H in tabG
 * q = the index in tabP corresponding to H
 */
                  if (i < prod.size - 1)
                    {
                      ba0_realloc2_table ((struct ba0_table *) tabG, tabG->size + 1,
                          (ba0_new_function *) & bad_new_quadruple);
                      ba0_realloc2_table ((struct ba0_table *) tabP, tabP->size + 1,
                          (ba0_new_function *) & bap_new_polynom_mpz);
                      ba0_realloc2_table ((struct ba0_table *) tabTL, tabTL->size + 1,
                          (ba0_new_function *) & ba0_new_table);
                      tabG->size += 1;
                      tabP->size += 1;
                      tabTL->size += 1;
                      ba0_reset_table ((struct ba0_table *) tabTL->tab[tabTL->size - 1]);
                      h = tabG->size - 1;
                      q = tabP->size - 1;
                      H = tabG->tab[h];
                      bad_set_quadruple (H, G);
                      bad_set_next_number_quadruple (H, tree);
                      bad_insert_in_S_quadruple (G, G, poly);
                    }
                  else
                    {
                      ba0_move_to_tail_table ((struct ba0_table *) tabG, (struct ba0_table *) tabG, g);
                      ba0_move_to_tail_table ((struct ba0_table *) tabP, (struct ba0_table *) tabP, p);
                      ba0_move_to_tail_table ((struct ba0_table *) tabTL, (struct ba0_table *) tabTL, p);
                      g = tabG->size - 1;
                      p = tabP->size - 1;
                      h = tabG->size - 1;
                      q = tabP->size - 1;
                      H = G;
                    }
                  ba0_push_another_stack ();
                  if (!bap_depend_polynom_mpz (poly, v))
                    {
/*
 * If the ith factor of R does not depend on v, suppose it equal to zero and take B for gcd
 * This is achieved by the next recursive call
 */
                      ba0_pull_stack ();
                      bad_gcd_mod_quadruple (tabP, tabG, tabTL, &discarded, tree, B, poly, v, K);
                      or_discarded = or_discarded || discarded;
                      ba0_push_another_stack ();
                    }
                  else
                    {
                      bool init_may_vanish;
/*
 * Take the initial and reductum of the ith factor of R
 * The ith factor of prod should not involve trivial factors so that the reductum should not be zero.
 */
                      bap_initial_and_reductum2_polynom_mpz (&init, &reductum, poly, v);
                      if (bap_is_zero_polynom_mpz (&reductum))
                        BA0_RAISE_EXCEPTION (BA0_ERRALG);
                      init_may_vanish = !bad_member_nonzero_polynom_base_field (&init, K);
                      if (init_may_vanish && !bad_member_nonzero_polynom_base_field (&reductum, K))
                        {
/*
 * If both the initial and the reductum can vanish, generate splittings.
 */
                          baz_factor_easy_polynom_mpz (&prod_init, &init, H->S);
                          bad_preprocess_equation_quadruple (&prod_init, &ineqs, &factored_ineqs, &discarded, H, K);
                          or_discarded = or_discarded || discarded;
                          if (ineqs.size > 0)
                            {
                              ba0_pull_stack ();
                              bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
                              ba0_push_another_stack ();
                            }
                          if (prod_init.size > 0)
                            {
                              baz_factor_easy_polynom_mpz (&prod_reductum, &reductum, H->S);
                              bad_preprocess_equation_quadruple (&prod_reductum, &ineqs, &factored_ineqs, &discarded, H,
                                  K);
                              or_discarded = or_discarded || discarded;
                              if (ineqs.size > 0)
                                {
                                  ba0_pull_stack ();
                                  bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
                                  ba0_push_another_stack ();
                                }
                              if (prod_reductum.size > 0)
                                {
                                  ba0_int_p j, k;

                                  ba0_pull_stack ();
/*
 * If, really, both initial and reductum can vanish, split
 * Observe the (struct bap_product_mpz *)0, which means that the reductum is temporarily assumed identically zero
 */
                                  if (h != tabG->size - 1)
                                    BA0_RAISE_EXCEPTION (BA0_ERRALG);

                                  bad_split_on_factors_of_equations_quadruple (tabG, &tabL,
                                      (struct bav_tableof_variable *) 0, tree, &prod_init,
                                      (struct bap_product_mpz *) 0, false);
/*
 * H was moved on the top of tabG so that h is no more the index of H
 * However h is equal to the former value of tabG->size-1
 */
                                  if (H != tabG->tab[tabG->size - 1])
                                    BA0_RAISE_EXCEPTION (BA0_ERRALG);
/*
 * k = the number of newly allocated quadruples, must be equal to tabL.size
 *     the entries correspond as follows:
 *     tabG:     h    h+1   h+2    ...    h+k-1     h+k
 *     tabL:     0     1     2     ...     k-1
 *     tabTL: size-1 size  size+1  ...  size+k-2  size+k-1
 */
                                  k = tabG->size - (h + 1);
                                  if (k != tabL.size)
                                    BA0_RAISE_EXCEPTION (BA0_ERRALG);

                                  ba0_realloc2_table ((struct ba0_table *) tabP,
                                      tabP->size + k, (ba0_new_function *) & bap_new_polynom_mpz);
                                  tabP->size += k;

                                  ba0_realloc2_table ((struct ba0_table *) tabTL,
                                      tabTL->size + k, (ba0_new_function *) & ba0_new_table);
                                  {
                                    struct bav_tableof_variable *L, *L0 = tabTL->tab[tabTL->size - 1];
/*
 * for all new quadruples Q but the last one 
 *      the table of leaders of Q (i.e. tabTL [size + j]) is equal to the table of leaders of H + tabL [j]
 * for the last quadruple Q (the one in which only inequations have been added)
 *      the table of leaders of Q is equal to the table of leaders of H
 */
                                    L = tabTL->tab[tabTL->size - 1 + k];
                                    ba0_set_table ((struct ba0_table *) L, (struct ba0_table *) L0);

                                    for (j = k - 1; j >= 0; j--)
                                      {
                                        L = tabTL->tab[tabTL->size - 1 + j];
                                        ba0_realloc_table ((struct ba0_table *) L, L0->size + 1);
                                        ba0_set_table ((struct ba0_table *) L, (struct ba0_table *) L0);
                                        if (!ba0_member_table (tabL.tab[j], (struct ba0_table *) L))
                                          {
                                            L->tab[L->size] = tabL.tab[j];
                                            L->size += 1;
                                          }
                                      }
                                  }
                                  tabTL->size += k;
/*
 * For each new quadruple Q (but not the last one) generated by bad_split_on_factors_of_equations_quadruple
 *     for each factor of the reductum, recursive call:
 *          bad_gcd_mod_quadruple (B, the factor of the reductum) over Q
 */
                                  for (j = tabG->size - 2, k = tabP->size - 2; j >= h; j--, k--)
                                    {
                                      ba0_int_p l;

                                      for (l = 0; l < prod_reductum.size; l++)
                                        {
/*
 * I = the new quadruple
 * J = I 
 * I = I + "the lth factor of the reductum != 0"
 * except for the last factor, in which case I = J
 */
                                          if (l < prod_reductum.size - 1)
                                            {
                                              struct bad_quadruple *I, *J;

                                              ba0_realloc2_table ((struct ba0_table *)
                                                  tabG, tabG->size + 1, (ba0_new_function *) & bad_new_quadruple);
                                              ba0_realloc2_table ((struct ba0_table *)
                                                  tabP, tabP->size + 1, (ba0_new_function *) & bap_new_polynom_mpz);
                                              ba0_realloc2_table ((struct ba0_table *)
                                                  tabTL, tabTL->size + 1, (ba0_new_function *) & ba0_new_table);
                                              tabG->size += 1;
                                              tabP->size += 1;
                                              tabTL->size += 1;
                                              I = tabG->tab[j];
                                              J = tabG->tab[tabG->size - 1];
                                              bad_set_quadruple (J, I);
                                              bad_set_next_number_quadruple (J, tree);
                                              ba0_set_table ((struct ba0_table *) tabTL->tab[tabTL->size - 1],
                                                  (struct ba0_table *) tabTL->tab[k]);
                                              bad_insert_in_S_quadruple (I, I, &prod_reductum.tab[l].factor);
                                            }
                                          else
                                            {
                                              ba0_move_to_tail_table ((struct ba0_table *) tabG,
                                                  (struct ba0_table *) tabG, j);
                                              ba0_move_to_tail_table ((struct ba0_table *) tabP,
                                                  (struct ba0_table *) tabP, k);
                                              ba0_move_to_tail_table ((struct ba0_table *) tabTL,
                                                  (struct ba0_table *) tabTL, k);
                                            }
                                          bad_gcd_mod_quadruple (tabP, tabG, tabTL, &discarded, tree, B,
                                              &prod_reductum.tab[l].factor, v, K);
                                          or_discarded = or_discarded || discarded;
                                        }
                                    }
                                  ba0_push_another_stack ();
                                }
                            }
                        }
                      else if (init_may_vanish)
                        {
                          ba0_int_p j;
/*
 * The reductum cannot vanish but the initial, isolated, could
 * To make sure that the gcd is correct, force it not to vanish by inserting in S (but this is not necessary)
 */
                          baz_factor_easy_polynom_mpz (&prod_init, &init, H->S);
                          bad_preprocess_equation_quadruple (&prod_init, &ineqs, &factored_ineqs, &discarded, H, K);
                          or_discarded = or_discarded || discarded;
                          if (ineqs.size > 0)
                            {
                              ba0_pull_stack ();
                              bad_report_simplification_of_inequations_quadruple (tabG, &ineqs, &factored_ineqs);
                              ba0_push_another_stack ();
                            }
                          ba0_pull_stack ();
                          for (j = 0; j < prod_init.size; j++)
                            H->S = bad_insert_in_listof_polynom_mpz (&prod_init.tab[j].factor, H->S);
                          ba0_push_another_stack ();
                        }
                      if (H != tabG->tab[h])
                        BA0_RAISE_EXCEPTION (BA0_ERRALG);
/*
 * We still have the quadruple H (the last one generated by bad_split_on_factors_of_equations_quadruple) to process
 * Over this quadruple H, the initial of the ith factor of R cannot vanish.
 * Recursive call:
 *    bad_gcd_mod_quadruple (B, ith factor of R) over H
 */
                      ba0_pull_stack ();
                      ba0_move_to_tail_table ((struct ba0_table *) tabG, (struct ba0_table *) tabG, h);
                      ba0_move_to_tail_table ((struct ba0_table *) tabP, (struct ba0_table *) tabP, q);
                      ba0_move_to_tail_table ((struct ba0_table *) tabTL, (struct ba0_table *) tabTL, q);
                      bad_gcd_mod_quadruple (tabP, tabG, tabTL, &discarded, tree, B, poly, v, K);
                      or_discarded = or_discarded || discarded;
                      ba0_push_another_stack ();
                    }
                }
            }
        }
      ba0_pull_stack ();
      ba0_restore (&M);
    }
  if (discarded_branch)
    *discarded_branch = or_discarded;
  if (delta != tabG->size - tabP->size)
    BA0_RAISE_EXCEPTION (BA0_ERRALG);
}
