/*
 * Test 1: a divided by b
 * - both a and b are small integers
 */
static void test_small_small(void) {
  rational_t a, b, c;
  int32_t x, y;

  q_init(&a);
  q_init(&b);
  q_init(&c);

  for (y=1; y<8; y++) {
    q_set32(&b, y);
    for (x=-20; x<=20; x++) {
      q_set32(&a, x);
      q_integer_div(&a, &b);
      q_set32(&c, x);
      q_integer_rem(&c, &b);

      printf("div[%3"PRId32", %"PRId32"]: quotient = ", x, y);
      q_print(stdout, &a);
      printf(", remainder = ");
      q_print(stdout, &c);
      printf("\n");
    }
    printf("\n");
  }

  q_clear(&a);
  q_clear(&b);
  q_clear(&c);
}
Exemple #2
0
/*
 * Test1: construct powers of two
 */
static void test1(void) {
  rational_t r, aux;
  uint32_t i;

  printf("\nTest 1\n\n");

  q_init(&r);
  q_init(&aux);
  q_set32(&aux, 2);

  q_set_one(&r);
  for (i=0; i<68; i++) {
    test_conversions(&r);
    q_mul(&r, &aux);
  }

  // negative powers
  q_set_minus_one(&r);
  for (i=0; i<68; i++) {
    test_conversions(&r);
    q_mul(&r, &aux);
  }

  q_clear(&aux);
  q_clear(&r);
}
/*
 * Test 2: a is large, b is small
 */
static void test_big_small(void) {
  rational_t a, b, c;
  uint32_t i;
  int32_t y;

  q_init(&a);
  q_init(&b);
  q_init(&c);

  for (y=1; y<8; y++) {
    q_set32(&b, y);
    for (i=0; i<NBIGS; i++) {
      q_set_from_string(&a, large_signed[i]);
      q_set(&c, &a);
      q_integer_div(&a, &b);
      q_integer_rem(&c, &b);

      printf("div[%s, %"PRId32"]: quotient = ", large_signed[i], y);
      q_print(stdout, &a);
      printf(", remainder = ");
      q_print(stdout, &c);
      printf("\n");
    }
    printf("\n");
  }

  q_clear(&a);
  q_clear(&b);
  q_clear(&c);
}
/*
 * Test 3: a is small, b is large
 */
static void test_small_big(void) {
  rational_t a, b, c;
  uint32_t i;
  int32_t x;

  q_init(&a);
  q_init(&b);
  q_init(&c);

  for (i=0; i<NBIGS; i++) {
    q_set_from_string(&b, large_divisor[i]);
    for (x=-10; x<=10; x++) {
      q_set32(&a, x);
      q_set32(&c, x);
      q_integer_div(&a, &b);
      q_integer_rem(&c, &b);

      printf("div[%"PRId32", %s]: quotient = ", x, large_divisor[i]);
      q_print(stdout, &a);
      printf(", remainder = ");
      q_print(stdout, &c);
      printf("\n");
    }
    printf("\n");
  }

  q_clear(&a);
  q_clear(&b);
  q_clear(&c);
}
Exemple #5
0
/*
 * Test 4: construct 1/(2^n-1)
 */
static void test4(void) {
  rational_t r, aux, aux2;
  uint32_t i;

  printf("\nTest 4\n\n");

  q_init(&r);
  q_init(&aux);
  q_init(&aux2);
  q_set32(&aux, 2);
  q_set_one(&aux2);

  q_set_one(&r);
  for (i=0; i<68; i++) {
    q_inv(&r);
    test_conversions(&r);
    q_inv(&r);
    q_mul(&r, &aux);
    q_add(&r, &aux2);
  }

  q_set_minus_one(&r);
  for (i=0; i<68; i++) {
    q_inv(&r);
    test_conversions(&r);
    q_inv(&r);
    q_mul(&r, &aux);
    q_sub(&r, &aux2);
  }

  q_clear(&aux);
  q_clear(&aux2);
  q_clear(&r);
}
Exemple #6
0
/*
 * Test 3: inverses of powers of two
 */
static void test3(void) {
  rational_t r, aux;
  uint32_t i;

  printf("\nTest 3\n\n");

  q_init(&r);
  q_init(&aux);
  q_set_int32(&aux, 1, 2); // 1/2

  q_set_one(&r);
  for (i=0; i<68; i++) {
    test_conversions(&r);
    q_mul(&r, &aux);
  }

  q_set_minus_one(&r);
  for (i=0; i<68; i++) {
    test_conversions(&r);
    q_mul(&r, &aux);
  }

  q_clear(&aux);
  q_clear(&r);
}
/*
 * Test 4: a is large, b is large
 */
