示例#1
0
/*
 * Convert term t to a conditional; store the result in d
 * - d is reset first
 * - t must be a valid term defined in d->terms
 * - if t is not an if-then-else term, the result is
 *     d->nconds = 0
 *     d->defval = t
 * - if t is (ite c a b) then the conversion depends on whether
 *   a or b is an if-then-else term.
 */
void convert_term_to_conditional(conditional_t *d, term_t t) {
  composite_term_t *ite;
  term_t a, b;

  if (is_ite_term(d->terms, t)) {
    ite = ite_term_desc(d->terms, t);
    assert(ite->arity == 3);

    a = ite->arg[1];
    b = ite->arg[2];
    if (is_neg_term(t)) {
      a = opposite_term(a);
      b = opposite_term(b);
    }
    convert_ite_to_conditional(d, ite->arg[0], ite->arg[1], ite->arg[2]);
  } else {
    reset_conditional(d);
    d->defval = t;
  }
}
示例#2
0
/*
 * Build the abstraction for an (OR ...) formula or its negation
 * - if polarity is true: abstraction of (OR t1 ... tn)
 * - if polarity is false: abstraction of not (OR t1 ... tn)
 *   (i.e., abstraction of (AND (not t1) ... (not tn)))
 */
static epartition_t *eq_abstract_or(eq_learner_t *learner, composite_term_t *or, bool polarity) {
  uint32_t i, n;
  epartition_manager_t *m;
  epartition_t *p;

  assert(or->arity > 1);

  // abstract the arguments
  n = or->arity;
  for (i=0; i<n; i++) {
    (void) eq_abstract(learner, or->arg[i], polarity);
  }

  /*
   * for (OR t1 ... t_n): construct the join of abs(t1) ... abs(t_n)
   * for not (OR t1 ... t_n) <=> (and (not t1) ... (not t_n)):
   *  construct meet(abs (not t1) ... abs(not t_n))
   */
  m = &learner->manager;
  if (polarity) {
    // (OR t1 ... t_n)
    p = get_cached_abstraction(learner, or->arg[0]);
    epartition_init_for_join(m, p);
    for (i=1; i<n; i++) {
      p = get_cached_abstraction(learner, or->arg[i]);
      epartition_join(m, p);
    }
    return epartition_get_join(m);

  } else {
    // (AND (not t1) ... (not t_n))
    p = get_cached_abstraction(learner, opposite_term(or->arg[0]));
    epartition_init_for_meet(m, p);
    for (i=1; i<n; i++) {
      p = get_cached_abstraction(learner, opposite_term(or->arg[i]));
      epartition_meet(m, p);
    }
    return epartition_get_meet(m);
  }
}
示例#3
0
/*
 * Assert (B and not C) in ctx
 * - return the assertion code
 */
static int32_t forall_context_assert(ef_solver_t *solver, term_t b, term_t c) {
  context_t *ctx;
  term_t assertions[2];

  ctx = solver->forall_context;

  assert(ctx != NULL && context_status(ctx) == STATUS_IDLE);
  assert(is_boolean_term(ctx->terms, b) && is_boolean_term(ctx->terms, c));

  assertions[0] = b;
  assertions[1] = opposite_term(c);
  return assert_formulas(ctx, 2, assertions);
}
示例#4
0
/*
 * Compute an implicant for constraint i
 * - we must have an assignment for the exists variable in solver->evalue
 *   and an assignment for the universal variables of constraints i in
 *   solver->uvalue_aux.
 * - this builds and store the full model for constraint i in solver->full_model
 *   then construct and store the implicant in solver->implicant
 *
 * Error codes: set solver->status to EF_STATUS_ERROR
 * - this may happen if yices_model_from_map or yices_implicant_for_fomuulas fail
 */
