/** * @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; }
/** * @brief Do the union between @p dst and @p src in @p dst */ void noll_dform_array_cup_all (noll_dform_array * dst, noll_dform_array * src) { assert (dst != NULL); if (src == NULL) return; for (uint_t i = 0; i < noll_vector_size (src); i++) noll_dform_array_push (dst, noll_vector_at (src, i)); // TODO: do a cup }
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; }
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; }
/** * Return the edge of @p g2 having label @p label between nodes @p args. * * @param args [inout] contains the mapping of arguments of the edge * on nodes of @p g or UNDEFINED_ID * @param df [inout] collect the equality constraints between data * required by the mapping found * @return the identifier of the edge matched or UNDEFINED_ID */ uint_t noll_graph_get_edge (noll_graph_t * g, noll_edge_e kind, uint_t label, noll_uid_array * args, noll_dform_array * df) { // store of edge identifier matching the searched edge uint_t uid_res = UNDEFINED_ID; // source and destination nodes for edge searched uint_t nroot = noll_vector_at (args, 0); // a new intermediary node uint_t nend = noll_vector_at (args, 1); uint_t fargs = noll_vector_size (args); uint_t shift_j = 0; if (noll_pred_isUnaryLoc (label) == true) { nend = 0; fargs++; shift_j++; } #ifndef NDEBUG fprintf (stdout, "\n---- Search for edge n%d---(kind=%d, label=%d)-->n%d:\n", nroot, kind, label, nend); #endif if (g->mat[nroot] != NULL) { for (uint_t i = 0; (i < noll_vector_size (g->mat[nroot])) && (uid_res == UNDEFINED_ID); i++) { uint_t ei = noll_vector_at (g->mat[nroot], i); noll_edge_t *edge_i = noll_vector_at (g->edges, ei); if ((edge_i->kind == kind) && (edge_i->label == label) && (noll_vector_size (edge_i->args) == fargs)) { #ifndef NDEBUG fprintf (stdout, "\t found e%d, same kind, label and root\n", ei); #endif // edge found with the same kind, label and root, // check the other arguments than source are equal bool ishom = true; for (uint_t j = 1; j < noll_vector_size (args) && (ishom == true); j++) { uint_t naj = noll_vector_at (args, j); uint_t nej = noll_vector_at (edge_i->args, j + shift_j); if (naj == UNDEFINED_ID) { #ifndef NDEBUG fprintf (stdout, "\t\t update arg %d to n%d\n", j, nej); #endif noll_uid_array_set (args, j, nej); } else if (naj != nej) { noll_typ_t ty = noll_graph_get_node_type (g, naj); if ((ty == NOLL_TYP_INT) || (ty == NOLL_TYP_BAGINT)) { // generate an equality constraint uid_t vaj = noll_graph_get_var (g, naj); uid_t vej = noll_graph_get_var (g, naj); noll_dform_t *df_eq = noll_dform_new_eq (noll_dterm_new_var (vaj, ty), noll_dterm_new_var (vej, ty)); noll_dform_array_push (df, df_eq); } else { // if it is a location node, then error #ifndef NDEBUG fprintf (stdout, "\t\t but different arg %d (n%d != n%d)\n", j, naj, nej); #endif ishom = false; } } } if (ishom == true) { #ifndef NDEBUG fprintf (stdout, "\t\t , the same args, and the df = "); noll_dform_array_fprint (stdout, g->lvars, df); #endif uid_res = ei; } } } } #ifndef NDEBUG fprintf (stdout, "\t edge-%d matches!\n", uid_res); #endif if (uid_res == UNDEFINED_ID) noll_dform_array_clear (df); // TODO: free also the pointers inside return uid_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; }