static void test_big_big(void) {
  rational_t a, b, c;
  uint32_t i, j;

  q_init(&a);
  q_init(&b);
  q_init(&c);

  for (i=0; i<NBIGS; i++) {
    q_set_from_string(&b, large_divisor[i]);
    for (j=0; j<NBIGS; j++) {
      q_set_from_string(&a, large_signed[j]);
      q_set(&c, &a);
      q_integer_div(&a, &b);
      q_integer_rem(&c, &b);

      printf("div[%s, %s]: quotient = ", large_signed[j], large_divisor[i]);
      q_print(stdout, &a);
      printf(", remainder = ");
      q_print(stdout, &c);
      printf("\n");
    }
    printf("\n");
  }

  q_clear(&a);
  q_clear(&b);
  q_clear(&c);
}
Exemple #8
0
/*
 * Test node removal: p = power_product to remove
 */
static void test_remove(rba_buffer_t *b, pprod_t *p) {
  uint32_t i, j;
  bool new_node;

  if (p == empty_pp) {
    printf("test remove: empty product\n");
  } else {
    printf("test remove: x%"PRId32"\n", var_of_pp(p));
  }

  i = rba_find_node(b, p);
  if (i != 0) {
    q_clear(&b->mono[i].coeff);
    // get_node must be called first to setup b->stack
    j = rba_get_node(b, p, &new_node);
    if (j != i && new_node) {
      printf("Error in test_removed: get_node failed\n");
      fflush(stdout);
      exit(1);
    }
    rba_delete_node(b, i);
    j = rba_find_node(b, p);
    if (j != 0) {
      printf("Error in test_remove: removal failed\n");
      fflush(stdout);
      exit(1);
    }

    check_tree(b);
  }
}
static void delete_vartable(void) {
  uint32_t i;

  for (i=0; i<NVARS; i++) {
    q_clear(&var[i].fixed_value);
  }
}
/*
 * Check whether cnstr => var[k] = period * integer + phase
 */
static void check_period_and_phase(int_constraint_t *cnstr, uint32_t k, rational_t *period, rational_t *phase) {
  rational_t test_val;
  int32_t x, z;  

  q_init(&test_val);

  x = int_constraint_get_var(cnstr, k);

  for (z = -10; z < 10; z++) {
    get_solution_for_var(cnstr, k, &test_val, z);
    q_sub(&test_val, phase);  // value - phase 
    if (q_divides(period, &test_val)) {
      printf("  passed test for %s = ", var[x].name);
      q_print(stdout, &test_val);
      printf("\n");
    } else {
      printf("*** BUG ***");
      printf("  failed test for %s = ", var[x].name);
      q_print(stdout, &test_val);
      printf("\n");
      fflush(stdout);
      exit(1);
    }
  }

  q_clear(&test_val);
}
Exemple #11
0
/*
 * Conversion to an integer
 */
static void convert32_test(rational_t *r1) {
  int32_t a;
  rational_t check;

  if (q_get32(r1, &a)) {
    printf("Rational: ");
    q_print(stdout, r1);
    printf(" equal to %"PRId32" (32 bits)\n", a);
    q_init(&check);
    q_set32(&check, a);
    if (! q_eq(r1, &check)) {
      printf("---> BUG\n");
      fflush(stdout);
      exit(1);
    }
    if (! q_is_int32(r1)) {
      printf("---> BUG\n");
      fflush(stdout);
      exit(1);
    }
    q_clear(&check);
  } else {
    printf("Rational: ");
    q_print(stdout, r1);
    printf(" not convertible to a 32bit integer\n");
    if (q_is_int32(r1)) {
      printf("---> BUG\n");
      fflush(stdout);
      exit(1);
    }
  }
}
Exemple #12
0
static void test_equality(int32_t x, int32_t y, int32_t offset, int32_t id) {
  rational_t q;

  printf("\n\n*** Asserting: eq[%"PRId32"]: ", id);
  if (x < 0) {
    printf("0 = ");
  } else {
    printf("x%"PRId32" = ", x);
  }
  if (y < 0) {
    printf("%"PRId32" ****\n", offset);
  } else {
    printf("x%"PRId32, y);
    if (offset > 0) {
      printf(" + %"PRId32" ****\n", offset);
    } else if (offset< 0) {
      printf(" - %"PRId32" ****\n", -offset);
    } else {
      printf(" ****\n");
    }
  }

  q_init(&q);
  q_set32(&q, offset);
  assert_offset_equality(&mngr, x, y, &q, id);
  q_clear(&q);
}
/*
 * Initialize the buffers
 */
