C:/Users/Dennis/src/lang/bertrand/BERTRAND/bertrand/mole.c

Go to the documentation of this file.
00001 /*****************************************************************
00002  *
00003  * These routines are not finished yet, and have not been included
00004  * in the current Bertrand interpreter.  As they currently stand,
00005  * they make invalid assumptions about the form of a linear expression.
00006  * When a bound variable in a linear expression gets replaced by
00007  * its value, these assumptions will be violated.  There might be
00008  * other bugs as well (and ole_solve has not even been written yet!).
00009  *
00010  * Wm Leler
00011  *
00012  *****************************************************************/
00013 
00014 /*****************************************************************
00015  *
00016  * Manipulate Ordered Linear Expressions
00017  *
00018  * Some of these routines could be implemented in Bertand directly
00019  * but were done instead as primitives for speed.
00020  * See the comments for each routine.
00021  *
00022  * Linear expressions are always of the form:
00023  *      (c1**v1) ++ (c2**v2) ++ ... ++ (cn**vn) ++ k
00024  * where the v's are variables and the c's and the k are constants.
00025  * (See note above for a problem concerning what happens when a
00026  * variable v becomes bound and is replaced by its value.)
00027  *
00028  *****************************************************************/
00029 
00030 #include "def.h"
00031 
00032 NODE *expr_copy();      /* from expr.c */
00033 NODE *node_new();       /* from expr.c */
00034 NODE *expr_update();    /* from expr.c */
00035 
00036 /*****************************************************************
00037  *
00038  * Multiply a linear expression by a constant.
00039  *
00040  * The argument must be an expression of the form:
00041  *      k'constant * lx'linear
00042  *
00043  * Equivalent Bertrand code for this:
00044  *      k'constant * ((c**v) ++ rest)   { ((k*c)**v) ++ (k * rest) }
00045  *
00046  *****************************************************************/
00047 NODE *
00048 ole_multiply(tn)
00049 TERM_NODE *tn;
00050 {
00051 double k = ((NUM_NODE *)(tn->left))->value;
00052 NODE *answer = expr_copy(tn->right);
00053 register TERM_NODE *t = (TERM_NODE *) answer;
00054 
00055 while(t) {      /* ever */
00056     if (t->op->arity == OP_NUM) {       /* the constant at the end */
00057         ((NUM_NODE *)t)->value *= k;
00058         return answer;
00059         }
00060     ((NUM_NODE *)((TERM_NODE *)(t->left))->left)->value *= k;
00061     t = (TERM_NODE *)(t->right);
00062     }
00063 
00064 expr_print(tn->right);
00065 error("invalid linear expression to multiply");
00066 }
00067 
00068 /*****************************************************************
00069  *
00070  * Add two linear expressions.
00071  *
00072  * The argument must be an expression of the form:
00073  *      lx1'linear + lx2'linear
00074  *
00075  * Equivalent Bertrand code:
00076  *      ... add a constant to a linear expression
00077  *      k'constant + ((c**v) ++ rest)   { (c**v) ++ (k + rest) }
00078  *      ((c**v) ++ rest) + k'constant   { (c**v) ++ (k + rest) }
00079  *      ... add two linear expressions
00080  *      ((c1**v1'numvar)++r1) + ((c2**v2'numvar)++r2) {
00081  *          lx_merge ( (1+(v1 lexc v2)), ((c1**v1)++r1) , ((c2**v2)++r2) }
00082  *      lx_merge( 0, (t1++r1) , lx2 ) { t1 ++ (r1 + lx2) }      .. less
00083  *      lx_merge( 2, lx1 , (t2++r2) ) { t2 ++ (lx1 + r2) }      .. greater
00084  *      lx_merge( 1, ((c1**v1)++r1) , ((c2**v2)++r2) ) {        .. equal
00085  *          lx_merge ( (c1 = -c2), ((c1**v1)++r1) , ((c2**v2)++r2) }
00086  *      lx_merge(  true, (t1++r1) , (t2++r2) ) { r1 + r2 }
00087  *      lx_merge( false, ((c1**v1)++r1) , ((c2**v2)++r2) ) {
00088  *          ((c1+c2)**v1) ++ (r1 + r2) }
00089  *
00090  *****************************************************************/
00091 NODE *
00092 ole_add(exp)
00093 TERM_NODE *exp;
00094 {
00095 register TERM_NODE *le = (TERM_NODE *)(exp->left);
00096 register TERM_NODE *re = (TERM_NODE *)(exp->right);
00097 NODE *answer;
00098 register TERM_NODE *pa = NULL;  /* position in answer */
00099 double con;                     /* merged constant */
00100 register TERM_NODE *newt;       /* new term */
00101 
00102 for(;;) {       /* ever */
00103     /* next term in answer is the constant (the final term) */
00104     if ((le->op->arity == OP_NUM) && (re->op->arity == OP_NUM)) {
00105         newt = (TERM_NODE *) expr_copy((NODE *)le);
00106         ((NUM_NODE *)newt)->value =
00107             ((NUM_NODE *)le)->value + ((NUM_NODE *)re)->value;
00108         if (pa) pa->right = (NODE *) newt;
00109         else {  /* answer is just a constant (other terms cancelled!) */
00110             answer = (NODE *) newt;
00111             }
00112         return answer;
00113         }       /* end of constant term */
00114     /* merge terms from le and re */
00115     else if ((le->op->arity != OP_NUM) && (re->op->arity != OP_NUM) &&
00116         (((TERM_NODE *)(le->left))->right==((TERM_NODE *)(re->left))->right)) {
00117         con = ((NUM_NODE *)(((TERM_NODE *)(le->left))->left))->value
00118             + ((NUM_NODE *)(((TERM_NODE *)(re->left))->left))->value;
00119         if (con != 0.0) {
00120             newt = (TERM_NODE *) node_new();
00121             if (pa) pa->right = (NODE *) newt;
00122             else answer = (NODE *) newt;
00123             pa = newt;
00124             pa->label = (NAME_NODE *) NULL;
00125             pa->op = le->op;
00126             pa->left = expr_copy(le->left);
00127             ((NUM_NODE *)(((TERM_NODE *)(pa->left))->left))->value = con;
00128             }
00129         le = (TERM_NODE *)(le->right);
00130         re = (TERM_NODE *)(re->right);
00131         }
00132     else {      /* next term in answer comes from le or re */
00133         newt = (TERM_NODE *) node_new();
00134         if (pa) pa->right = (NODE *) newt;
00135         else answer = (NODE *) newt;
00136         pa = newt;
00137         pa->label = (NAME_NODE *) NULL;
00138         if ((re->op->arity == OP_NUM) || (0 < strcmp(
00139         ((NAME_NODE *)(((TERM_NODE *)(le->left))->right))->pval,
00140         ((NAME_NODE *)(((TERM_NODE *)(re->left))->right))->pval) )) {   /* le */
00141             pa->op = le->op;    /* get ++ operator */
00142             pa->left = expr_copy(le->left);
00143             le = (TERM_NODE *)(le->right);
00144             }   /* end of term from le */
00145         else {  /* from re */
00146             pa->op = re->op;    /* get ++ operator */
00147             pa->left = expr_copy(re->left);
00148             re = (TERM_NODE *)(re->right);
00149             }   /* end of term from re */
00150         }
00151     }   /* end of forever */
00152 }
00153 
00154 /*****************************************************************
00155  *
00156  * Solve a linear equation.
00157  *
00158  * The argument must be an expression of the form:
00159  *      0 = lx'linear ; ex
00160  *
00161  * This routine walks the expression, and finds the variable (v) in
00162  * the linear expression lx that occurs furthest to the right in the
00163  * expression ex.  This (hopefully) finds the most "interesting"
00164  * variable in lx.  The linear expression lx is then solved for the
00165  * variable v, and the result bound as the value of v.  Finally,
00166  * the expression ex is returned.
00167  * Boundary conditions:
00168  * If there is only a single variable in lx, it is solved for.
00169  * If no variable in lx occurs in ex, then the variable with the
00170  * largest coefficient (in absolute value) is solved for.
00171  * If multiple variables have equally great coefficients, the one
00172  * with the name which occurs first alphabetically is solved for.
00173 
00174  * Solving would be more difficult (but not impossible) to implement
00175  * directly in Bertrand.  Here is some code to get you started.
00176  *
00177  *   0 = ((c**v'numvar) ++ rest'number) ; ex {
00178  *      (v is ((-1/c) * rest)) ; ex }
00179  *   (c'constant ** k'constant) ++ rest { (c*k) + rest }
00180  *   (c'constant ** (a ++ b)) ++ rest { (c*(a++b)) + rest }
00181  *
00182  *****************************************************************/
00183 NODE *
00184 ole_solve(exp)
00185 TERM_NODE *exp;
00186 {
00187 NODE *ex = expr_update(expr_copy(exp->right));
00188 NODE *lx = expr_update(((TERM_NODE *)(exp->left))->right);
00189 return ex;
00190 }

Generated on Fri Jan 25 09:58:43 2008 for Bertrand by  doxygen 1.5.4