static void ef_build_implicant(ef_solver_t *solver, uint32_t i) {
  model_t *mdl;
  ef_cnstr_t *cnstr;
  term_vector_t *v;
  term_t a[2];
  uint32_t n;
  int32_t code;

  assert(i < ef_prob_num_constraints(solver->prob));

  // free the current full model if any
  if (solver->full_model != NULL) {
    yices_free_model(solver->full_model);
    solver->full_model = NULL;
  }

  // build the full_map and the correspongin model.
  ef_build_full_map(solver, i);
  n = solver->all_vars.size;
  assert(n == solver->all_values.size);
  mdl = yices_model_from_map(n, solver->all_vars.data, solver->all_values.data);
  if (mdl == NULL) {
    // error in the model construction
    solver->status = EF_STATUS_ERROR; // TODO: add another code
    solver->error_code = yices_error_code();
    return;
  }
  solver->full_model = mdl;

  cnstr = solver->prob->cnstr + i;
  a[0] = cnstr->assumption;
  a[1] = opposite_term(cnstr->guarantee);
  v = &solver->implicant;
  v->size = 0;
  code = yices_implicant_for_formulas(mdl, 2, a, v);
  if (code < 0) {
    solver->status = EF_STATUS_ERROR;
    solver->error_code = yices_error_code();
  }

#if 1
  printf("Implicant\n");
  yices_pp_term_array(stdout, v->size, v->data, 120, UINT32_MAX, 0, 0);
  printf("(%"PRIu32" literals)\n", v->size);
#endif

}
示例#5
0
/*
 * Main abstraction function
 */
static epartition_t *eq_abstract(eq_learner_t *learner, term_t f, bool polarity) {
  term_table_t *terms;
  epartition_t *a;

  assert(is_boolean_term(learner->terms, f));

  a = find_cached_abstraction(learner, signed_term(f, polarity));
  if (a == NULL) {
    // not in the cache

    // remove top-level negation
    if (is_neg_term(f)) {
      f = opposite_term(f);
      polarity = !polarity;
    }

    // explore f
    terms = learner->terms;
    switch (term_kind(terms, f)) {
    case EQ_TERM:
      a = eq_abstract_eq(learner, eq_term_desc(terms, f), polarity);
      break;
    case ITE_TERM:
    case ITE_SPECIAL:
      a = eq_abstract_ite(learner, ite_term_desc(terms, f), polarity);
      break;
    case OR_TERM:
      a = eq_abstract_or(learner, or_term_desc(terms, f), polarity);
      break;
    default:
      a = empty_epartition(&learner->manager);
      break;
    }
    cache_abstraction(learner, signed_term(f, polarity), a);
  }

  return a;
}
示例#6
0
/*
 * Flatten all terms in flat->queue to conjuncts
 * - all terms in the queue must also be in the cache
 * - f_ite: if true, flatten (ite c a b)
 * - f_iff: if true, flatten (iff a b)
 */
static void flattener_build_conjuncts(flattener_t *flat, bool f_ite, bool f_iff) {
  term_table_t *terms;
  int_queue_t *queue;
  composite_term_t *d;
  term_t t, u, v;
  uint32_t i, n;

  queue = &flat->queue;
  terms = flat->terms;

  while (! int_queue_is_empty(queue)) {
    t = int_queue_pop(queue);

    switch (term_kind(terms, t)) {
    case ITE_TERM:
    case ITE_SPECIAL:
      d = ite_term_desc(terms, t);
      assert(d->arity == 3);
      if (f_ite && is_boolean_term(terms, d->arg[1])) {
        assert(is_boolean_term(terms, d->arg[2]));
        /*
         * If t is (ite C A B)
         *    u := (C => A)
         *    v := (not C => B)
         * Otherwise, t is (not (ite C A B))
         *    u := (C => not A)
         *    v := (not C => not B)
         */
        u = d->arg[1];  // A
        v = d->arg[2];  // B
        if (is_neg_term(t)) {
          u = opposite_term(u);
          v = opposite_term(v);
        }
        u = mk_implies(flat->manager, d->arg[0], u); // (C => u)
        v = mk_implies(flat->manager, opposite_term(d->arg[0]), v); // (not C) => v
        flattener_push_term(flat, u);
        flattener_push_term(flat, v);
        continue;
      }
      break;

    case EQ_TERM:
      d = eq_term_desc(terms, t);
      assert(d->arity == 2);
      if (f_iff && is_boolean_term(terms, d->arg[0])) {
        assert(is_boolean_term(terms, d->arg[1]));
        /*
         * t is either (iff A B) or (not (iff A B)):
         */
        u = d->arg[0]; // A
        v = d->arg[1]; // B
        if (is_neg_term(t)) {
          u = opposite_term(u);
        }
        // flatten to (u => v) and (v => u)
        t = mk_implies(flat->manager, u, v); // (u => v)
        u = mk_implies(flat->manager, v, u); // (v => u);
        flattener_push_term(flat, t);
        flattener_push_term(flat, u);
        continue;
      }
      break;

    case OR_TERM:
      if (is_neg_term(t)) {
        /*
         * t is (not (or a[0] ... a[n-1]))
         * it flattens to (and (not a[0]) ... (not a[n-1]))
         */
        d = or_term_desc(terms, t);
        n = d->arity;
        for (i=0; i<n; i++) {
          flattener_push_term(flat, opposite_term(d->arg[i]));
        }
        continue;
      }
      break;

    default:
      break;
    }
    ivector_push(&flat->resu, t);
  }

  // clean up the cache
  assert(int_queue_is_empty(queue));
  int_hset_reset(&flat->cache);
}
示例#7
0
/*
 * Process disjuncts and universal quantifiers
 * - input = all terms in the queue
 * - f_ite: if true, flatten (ite c a b)
 * - f_iff: if true, flatten (iff a b)
 */