static void init_test2(void) {
  rational_t q0;
  uint32_t i;

  q_init(&q0);
  for (i=0; i<8; i++) {
    init_rba_buffer(aux + i, &prod_table);
  }

  rba_buffer_add_var(&aux[0], 3); // x_3

  q_set32(&q0, 2);
  rba_buffer_add_const(&aux[1], &q0); // 2

  rba_buffer_add_var(&aux[2], 1);
  rba_buffer_sub_var(&aux[2], 2); // x_1 - x_2

  rba_buffer_add_var(&aux[3], 0);
  rba_buffer_sub_const(&aux[3], &q0); // x_0 - 2

  rba_buffer_add_pp(&aux[4], pprod_mul(&prod_table, var_pp(1), var_pp(1))); // x_1^2

  rba_buffer_add_var(&aux[5], 0);
  rba_buffer_mul_const(&aux[5], &q0); // 2 * x_0

  rba_buffer_add_varmono(&aux[6], &q0, 1); // 2 * x_1

  rba_buffer_sub_var(&aux[7], 3);
  rba_buffer_sub_var(&aux[7], 3);
  rba_buffer_add_var(&aux[7], 4);

  q_clear(&q0);
}
Exemple #14
0
/*
 * Apply s to a monomial array mono
 * - store the result in buffer b
 */
static void subst_poly(substitution_t *s, poly_buffer_t *b, monomial_t *mono) {
  offset_pair_t aux;
  rational_t q;
  int32_t x;

  q_init(&q);
  reset_poly_buffer(b);

  x = mono->var;
  while (x != max_idx) {
    if (x == const_idx) {
      poly_buffer_add_const(b, &mono->coeff);
    } else {
      aux.var = x;
      aux.delta = 0;
      subst_var(s, &aux); // aux constains S[x] = y + delta

      // add a * y + a * delta to b
      if (aux.var > 0) {
	poly_buffer_add_monomial(b, aux.var, &mono->coeff);
      }
      q_set32(&q, aux.delta);
      poly_buffer_addmul_monomial(b, const_idx, &mono->coeff, &q);
    }
    mono ++;
    x = mono->var;
  }

  normalize_poly_buffer(b);
  q_clear(&q);
}
Exemple #15
0
/*
 * Check whether b is of the form a * X - a * Y
 * for a non-zero rational a and two products X and Y.
 * If so return X in *r1 and Y in *r2
 */
bool arith_buffer_is_equality(arith_buffer_t *b, pprod_t **r1, pprod_t **r2) {
  mlist_t *p, *q;
  pprod_t *x, *y;
  rational_t a;
  bool is_eq;

  is_eq = false;
  if (b->nterms == 2) {
    p = b->list;
    q = p->next;
    x = p->prod;
    y = p->prod;
    if (x != empty_pp) {
      *r1 = x;
      *r2 = y;
      q_init(&a);
      q_set(&a, &p->coeff);
      q_add(&a, &q->coeff);
      is_eq = q_is_zero(&a);
      q_clear(&a);
    }
  }

  return is_eq;
}
Exemple #16
0
static void convert_int64_test(rational_t *r1) {
  int64_t a;
  uint64_t b;
  rational_t check;

  if (q_get_int64(r1, &a, &b)) {
    printf("Rational: ");
    q_print(stdout, r1);
    printf(" decomposed to %"PRId64"/%"PRIu64" (64 bits)\n", a, b);
    q_init(&check);
    q_set_int64(&check, a, b);
    if (! q_eq(r1, &check)) {
      printf("---> BUG\n");
      fflush(stdout);
      exit(1);
    }
    if (! q_fits_int64(r1)) {
      printf("---> BUG\n");
      fflush(stdout);
      exit(1);
    }
    q_clear(&check);
  } else {
    printf("Rational: ");
    q_print(stdout, r1);
    printf(" not convertible to 64bit integers\n");
    if (q_fits_int64(r1)) {
      printf("---> BUG\n");
      fflush(stdout);
      exit(1);
    }
  }
}
Exemple #17
0
/*
 * Random polynomial:
 * - use variables defined in table
 */
