/* * 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); }
/* * 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); }
/* * 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); }
/* * 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); }
/* * 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); }
/* * 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); } } }
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); }
/* * 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); }
/* * 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; }
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); } } }
/* * 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); }
/* * 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; } } }
/* * 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); } }
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); } }
/* * 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); }
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; }
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 ++; }
/* * 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); } }
/* * 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); }
/* * 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; }
/* * 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); } }