ref: 2b23d05d57743af57385cd42c0fd2d223b11d8c8
dir: /constraint.c/
#include <u.h> #include <libc.h> #include <thread.h> #include "dat.h" #include "fns.h" /* monadic constraints */ /* dyadic constraints */ static void constraint_equal(Ast *, Array *, Array *); Array * allocvar(char *name) { static int id = 0; if(name == nil) name = "⎕var"; ConstraintVar *v = alloc(DataConstraintVar); v->name = name; v->id = id++; Array *a = allocarray(TypeVar, 0, 1); setvar(a, 0, v); return a; } static Ast * varast(Array *a) { if(a == nil) return nil; if(gettype(a) == TypeVar && getrank(a) == 0){ ConstraintVar *v = getvar(a, 0); if(v->ast) return v->ast; } Ast *c = alloc(DataAst); c->tag = AstConst; c->val = a; return c; } Array * delayedexpr(int prim, Array *x, Array *y) { Array *a = allocvar(nil); ConstraintVar *v = getvar(a, 0); Ast *func = alloc(DataAst); func->tag = AstPrim; func->prim = prim; Ast *e = alloc(DataAst); v->ast = e; e->func = func; e->tag = x ? AstDyadic : AstMonadic; e->left = varast(x); e->right = varast(y); return a; } void graphadd(ConstraintGraph *g, Constraint *c) { for(uvlong i = 0; i < g->ccount; i++){ if(g->cs[i] == c) return; /* The constraint is already there. TODO: make a better test */ } if(g->ccount == nelem(g->cs)) error(EInternal, "not enough space in the constraint graph"); g->cs[g->ccount] = c; g->ccount++; for(uvlong i = 0; i < nelem(c->vars); i++){ ConstraintVar *v = c->vars[i]; if(v == nil) continue; int new = 1; for(uvlong j = 0; j < g->vcount && new; j++){ if(g->vs[j] == v) new = 0; } if(!new) continue; g->vs[g->vcount] = v; g->vcount++; for(uvlong j = 0; j < v->count; j++) graphadd(g, v->constraints[j]); } } Array * solve(ConstraintVar *v) { Array *res; if(v->ast) error(EDomain, "Cannot solve expression. Use ⎕assert first."); /* Consider the available constraints on the variable, and find a solutions (just one). * If that isn't possible, fail with some appropriate error. * * There are of course multiple strategies to perform this search, and perhaps it would * make sense if ⎕solve let the user specify one as the left argument. */ /* Build a graph containing all the variables and constraints involved. * The number of max vars and constraints are fixed for now. */ ConstraintGraph *g = alloc(DataConstraintGraph); for(uvlong i = 0; i < v->count; i++) graphadd(g, v->constraints[i]); if(g->ccount == 0){ /* it can have any value */ res = allocarray(TypeNumber, 0, 1); setint(res, 0, 0); }else error(EInternal, "⎕solve not implemented (%ulld vars and %ulld constraints)", g->vcount, g->ccount); return res; } void constrain(ConstraintVar *v) { if(!v->ast) error(EDomain, "Expected a constraint expression, not a variable."); /* Analyse the AST and add the appropriate constraints to the variables involved. * Also simplify with the constraints already there, and give an error if * the simplifications show that no solutions are possible. */ int prim, dyadic; Array *left = nil; Array *right = nil; if(!(v->ast->tag == AstMonadic || v->ast->tag == AstDyadic)) goto fail; if(v->ast->func->tag != AstPrim) goto fail; prim = v->ast->func->prim; dyadic = 0; switch(v->ast->tag){ case AstDyadic: dyadic = 1; if(v->ast->left->tag != AstConst) goto fail; left = v->ast->left->val; /* fall through */ case AstMonadic: if(v->ast->right->tag != AstConst) goto fail; right = v->ast->right->val; } switch(prim){ case PMatch: if(dyadic) constraint_equal(v->ast, left, right); else goto fail; break; default: goto fail; } return; fail: error(EInternal, "don't know how to assert the given constraint"); } static void applyconstraint(Constraint *c) { /* Find the variables involved */ Array *args[2]; args[0] = c->left; args[1] = c->right; int nvars = 0; for(int i = 0; i < nelem(args); i++){ Array *a = args[i]; if(gettype(a) != TypeVar || getrank(a) != 0) continue; ConstraintVar *v = getvar(a, 0); c->vars[nvars] = v; nvars++; v->count++; v->constraints = allocextra(v, sizeof(c) * v->count); v->constraints[v->count-1] = c; } /* Should simplify here as well */ } /* monadic constraints */ /* dyadic constraints */ static void constraint_equal(Ast *a, Array *x, Array *y) { Constraint *c = alloc(DataConstraint); c->tag = CEqual; c->ast = a; c->left = x; c->right = y; applyconstraint(c); }