root/trunk/backmath/backmath.d

Revision 177, 10.8 kB (checked in by BCS, 1 year ago)

More rules! If I haven't dropped a file in there somewhere this will now handle most single variable linear problems.

Line 
1 /***************
2     BackMath
3
4     Author: Benjamin Shropshire
5
6     Note:
7         If this library can't handle something you feed it it will spit out a
8         line with a message something like this:
9
10     "invalid types used for Sub: (- (*> a (-> (* e a) b)) (/> c (-> (/ d c) b)))"
11
12     If you want to help improve the library (and make it work in your case)
13     then you can add a rule to meta.lisp that will handle the case you are
14     running into. Here is an example of how to generate a rule for the above
15     case:
16
17     start with the given lisp s-expression
18
19     (- (*> a (-> (* e a) b)) (/> c (-> (/ d c) b)))
20
21     replace any known sections with new variables
22
23     (- (*> a (-> e b)) (/> c (-> d b)))
24
25     pull out and name any (_> ...) sections and replace them with the name
26
27     (- W T)
28     W = (*> a (-> e b))
29     T = (/> c (-> d b))
30
31     "Invert" the named expressions
32
33     (- W T)
34     (- (* W a) e) = b
35     (- (/ T c) d) = b
36
37     solve for the placeholders
38
39     (- W T)
40     W = (/ (+ b e) a)
41     T = (* (+ b d) c)
42
43     substitute back in
44
45     (- (/ (+ b e) a) (* (+ b d) c))
46
47     isolate the unknown (in this case "b")
48
49     (- (/ (+ b e) a) (* (+ b d) c))
50     (- (+ (/ b a) (/ e a)) (+ (* b c) (* d c)))
51     (- (- (+ (/ b a) (/ e a)) (* b c)) (* d c))
52     (- (+ (- (/ b a) (* b c)) (/ e a)) (* d c))
53     (- (+ (* b (- (/ 1 a) (* 1 c))) (/ e a)) (* d c))
54     (- (+ (* b (- (/ 1 a) c)) (/ e a)) (* d c))
55     (+ (+ (* b (- (/ 1 a) c)) (/ e a)) (- (* d c)))
56     (+ (* b (- (/ 1 a) c)) (/ e a) (- (* d c)))
57     (+ (* b (- (/ 1 a) c)) (- (/ e a) (* d c)))
58
59     solve for the unknown
60
61     y = (+ (* b (- (/ 1 a) c)) (- (/ e a) (* d c)))
62     (- y  (- (/ e a) (* d c))) = (* b (- (/ 1 a) c))
63     (/ (- y  (- (/ e a) (* d c))) (- (/ 1 a) c)) = b
64
65     convert to "(+,- (*,/ y a) b) = x" from
66
67     (/ (- y  (- (/ e a) (* d c))) (- (/ 1 a) c)) = b
68     (- (/ y (- (/ 1 a) c)) (/ (- (/ e a) (* d c)) (- (/ 1 a) c))) = b
69
70     convert to "assignment form"
71
72     (- (/ y (- (/ 1 a) c)) (/ (- (/ e a) (* d c)) (- (/ 1 a) c))) = b
73     (/ y (- (/ 1 a) c)) = (-> (/ (- (/ e a) (* d c)) (- (/ 1 a) c)) b)
74     y = (/> (- (/ 1 a) c) (-> (/ (- (/ e a) (* d c)) (- (/ 1 a) c)) b))
75
76     insert the new rule
77
78     (
79         (- (*> a (-> e b)) (/> c (-> d b)))
80         (/> (- (/ 1 a) c) (-> (/ (- (/ e a) (* d c)) (- (/ 1 a) c)) b))
81     )
82
83     in most cases meta.lisp should contain the original case or a generalization
84     of it.
85
86
87     Copywrite: You may used this code only if you accept all risk involved in
88     doing so. It is highly experimental and probably contains bugs. I DON'T
89     warrant it for any use.
90
91     Version: 0.001
92     Date: 12/4/2007
93 */
94
95 import std.stdio;
96
97
98 /* *****************************************************
99  * Formatting code shamelessly stolen from ddl.meta.conv
100  *
101  * Author: Don Clugston.
102  * License: Public domain.
103  */
104
105 /* *****************************************************
106  *  char [] fcvt!(real x)
107  *  Convert a real number x to %f format
108  */
109 template fcvt(real x)
110 {
111     static if (x<0) {
112         const real fcvt = "-" ~ .fcvt!(-x);
113     } else static if (x==cast(long)x) {
114         const char [] fcvt = itoa!(cast(long)x);
115     } else {
116         const char [] fcvt = itoa!(cast(long)x) ~ "." ~ chomp!(afterdec!(x - cast(long)x), '0');
117     }
118 }
119
120 template decimaldigit(int n) { const char [] decimaldigit = "0123456789"[n..n+1]; }
121
122 /* *****************************************************
123  *  char [] itoa!(long n);
124  */
125 template itoa(long n)
126 {
127     static if (n<0)
128         const char [] itoa = "-" ~ itoa!(-n);
129     else static if (n<10L)
130         const char [] itoa = decimaldigit!(n);
131     else
132         const char [] itoa = itoa!(n/10L) ~ decimaldigit!(n%10L);
133 }
134
135
136
137
138
139 // symboles for is(Type == Type) tests
140 // used like enums.
141 private struct Defined{}
142 private struct UnDefined{}
143
144 private struct CVal{}
145 private struct Term{}
146 private struct Add{}
147 private struct Sub{}
148 private struct Mul{}
149 private struct Div{}
150
151 private struct AddA{}
152 private struct SubA{}
153 private struct MulA{}
154 private struct DivA{}
155
156 private struct SubAR{}
157 private struct DivAR{}
158
159 private mixin(import("generated_rules.d"));
160
161 template Operate(T)
162 {
163     // this mixin is used so that the auto generated code need not be
164     // hard coded into the generation program
165     //
166     // If anyone has a better idea on how to do this, I'm open to sugestions
167     // Note: the code in generated_rules.d needs access to private memebers of
168     // this module.
169
170     TypeOfAdd!(T,V) opAdd(V)(V t) { TypeOfAdd!(T,V) ret; return ret; }
171     TypeOfSub!(T,V) opSub(V)(V t) { TypeOfSub!(T,V) ret; return ret; }
172     TypeOfMul!(T,V) opMul(V)(V t) { TypeOfMul!(T,V) ret; return ret; }
173     TypeOfDiv!(T,V) opDiv(V)(V t) { TypeOfDiv!(T,V) ret; return ret; }
174
175     void opAssign(V)(V t)
176     {
177         static if(is(T.DefP == Defined))
178         {
179             static assert(is(V.DefP == UnDefined));
180             V.set = T.get;
181         }
182         else
183         {
184             static if(is(V.DefP == Defined))
185                 T.set = V.get;
186             else
187             {
188 //              static assert(is(typeof(*this - t)), "Can't force equality of '"~typeof(*this).stringof~"' and '"~V.stringof~\');
189                 (*this - t).set = 0;
190             }
191         }
192     }
193 }
194
195 template Val(real r){Value!(r) Val;}
196 struct Value(real r)
197 {
198     private alias   Defined DefP; private alias CVal  Op;
199     static real get(){return r;}
200     mixin Operate!(typeof(*this));
201     const char[] LispOf = fcvt!(r);
202 }
203 struct DefinedT(alias _r)
204 {
205     private alias   Defined DefP; private alias Term  Op;
206     static real get(){return r;}
207     alias _r r;   mixin Operate!(typeof(*this));
208     const char[] LispOf = _r.stringof;
209 }
210 struct UnDefinedT(alias _r)
211 {
212     private alias UnDefined DefP; private alias Term  Op;
213     static void set(real v){r = v;}
214     alias _r r;   mixin Operate!(typeof(*this));
215     const char[] LispOf = _r.stringof;
216 }
217
218 struct OpAdd  (T, U)
219 {
220     private alias   Defined DefP; private alias Add   Op;
221     static real get(){ return T.get + U.get; }   
222     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
223     const char[] LispOf = "(+ "~LHS.LispOf~" "~RHS.LispOf~")";
224 }
225 struct OpSub  (T, U)
226 {
227     private alias   Defined DefP; private alias Sub   Op;
228     static real get(){ return T.get - U.get; }   
229     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
230     const char[] LispOf = "(- "~LHS.LispOf~" "~RHS.LispOf~")";
231 }
232 struct OpMul  (T, U)
233 {
234     private alias   Defined DefP; private alias Mul   Op;
235     static real get(){ return T.get * U.get; }   
236     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
237     const char[] LispOf = "(* "~LHS.LispOf~" "~RHS.LispOf~")";
238 }
239 struct OpDiv  (T, U)
240 {
241     private alias   Defined DefP; private alias Div   Op;
242     static real get(){ return T.get / U.get; }   
243     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
244     const char[] LispOf = "(/ "~LHS.LispOf~" "~RHS.LispOf~")";
245 }
246
247 struct OpAddA (T, U)
248 {
249     private alias UnDefined DefP; private alias AddA  Op;
250     static void set(real v){ U.set = v + T.get; }
251     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
252     const char[] LispOf = "(+> "~LHS.LispOf~" "~RHS.LispOf~")";
253 }
254 struct OpSubA (T, U)
255 {
256     private alias UnDefined DefP; private alias SubA  Op;
257     static void set(real v){ U.set = v - T.get; }
258     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
259     const char[] LispOf = "(-> "~LHS.LispOf~" "~RHS.LispOf~")";
260 }
261 struct OpSubAR(T, U)
262 {
263     private alias UnDefined DefP; private alias SubAR Op;
264     static void set(real v){ U.set = T.get - v; }
265     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
266     const char[] LispOf = "(-R> "~LHS.LispOf~" "~RHS.LispOf~")";
267 }
268 struct OpMulA (T, U)
269 {
270     private alias UnDefined DefP; private alias MulA  Op;
271     static void set(real v){ U.set = v * T.get; }
272     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
273     const char[] LispOf = "(*> "~LHS.LispOf~" "~RHS.LispOf~")";
274 }
275 struct OpDivA (T, U)
276 {
277     private alias UnDefined DefP; private alias DivA  Op;
278     static void set(real v){ U.set = v / T.get; }
279     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
280     const char[] LispOf = "(/> "~LHS.LispOf~" "~RHS.LispOf~")";
281 }
282 struct OpDivAR(T, U)
283 {
284     private alias UnDefined DefP; private alias DivAR Op;
285     static void set(real v){ U.set = T.get / v; }
286     mixin Operate!(typeof(*this)); alias T LHS; alias U RHS;
287     const char[] LispOf = "(/R> "~LHS.LispOf~" "~RHS.LispOf~")";
288 }
289
290
291 real a, b, c, d, e, f, g;
292
293 void main(){Unittest();}
294
295
296 //unittest
297 void Unittest()
298 {
299     DefinedT!(a)   A;
300     UnDefinedT!(b) B;
301     DefinedT!(c)   C;
302     DefinedT!(d)   D;
303     DefinedT!(e)   E;
304     DefinedT!(f)   F;
305     DefinedT!(g)   G;
306     Value!(0)      Z;
307
308     a=1;
309     c=2;
310     d=3;
311
312     A + B - D = C; // 1 + b - 3 = 2; -> 4
313     assert(b == 4);
314
315     A - B - D = C; // 1 - b - 3 = 2; -> -4
316     assert(b == -4);
317
318     A - D - B = C; // 1 - 3 - b = 2; -> -4
319     assert(b == -4);
320
321     (B - A) - D = C; // b - 1 - 3 = 2; -> 6
322     assert(b == 6);
323
324     A - D - B - D = C; // 1 - 3 - b - 3 = 2; -> -7
325     assert(b == -7);
326
327     A - B - (D + D) = C; // 1 - b - (3 + 3) = 2; -> -7
328     assert(b == -7);
329
330     a=3;
331     C = A + B - D; // 2 = 3 + b - 3; -> 2
332     assert(b == 2);
333
334     C = B * A; // 2 = b * 3; -> 2/3
335     writef("%s == (2/3)\n", b);
336
337     C = B * A + B * D; // 2 = b*3 + b*3; -> 1/3
338     writef("%s == (1/3)\n", b);
339
340     A / B  + D / B = C; // 2 = 3/B + 3/B; -> 6/2
341     writef("%s == (6/2)\n", b);
342
343     B / A = (B / C) + D; // B / 3 = B / 2 + 3; -> -18
344     writef("%s == -18\n", b);
345
346     (B * A) + E = (B * C) + D;
347     (B / A) + E = (B * C) + D;
348     (B * A) + E = (B / C) + D;
349     (B / A) + E = (B / C) + D;
350
351     (B * A) = (B * C) + D; // B * 3 = B * 2 + 3; -> 3
352     writef("%s == 3\n", b);
353     (B / A) = (B * C) + D;
354     (B * A) = (B / C) + D;
355     (B / A) = (B / C) + D;
356
357     (B * A) + E = (B * C);
358     (B / A) + E = (B * C);
359     (B * A) + E = (B / C);
360     (B / A) + E = (B / C);
361
362     (B * A) - E = (B * C) - D;
363     (B / A) - E = (B * C) - D;
364     (B * A) - E = (B / C) - D;
365     (B / A) - E = (B / C) - D;
366
367     (B * A) = (B * C) - D;
368     (B / A) = (B * C) - D;
369     (B * A) = (B / C) - D;
370     (B / A) = (B / C) - D;
371
372     (B * A) - E = (B * C);
373     (B / A) - E = (B * C);
374     (B * A) - E = (B / C);
375     (B / A) - E = (B / C);
376
377     (B * A) = (B * C);
378     (B / A) = (B * C);
379     (B * A) = (B / C);
380     (B / A) = (B / C);
381
382     Z = (B * A) + E + ((B * C) + D);
383     Z = (B / A) + E + ((B * C) + D);
384     Z = (B * A) + E + ((B / C) + D);
385     Z = (B / A) + E + ((B / C) + D);
386
387     Z = (B * A) + ((B * C) + D);
388     Z = (B / A) + ((B * C) + D);
389     Z = (B * A) + ((B / C) + D);
390     Z = (B / A) + ((B / C) + D);
391
392     Z = (B * A) + E + (B * C);
393     Z = (B / A) + E + (B * C);
394     Z = (B * A) + E + (B / C);
395     Z = (B / A) + E + (B / C);
396
397     Z = (B * A) - E + ((B * C) - D);
398     Z = (B / A) - E + ((B * C) - D);
399     Z = (B * A) - E + ((B / C) - D);
400     Z = (B / A) - E + ((B / C) - D);
401
402     Z = (B * A) + ((B * C) - D);
403     Z = (B / A) + ((B * C) - D);
404     Z = (B * A) + ((B / C) - D);
405     Z = (B / A) + ((B / C) - D);
406
407     Z = (B * A) - E + (B * C);
408     Z = (B / A) - E + (B * C);
409     Z = (B * A) - E + (B / C);
410     Z = (B / A) - E + (B / C);
411
412     Z = (B * A) + (B * C);
413     Z = (B / A) + (B * C);
414     Z = (B * A) + (B / C);
415     Z = (B / A) + (B / C);
416
417     Z = B + (B*A + D);
418     Z = B + (B/A + D);
419     Z = B + (B*A - D);
420     Z = B + (B/A - D);
421     Z = B - (B*A + D);
422     Z = B - (B/A + D);
423     Z = B - (B*A - D);
424     Z = B - (B/A - D);
425
426 }
Note: See TracBrowser for help on using the browser.