int noll_pure_add_dform (noll_pure_t * form, noll_dform_t * df) { assert (form != NULL); assert (df != NULL); if (form->data == NULL) form->data = noll_dform_array_new (); noll_dform_array_push (form->data, df); return 1; }
/** * @brief Update the data constraints in @g with eq constraints. * * The (in-)equality constraints on data are pushed. */ void noll_graph_sat_dform (noll_graph_t * g) { assert (g != NULL); if (g->data == NULL) g->data = noll_dform_array_new (); noll_dform_array *res = g->data; // go through all equality constraints and push them for data for (uint_t vi = 1; // ignore 'nil' vi < noll_vector_size (g->lvars); vi++) { noll_type_t *ty_vi = noll_var_type (g->lvars, vi); if (ty_vi->kind == NOLL_TYP_RECORD) continue; // it is a data variable // see relation of vi with all other data variables vj for (uint_t vj = vi + 1; // ignore 'nil' vj < noll_vector_size (g->lvars); vj++) { noll_type_t *ty_vj = noll_var_type (g->lvars, vj); if ((ty_vj->kind == NOLL_TYP_RECORD) || (ty_vi->kind != ty_vj->kind)) continue; uint_t ni = g->var2node[vi]; uint_t nj = g->var2node[vj]; assert (ni < g->nodes_size); assert (nj < g->nodes_size); if (ni == nj) { noll_dform_t *df = noll_dform_new_eq (noll_dterm_new_var (vi, ty_vi->kind), noll_dterm_new_var (vj, ty_vj->kind)); noll_dform_array_push (res, df); } // no difference constraints in the logic of msets if ((ty_vi->kind == NOLL_TYP_INT) && (noll_graph_is_diff (g, ni, nj) == true)) { noll_dform_t *df = noll_dform_new_eq (noll_dterm_new_var (vi, ty_vi->kind), noll_dterm_new_var (vj, ty_vj->kind)); df->kind = NOLL_DATA_NEQ; noll_dform_array_push (res, df); } } } g->isDataComplete = true; }
noll_dform_t * noll_dform_apply (noll_dform_t * df, noll_uid_array * m) { if (df == NULL) return NULL; /// if m == NULL, copy only noll_dform_t *res = noll_dform_new (); res->kind = df->kind; res->typ = df->typ; if (df->kind == NOLL_DATA_IMPLIES) { res->p.bargs = noll_dform_array_new (); noll_dform_array_reserve (res->p.bargs, 2); for (uint_t i = 0; i < 2; i++) { noll_dform_t *a = noll_dform_apply (noll_vector_at (df->p.bargs, i), m); if (a == NULL) { noll_dform_free (res); return NULL; } noll_dform_array_push (res->p.bargs, a); } return res; } /// only dterm arguments if (df->p.targs != NULL) { uint_t size = noll_vector_size (df->p.targs); res->p.targs = noll_dterm_array_new (); noll_dterm_array_reserve (res->p.targs, size); for (uint_t i = 0; i < size; i++) { noll_dterm_t *a = noll_dterm_apply (noll_vector_at (df->p.targs, i), m); if (a == NULL) { noll_dform_free (res); return NULL; } noll_dterm_array_push (res->p.targs, a); } } return res; }
/** * @brief Apply the substitution @p m on @p df and generate new formulas */ noll_dform_array * noll_dform_array_apply (noll_dform_array * df, noll_uid_array * m) { if (df == NULL || m == NULL) return NULL; noll_dform_array *res = noll_dform_array_new (); for (uint_t i = 0; i < noll_vector_size (df); i++) { noll_dform_t *dfi = noll_vector_at (df, i); noll_dform_t *dfi_m = noll_dform_apply (dfi, m); if (dfi_m == NULL) { noll_dform_array_delete (res); return NULL; } noll_dform_array_push (res, dfi_m); } return res; }
/** * @brief Check that @p diff entails @p f->m[@p m]. * * @return 0 if some constraint not entailed, 1 otherwise */ int noll_pure_check_entl (bool ** diff, uint_t dsize, noll_pure_t * f, noll_uid_array * lmap, noll_var_array * exvars, noll_uid_array * map, noll_dform_array * df) { /// this procedure could also be called for the pure part /// of a recursive rule, where @p f->m includes also existential vars, /// all shall be included in @p m assert (noll_vector_size (exvars) == noll_vector_size (map)); assert (f->size == noll_vector_size (lmap)); noll_dform_array *dfn = noll_dform_array_new (); int res = 1; for (uint_t lv2 = 1; (lv2 < noll_vector_size (lmap)) && res; lv2++) { uint_t v2 = noll_vector_at (lmap, lv2); noll_type_t *ty2 = noll_var_type (exvars, v2); for (uint_t lv1 = 0; (lv1 < lv2) && res; lv1++) { uint_t v1 = noll_vector_at (lmap, lv1); noll_type_t *ty1 = noll_var_type (exvars, v1); noll_pure_op_t rhs_op = noll_pure_matrix_at (f, lv1, lv2); if (rhs_op == NOLL_PURE_OTHER) continue; uint_t nv1 = noll_vector_at (map, v1); uint_t nv2 = noll_vector_at (map, v2); if (rhs_op == NOLL_PURE_EQ) { if (ty1->kind != ty2->kind) { #ifndef NDEBUG fprintf (stdout, "\n**** pure_check_entl: fails (typing) to prove (n%d == n%d)\n", nv1, nv2); #endif res = 0; } else /// one or both of variables is not yet bounded to a node, /// update m if the other is bounded if (nv1 < dsize && nv2 >= dsize) noll_uid_array_set (map, v2, nv1); else if (nv2 < dsize && nv1 >= dsize) noll_uid_array_set (map, v1, nv2); else if (ty1->kind == NOLL_TYP_RECORD) { /// shall be equal and less than dsize res = ((nv1 < dsize) && (nv2 < dsize) && (nv1 == nv2)) ? 1 : 0; #ifndef NDEBUG if (res == 0) fprintf (stdout, "\n**** pure_check_entl: fails (record) to prove (n%d == n%d)\n", nv1, nv2); #endif } else { /// there are nodes for data variables, generate a data constraint noll_dform_t *df_eq = noll_dform_new_eq (noll_dterm_new_var (v1, ty1->kind), noll_dterm_new_var (v2, ty2->kind)); noll_dform_array_push (dfn, df_eq); } } else if ((nv1 < dsize) && (nv2 < dsize)) { assert (rhs_op == NOLL_PURE_NEQ); bool lhs_isDiff = (nv1 != nv2); if (nv1 < nv2) lhs_isDiff = diff[nv2][nv1]; else if (nv2 < nv1) lhs_isDiff = diff[nv1][nv2]; res = (lhs_isDiff) ? 1 : 0; } else { /// inequality between unmapped vars /// push the constraint if vars are integer vars if ((ty1->kind == ty2->kind) && (ty1->kind == NOLL_TYP_INT)) /// generate an inequality constraint for data vars { noll_dform_t *df_eq = noll_dform_new_eq (noll_dterm_new_var (v1, ty1->kind), noll_dterm_new_var (v2, ty2->kind)); df_eq->kind = NOLL_DATA_NEQ; noll_dform_array_push (dfn, df_eq); } else /// cannot be checked assert (0); } } } if (res == 1) noll_dform_array_cup_all (df, dfn); noll_dform_array_clear (dfn); return res; }