static void flattener_forall_disjuncts(flattener_t *flat, bool f_ite, bool f_iff) {
  term_table_t *terms;
  int_queue_t *queue;
  composite_term_t *d;
  term_t t, u, v;
  uint32_t i, n;

  queue = &flat->queue;
  terms = flat->terms;

  while (! int_queue_is_empty(queue)) {
    t = int_queue_pop(queue);

    switch (term_kind(terms, t)) {
    case ITE_TERM:
    case ITE_SPECIAL:
      d = ite_term_desc(terms, t);
      assert(d->arity == 3);
      if (f_ite && is_boolean_term(terms, d->arg[1])) {
        assert(is_boolean_term(terms, d->arg[2]));
        /*
         * If t is (ite C A B)
         *    u := (C AND A)
         *    v := (not C AND B)
         * Otherwise, t is (not (ite C A B))
         *    u := (C AND not A)
         *    v := (not C AND not B)
         */
        u = d->arg[1];  // A
        v = d->arg[2];  // B
        if (is_neg_term(t)) {
          u = opposite_term(u); // NOT A
          v = opposite_term(v); // NOT B
        }
        u = mk_binary_and(flat->manager, d->arg[0], u); // (C AND u)
        v = mk_binary_and(flat->manager, opposite_term(d->arg[0]), v); // (not C) AND v
        flattener_push_term(flat, u);
        flattener_push_term(flat, v);
        continue;
      }
      break;

    case EQ_TERM:
      d = eq_term_desc(terms, t);
      assert(d->arity == 2);
      if (f_iff && is_boolean_term(terms, d->arg[0])) {
        assert(is_boolean_term(terms, d->arg[1]));
        /*
         * t is either (iff A B) or (not (iff A B)):
         */
        u = d->arg[0]; // A
        v = d->arg[1]; // B
        if (is_neg_term(t)) {
          u = opposite_term(u);
        }
        // flatten to (u AND v) or ((not u) AND (not v))
        t = mk_binary_and(flat->manager, u, v); // (u AND v)
        u = mk_binary_and(flat->manager, opposite_term(u), opposite_term(v)); // (not u AND not v);
        flattener_push_term(flat, t);
        flattener_push_term(flat, u);
        continue;
      }
      break;

    case OR_TERM:
      if (is_pos_term(t)) {
        /*
         * t is (or a[0] ... a[n-1])
         */
        d = or_term_desc(terms, t);
        n = d->arity;
        for (i=0; i<n; i++) {
          flattener_push_term(flat, d->arg[i]);
        }
        continue;
      }
      break;

    case FORALL_TERM:
      if (is_pos_term(t)) {
        d = forall_term_desc(terms, t);
        n = d->arity;
        assert(n >= 2);
        /*
         * t is (FORALL x_0 ... x_k : body)
         * body is the last argument in the term descriptor
         */
        flattener_push_term(flat, d->arg[n-1]);
        continue;
      }
      break;

    default:
      break;
    }

    ivector_push(&flat->resu, t);
  }

  // clean up the cache
  assert(int_queue_is_empty(queue));
  int_hset_reset(&flat->cache);
}
示例#8
0
/*
 * Convert (if c a b) to a conditional
 */