static polynomial_t *random_poly(poly_buffer_t *b, poly_table_t *table) {
  rational_t q;
  uint32_t i, n;
  int32_t x, a;

  q_init(&q);
  reset_poly_buffer(b);

  a = random_constant();
  q_set32(&q, a);
  poly_buffer_add_const(b, &q);

  n = random_nterms();
  for (i=0; i<n; i++) {
    a = random_coeff();
    x = random_var(table);
    assert(x > 0);

    q_set32(&q, a);
    poly_buffer_add_monomial(b, x, &q);
  }

  normalize_poly_buffer(b);
  q_clear(&q);

  return poly_buffer_get_poly(b);
}
Exemple #18
0
/*
 * Given p and q as above
 * - p and q must be normalized and have integer coefficients
 * - compute the GCD of all coefficients in p and q that are not
 *   in the common part.
 * - the result is returned in factor.
 * - if p = q, then the result is 0
 */
void monarray_pair_non_common_gcd(monomial_t *p, monomial_t *q, rational_t *factor) {
  int32_t x, y;

  q_clear(factor);
  x = p->var;
  y = q->var;
  for (;;) {
    if (x == y) {
      if (x == max_idx) break;
      if (q_neq(&p->coeff, &q->coeff)) {
        // a.x and b.x not in the common part
        aux_gcd(factor, &p->coeff);
        aux_gcd(factor, &q->coeff);
      }
      p ++;
      x = p->var;
      q ++;
      y = q->var;
    } else if (x < y) {
      aux_gcd(factor, &p->coeff);
      p ++;
      x = p->var;
    } else {
      aux_gcd(factor, &q->coeff);
      q ++;
      y = q->var;
    }
  }
}
Exemple #19
0
/*
 * Get the constant term of p and copy it in c
 * - p must be normalized
 */
void monarray_constant(monomial_t *p, rational_t *c) {
  if (p->var == const_idx) {
    q_set(c, &p->coeff);
  } else {
    q_clear(c);
  }
}
Exemple #20
0
static void free_normal_form(normal_form_t *tmp) {
  uint32_t i, n;

  n = tmp->size;
  for (i=0; i<n; i++) {
    q_clear(&tmp->mono[i].coeff);
  }
  safe_free(tmp);
}
/*
 * Print row in a simplified form: replace fixed variables by their value
 */
void print_simplex_reduced_row(FILE *f, simplex_solver_t *solver, row_t *row) {
  arith_vartable_t *vtbl;
  arith_bstack_t *bstack;
  rational_t q;
  uint32_t i, n;
  thvar_t x;
  bool first;
  int32_t l, u;

  vtbl = &solver->vtbl;
  bstack = &solver->bstack;

  // compute the constant
  q_init(&q);
  n = row->size;
  for (i=0; i<n; i++) {
    x = row->data[i].c_idx;
    if (x >= 0) {
      l = arith_var_lower_index(&solver->vtbl, x);
      u = arith_var_upper_index(&solver->vtbl, x);
      if (l >= 0 && u >= 0 && xq_eq(bstack->bound + l, bstack->bound + u)) {
        // x is a a fixed variable
        assert(xq_eq(bstack->bound + l, arith_var_value(vtbl, x)));
        assert(xq_is_rational(arith_var_value(vtbl, x)));
        q_addmul(&q, &row->data[i].coeff, &arith_var_value(vtbl, x)->main);
      }
    }
  }

  // print the non-constant monomials and q
  first = true;
  if (q_is_nonzero(&q)) {
    print_avar_monomial(f, vtbl, const_idx, &q, first);
    first = false;
  }

  for (i=0; i<n; i++) {
    x = row->data[i].c_idx;
    if (x >= 0) {
      l = arith_var_lower_index(&solver->vtbl, x);
      u = arith_var_upper_index(&solver->vtbl, x);
      if (l < 0 || u < 0 || xq_neq(bstack->bound + l, bstack->bound + u)) {
        // x is not a fixed variable
        print_avar_monomial(f, vtbl, x, &row->data[i].coeff, first);
        first = false;
      }
    }
  }

  if (first) {
    // nothing printed so the row is empty
    fputc('0', f);
  }
  fputs(" == 0", f);

  q_clear(&q);
}
/*
 * Sum of all fixed terms
 */
