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 }
1.5.4