void convert_ite_to_conditional(conditional_t *d, term_t c, term_t a, term_t b) {
  composite_term_t *ite;
  term_t t, c1, t1, t2;

  reset_conditional(d);

  if (is_ite_term(d->terms, b)) {
    /*
     * b is either (ite c1 ...) or (not (ite c1  ...).
     *
     * we normalize to (ite c1 t1 t2):
     * - if b is (ite c1 t1 t2) we're done
     * - if b is (not (ite c1 u1 u2)) we push the negation inside:
     *   so t1 := (not u1) and t2 := (not u2)
     */
    ite = ite_term_desc(d->terms, b);
    assert(ite->arity == 3);

    c1 = ite->arg[0];
    t1 = ite->arg[1];
    t2 = ite->arg[2];
    if (is_neg_term(b)) {
      t1 = opposite_term(t1);
      t2 = opposite_term(t2);
    }

    /*
     * we try to build the conditional
     *    [c --> a,     c1 --> t1, else --> t2] if c and c1 are disjoint
     * or [c --> a, not c1 --> t2, else --> t1] if c and not c1 are disjoint
     */
    if (incompatible_boolean_terms(d->terms, c, c1)) {
      conditional_add_pair(d, c, a);
      conditional_add_pair(d, c1, t1);
      t = t2;
      goto loop;
    }

    if (incompatible_boolean_terms(d->terms, c, opposite_term(c1))) {
      conditional_add_pair(d, c, a);
      conditional_add_pair(d, opposite_term(c1), t2);
      t = t1;
      goto loop;
    }
  }

  if (is_ite_term(d->terms, a)) {
    /*
     * a is either (ite c1 ...) or (not (ite c1 ...))
     * we normalize as above to (ite c1 t1 t2)
     */
    ite = ite_term_desc(d->terms, a);
    assert(ite->arity == 3);

    c1 = ite->arg[0];
    t1 = ite->arg[1];
    t2 = ite->arg[2];
    if (is_neg_term(a)) {
      t1 = opposite_term(t1);
      t2 = opposite_term(t2);
    }

    /*
     * we try
     *    [not c --> b,     c1 --> t1, else --> t2]
     * or [not c --> b, not c1 --> t2, else --> t1]
     */
    if (incompatible_boolean_terms(d->terms, opposite_term(c), c1)) {
      conditional_add_pair(d, opposite_term(c), b);
      conditional_add_pair(d, c1, t1);
      t = t2;
      goto loop;
    }

    if (incompatible_boolean_terms(d->terms, opposite_term(c), opposite_term(c1))) {
      conditional_add_pair(d, opposite_term(c), b);
      conditional_add_pair(d, opposite_term(c1), t2);
      t = t1;
      goto loop;
    }
  }

  // Default: found no disjoint conditions
  conditional_add_pair(d, c, a);
  d->defval = b;
  return;

  // t is the 'else part'
 loop:
  while (is_ite_term(d->terms, t)) {
    // t is (ite c1 t1 t2)
    ite = ite_term_desc(d->terms, t);
    assert(ite->arity == 3);

    c1 = ite->arg[0];
    t1 = ite->arg[1];
    t2 = ite->arg[2];
    if (is_neg_term(t)) {
      t1 = opposite_term(t1);
      t2 = opposite_term(t2);
    }

    if (disjoint_condition(d, c1)) {
      conditional_add_pair(d, c1, t1);
      t = t2;
    } else if (disjoint_condition(d, opposite_term(c1))) {
      conditional_add_pair(d, opposite_term(c1), t2);
      t = t1;
    } else {
      break;
    }
  }

  d->defval = t;
}
示例#9
0
static match_code_t match_term(context_t *ctx, term_t t, term_t *a, term_t *x) {
  composite_term_t *eq;
  term_table_t *terms;
  match_code_t code;
  term_t t1, t2;

  if (term_is_false(ctx, t)) {
    code = MATCH_FALSE;
  } else {
    code = MATCH_OTHER;
    terms = ctx->terms;

    switch (term_kind(terms, t)) {
    case OR_TERM:
      if (is_pos_term(t)) {
	code = MATCH_OR;
      }
      break;

    case EQ_TERM:
      eq = eq_term_desc(terms, t);
      t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
      t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
      if (is_boolean_term(terms, t1)) {
	assert(is_boolean_term(terms, t2));
	/*
	 * t is either (iff t1 t2) or (not (iff t1 t2))
	 * we rewrite (not (iff t1 t2)) to (iff t1 (not t2))
	 */
	if (is_neg_term(t)) {
	  t2 = opposite_term(t2);
	}
	/*
	 * Check whether t1 or t2 is true or false
	 */
	if (term_is_true(ctx, t1)) {
	  code = MATCH_IFF;
	  *x = t2;
	} else if (term_is_false(ctx, t1)) {
	  code = MATCH_IFF;
	  *x = opposite_term(t2);
	} else if (term_is_true(ctx, t2)) {
	  code = MATCH_IFF;
	  *x = t1;
	} else if (term_is_false(ctx, t2)) {
	  code = MATCH_IFF;
	  *x = opposite_term(t1);
	}

      } else if (t1 != t2) {
	/*
	 * t1 and t2 are not Boolean
	 * if t1 and t2 are equal, we return MATCH_OTHER, since (eq t1 t2) is true
	 */
	assert(is_pos_term(t1) && is_pos_term(t2));
	if (false_eq(terms, t1, t2)) {
	  code = MATCH_FALSE;
	} else if (term_is_constant(terms, t1)) {
	  *a = t1;
	  *x = t2;
	  code = MATCH_EQ;
	} else if (term_is_constant(terms, t2)) {
	  *a = t2;
	  *x = t1;
	  code = MATCH_EQ;
	}
      }
      break;

    default:
      break;
    }
  }

  return code;
}
示例#10
0
/*
 * Option 3: generalize by computing an implicant then
 * applying projection.
 */