static void sum_of_fixed_terms(int_constraint_t *cnstr, rational_t *sum) {
  uint32_t i, n;

  q_clear(sum);
  n = cnstr->fixed_nterms;
  for (i=0; i<n; i++) {
    q_addmul(sum, cnstr->fixed_val + i, &cnstr->fixed_sum[i].coeff);
  }
}
Exemple #23
0
/*
 * Test sum and difference of triples
 */
static void test_add_diff(dl_vartable_t *table) {
  uint32_t i, j, n;
  dl_triple_t test;
  dl_triple_t test2;
  poly_buffer_t buffer;

  init_poly_buffer(&buffer);
  q_init(&test.constant);
  q_init(&test2.constant);

  n = table->nvars;
  for (i=0; i<n; i++) {
    for (j=0; j<n; j++) {
      printf("Testing sum: var!%"PRIu32" + var!%"PRIu32":\n", i, j);
      printf("--> var!%"PRIu32" : ", i);
      print_dl_triple(dl_var_triple(table, i));
      printf("\n");
      printf("--> var!%"PRIu32" : ", j);
      print_dl_triple(dl_var_triple(table, j));
      printf("\n");
      test_sum_buffer(table, &buffer, i, j, &test2);
      test_sum(table, i, j, &test);
      printf("\n");

      printf("Testing diff: var!%"PRIu32" - var!%"PRIu32":\n", i, j);
      printf("--> var!%"PRIu32" : ", i);
      print_dl_triple(dl_var_triple(table, i));
      printf("\n");
      printf("--> var!%"PRIu32" : ", j);
      print_dl_triple(dl_var_triple(table, j));
      printf("\n");
      test_diff_buffer(table, &buffer, i, j, &test2);
      test_diff(table, i, j, &test);
      printf("\n");
    }
  }

  q_clear(&test.constant);
  q_clear(&test2.constant);
  delete_poly_buffer(&buffer);
}
/*
 * Get a value of of variable k that satisfies the constraints.
 * - the constraint is (a * var[k] + other vars + fixed sum) is an integer
 * - so a possible solution is to set all non-fixed vars to (z - fixed_sum)/a
 */
static void get_solution_for_var(int_constraint_t *cnstr, uint32_t k, rational_t *val, int32_t z) {
  rational_t qz;

  assert(k < cnstr->sum_nterms);

  q_init(&qz);

  q_set32(&qz, z);
  sum_of_fixed_terms(cnstr, val);
  q_neg(val);
  q_add(val, &qz);
  q_div(val, &cnstr->sum[k].coeff);

  q_clear(&qz);
}
Exemple #25
0
int main(int argc, const char * argv[]) {
    QUEUE* queue = q_init();
    
    for (int i = 0; i < 5; i++) {
        q_enter(queue, i);
    }
    q_print(queue);
    
    q_quit(queue);
    q_quit(queue);
    q_print(queue);
    
    q_clear(queue);
    q_print(queue);
    
    return 0;
}
Exemple #26
0
static void test_assert_eq(test_bench_t *bench, int32_t x, int32_t y, int32_t offset) {
  offset_equality_t e;
  rational_t q;
  int32_t id;

  id = push_assert_eq(&bench->stack, x, y, offset);

  e.lhs = x;
  e.rhs = y;
  e.offset = offset;

  printf("[%"PRIu32"]: TEST_ASSERT_EQ: eq[%"PRId32"]: ", ctr, id);
  print_offset_eq(&e);
  printf("\n");

  subst_eq(&bench->subst, &e);

  // if e.lhs == e.rhs, we can't add to the substitution table
  if (e.lhs != e.rhs) {
    if (e.lhs < 0) {
      // convert 0 = y + offset into y := -offset
      e.lhs = e.rhs;
      e.rhs = -1;
      e.offset = -e.offset;
    }
    // add substitution e.lhs := e.rhs + e.offset
    add_subst(&bench->subst, e.lhs, e.rhs, e.offset);
    subst_queue_push_var(&bench->squeue, e.lhs);
  } else if (e.offset != 0) {
    bench->conflict = true;
    printf("---> Conflict\n");
    fflush(stdout);
    if (bench->conflict_eq < 0) {
      bench->conflict_eq = id;
    }
  }

  // forward to the offset manager
  q_init(&q);
  q_set32(&q, offset);
  assert_offset_equality(&bench->manager, x, y, &q, id);
  q_clear(&q);

  ctr ++;
}
Exemple #27
0
/*
 * Apply s to poly[i]
 * - store the result in buffer b
 */