static term_t ef_generalize3(ef_solver_t *solver, uint32_t i) {
  model_t *mdl;
  ef_cnstr_t *cnstr;
  ivector_t *v, *w;
  term_t a[2];
  uint32_t n;
  int32_t code;
  proj_flag_t pflag;
  term_t result;

  assert(i < ef_prob_num_constraints(solver->prob));

  // free the current full model if any
  if (solver->full_model != NULL) {
    yices_free_model(solver->full_model);
    solver->full_model = NULL;
  }

  // build the full_map and the corresponding model.
  ef_build_full_map(solver, i);
  n = solver->all_vars.size;
  assert(n == solver->all_values.size);
  mdl = yices_model_from_map(n, solver->all_vars.data, solver->all_values.data);
  if (mdl == NULL) {
    // error in the model construction
    solver->status = EF_STATUS_MDL_ERROR;
    solver->error_code = yices_error_code();
    return NULL_TERM;
  }
  solver->full_model = mdl;


  // Constraint
  cnstr = solver->prob->cnstr + i;
  a[0] = cnstr->assumption;                 // B(y)
  a[1] = opposite_term(cnstr->guarantee);   // not C(x, y)


#if EF_VERBOSE
  printf("Constraint:\n");
  yices_pp_term_array(stdout, 2, a, 120, UINT32_MAX, 0, 0);
  printf("(%"PRIu32" literals)\n", 2);
#endif

  // Compute the implicant
  v = &solver->implicant;
  ivector_reset(v);
  code = get_implicant(mdl, solver->prob->manager, LIT_COLLECTOR_ALL_OPTIONS, 2, a, v);
  if (code < 0) {
    solver->status = EF_STATUS_IMPLICANT_ERROR;
    solver->error_code = code;
    return NULL_TERM;
  }

#if EF_VERBOSE
  printf("Implicant:\n");
  yices_pp_term_array(stdout, v->size, v->data, 120, UINT32_MAX, 0, 0);
  printf("(%"PRIu32" literals)\n", v->size);
#endif

  // Projection
  w = &solver->projection;
  ivector_reset(w);
  n = ef_constraint_num_uvars(cnstr);

#if EF_VERBOSE
  printf("(%"PRIu32" universals)\n", n);
  yices_pp_term_array(stdout, n, cnstr->uvars, 120, UINT32_MAX, 0, 0);
#endif

  
  pflag = project_literals(mdl, solver->prob->manager, v->size, v->data, n, cnstr->uvars, w);

  if (pflag != PROJ_NO_ERROR) {
    solver->status = EF_STATUS_PROJECTION_ERROR;
    solver->error_code = pflag;
    return NULL_TERM;
  }

#if EF_VERBOSE
  printf("Projection:\n");
  yices_pp_term_array(stdout, w->size, w->data, 120, UINT32_MAX, 0, 0);
  printf("(%"PRIu32" literals)\n", w->size);
#endif

  switch (w->size) {
  case 0:
    result = true_term;
    break;

  case 1:
    result = w->data[0];
    break;

  default:
    result = mk_and(solver->prob->manager, w->size, w->data);
    break;
  }

  return opposite_term(result);
}