static void subst_poly_idx(substitution_t *s, poly_table_t *table, poly_buffer_t *b, int32_t i) {
  monomial_t aux[2];
  polynomial_t *p;

  assert(0 < i && i < table->npolys);
  p = table->poly[i];
  if (p == NULL) {
    // build the polynomial 1.i in aux
    aux[0].var = i;
    q_init(&aux[0].coeff);
    q_set_one(&aux[0].coeff);
    aux[1].var = max_idx;
    subst_poly(s, b, aux);
    q_clear(&aux[0].coeff);
  } else {
    subst_poly(s, b, p->mono);
  }
}
Exemple #28
0
/*
 * Test hash consing: add a random triple in table
 */
static void test_random_triple(dl_vartable_t *table) {
  dl_triple_t *check;
  dl_triple_t test;
  int32_t x, y;

  test.target = random_vertex(6);
  test.source = random_vertex(6);
  q_init(&test.constant);
  random_rational(&test.constant);
  if (test.target == test.source) {
    test.target = nil_vertex;
    test.source = nil_vertex;
  }

  printf("Test: add triple ");
  print_dl_triple(&test);
  printf("\n");
  x = get_dl_var(table, &test);
  printf(" ---> var = %"PRId32"\n", x);

  check = dl_var_triple(table, x);
  if (check->target == test.target &&
      check->source == test.source &&
      q_eq(&check->constant, &test.constant)) {
    printf("Checking descriptor: OK\n");
  } else {
    printf("BUG: invalid descriptor for var %"PRId32"\n", x);
    fflush(stdout);
    exit(1);
  }

  y = get_dl_var(table, &test);
  if (x == y) {
    printf("Checking hash-consing: OK\n");
  } else {
    printf("BUG: hash-consing fails for var %"PRId32"\n", x);
    fflush(stdout);
    exit(1);
  }

  printf("\n");
  q_clear(&test.constant);
}
Exemple #29
0
/*
 * Normalize an array of monomials a or size n:
 * 1) merge monomials with identical variables:
 *     (c * v + d * v) --> (c + d) * v
 * 2) remove monomials with zero coefficients
 * 3) add end marker.
 * - a must be sorted.
 * - the function returns the size of the result = number of monomials
 *   in a after normalization.
 */
uint32_t normalize_monarray(monomial_t *a, uint32_t n) {
  uint32_t i, j, v;
  rational_t c;

  if (n == 0) return n;

  j = 0;
  q_init(&c);
  v = a[0].var;

  // c := a[0].coeff, clear a[0].coeff to prevent memory leak
  q_copy_and_clear(&c, &a[0].coeff);

  for (i=1; i<n; i++) {
    if (a[i].var == v) {
      q_add(&c, &a[i].coeff);
      q_clear(&a[i].coeff);
    } else {
      if (q_is_nonzero(&c)) {
        a[j].var = v;
        // copy c into a[j].coeff, then clear c
        q_copy_and_clear(&a[j].coeff, &c);
        j ++;
      }
      v = a[i].var;
      // copy a[i].coeff in c then clear a[i].coeff
      q_copy_and_clear(&c, &a[i].coeff);
    }
  }

  if (q_is_nonzero(&c)) {
    a[j].var = v;
    q_copy_and_clear(&a[j].coeff, &c);
    j ++;
  }

  // set end-marker
  a[j].var = max_idx;

  return j;
}
Exemple #30
0
/*
 * If p is an integer polynomial, compute factor = gcd of its coefficients
 * - p must be normalized and all its coefficients must be integers
 * - if p is zero, then factor is set to zero
 */
void monarray_common_factor(monomial_t *p, rational_t *factor) {
  int32_t v;

  v = p->var;
  if (v < max_idx) {
    // p is non zero
    assert(q_is_integer(&p->coeff));
    q_set_abs(factor, &p->coeff);
    for (;;) {
      p ++;
      v = p->var;
      if (v >= max_idx) break;
      assert(q_is_integer(&p->coeff));
      q_gcd(factor, &p->coeff);
    }

  } else {
    // p is zero
    q_clear(factor);
  }
}