multiply.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. // Symbolic multiplication
  2. #include "stdafx.h"
  3. #include "defs.h"
  4. extern void append(void);
  5. static void parse_p1(void);
  6. static void parse_p2(void);
  7. static void __normalize_radical_factors(int);
  8. void
  9. multiply(void)
  10. {
  11. if (esc_flag)
  12. stop("escape key stop");
  13. if (isnum(stack[tos - 2]) && isnum(stack[tos - 1]))
  14. multiply_numbers();
  15. else {
  16. save();
  17. yymultiply();
  18. restore();
  19. }
  20. }
  21. void
  22. yymultiply(void)
  23. {
  24. int h, i, n;
  25. // pop operands
  26. p2 = pop();
  27. p1 = pop();
  28. h = tos;
  29. // is either operand zero?
  30. if (iszero(p1) || iszero(p2)) {
  31. push(zero);
  32. return;
  33. }
  34. // is either operand a sum?
  35. if (expanding && isadd(p1)) {
  36. p1 = cdr(p1);
  37. push(zero);
  38. while (iscons(p1)) {
  39. push(car(p1));
  40. push(p2);
  41. multiply();
  42. add();
  43. p1 = cdr(p1);
  44. }
  45. return;
  46. }
  47. if (expanding && isadd(p2)) {
  48. p2 = cdr(p2);
  49. push(zero);
  50. while (iscons(p2)) {
  51. push(p1);
  52. push(car(p2));
  53. multiply();
  54. add();
  55. p2 = cdr(p2);
  56. }
  57. return;
  58. }
  59. // scalar times tensor?
  60. if (!istensor(p1) && istensor(p2)) {
  61. push(p1);
  62. push(p2);
  63. scalar_times_tensor();
  64. return;
  65. }
  66. // tensor times scalar?
  67. if (istensor(p1) && !istensor(p2)) {
  68. push(p1);
  69. push(p2);
  70. tensor_times_scalar();
  71. return;
  72. }
  73. // adjust operands
  74. if (car(p1) == symbol(MULTIPLY))
  75. p1 = cdr(p1);
  76. else {
  77. push(p1);
  78. list(1);
  79. p1 = pop();
  80. }
  81. if (car(p2) == symbol(MULTIPLY))
  82. p2 = cdr(p2);
  83. else {
  84. push(p2);
  85. list(1);
  86. p2 = pop();
  87. }
  88. // handle numerical coefficients
  89. if (isnum(car(p1)) && isnum(car(p2))) {
  90. push(car(p1));
  91. push(car(p2));
  92. multiply_numbers();
  93. p1 = cdr(p1);
  94. p2 = cdr(p2);
  95. } else if (isnum(car(p1))) {
  96. push(car(p1));
  97. p1 = cdr(p1);
  98. } else if (isnum(car(p2))) {
  99. push(car(p2));
  100. p2 = cdr(p2);
  101. } else
  102. push(one);
  103. parse_p1();
  104. parse_p2();
  105. while (iscons(p1) && iscons(p2)) {
  106. // if (car(p1)->gamma && car(p2)->gamma) {
  107. // combine_gammas(h);
  108. // p1 = cdr(p1);
  109. // p2 = cdr(p2);
  110. // parse_p1();
  111. // parse_p2();
  112. // continue;
  113. // }
  114. if (caar(p1) == symbol(OPERATOR) && caar(p2) == symbol(OPERATOR)) {
  115. push_symbol(OPERATOR);
  116. push(cdar(p1));
  117. push(cdar(p2));
  118. append();
  119. cons();
  120. p1 = cdr(p1);
  121. p2 = cdr(p2);
  122. parse_p1();
  123. parse_p2();
  124. continue;
  125. }
  126. switch (cmp_expr(p3, p4)) {
  127. case -1:
  128. push(car(p1));
  129. p1 = cdr(p1);
  130. parse_p1();
  131. break;
  132. case 1:
  133. push(car(p2));
  134. p2 = cdr(p2);
  135. parse_p2();
  136. break;
  137. case 0:
  138. combine_factors(h);
  139. p1 = cdr(p1);
  140. p2 = cdr(p2);
  141. parse_p1();
  142. parse_p2();
  143. break;
  144. default:
  145. stop("internal error 2");
  146. break;
  147. }
  148. }
  149. // push remaining factors, if any
  150. while (iscons(p1)) {
  151. push(car(p1));
  152. p1 = cdr(p1);
  153. }
  154. while (iscons(p2)) {
  155. push(car(p2));
  156. p2 = cdr(p2);
  157. }
  158. // normalize radical factors
  159. // example: 2*2(-1/2) -> 2^(1/2)
  160. // must be done after merge because merge may produce radical
  161. // example: 2^(1/2-a)*2^a -> 2^(1/2)
  162. __normalize_radical_factors(h);
  163. // this hack should not be necessary, unless power returns a multiply
  164. //for (i = h; i < tos; i++) {
  165. // if (car(stack[i]) == symbol(MULTIPLY)) {
  166. // multiply_all(tos - h);
  167. // return;
  168. // }
  169. //}
  170. if (expanding) {
  171. for (i = h; i < tos; i++) {
  172. if (isadd(stack[i])) {
  173. multiply_all(tos - h);
  174. return;
  175. }
  176. }
  177. }
  178. // n is the number of result factors on the stack
  179. n = tos - h;
  180. if (n == 1)
  181. return;
  182. // discard integer 1
  183. if (isrational(stack[h]) && equaln(stack[h], 1)) {
  184. if (n == 2) {
  185. p7 = pop();
  186. pop();
  187. push(p7);
  188. } else {
  189. stack[h] = symbol(MULTIPLY);
  190. list(n);
  191. }
  192. return;
  193. }
  194. list(n);
  195. p7 = pop();
  196. push_symbol(MULTIPLY);
  197. push(p7);
  198. cons();
  199. }
  200. // Decompose a factor into base and power.
  201. //
  202. // input: car(p1) factor
  203. //
  204. // output: p3 factor's base
  205. //
  206. // p5 factor's power (possibly 1)
  207. static void
  208. parse_p1(void)
  209. {
  210. p3 = car(p1);
  211. p5 = one;
  212. if (car(p3) == symbol(POWER)) {
  213. p5 = caddr(p3);
  214. p3 = cadr(p3);
  215. }
  216. }
  217. // Decompose a factor into base and power.
  218. //
  219. // input: car(p2) factor
  220. //
  221. // output: p4 factor's base
  222. //
  223. // p6 factor's power (possibly 1)
  224. static void
  225. parse_p2(void)
  226. {
  227. p4 = car(p2);
  228. p6 = one;
  229. if (car(p4) == symbol(POWER)) {
  230. p6 = caddr(p4);
  231. p4 = cadr(p4);
  232. }
  233. }
  234. void
  235. combine_factors(int h)
  236. {
  237. push(p4);
  238. push(p5);
  239. push(p6);
  240. add();
  241. power();
  242. p7 = pop();
  243. if (isnum(p7)) {
  244. push(stack[h]);
  245. push(p7);
  246. multiply_numbers();
  247. stack[h] = pop();
  248. } else if (car(p7) == symbol(MULTIPLY)) {
  249. // power can return number * factor (i.e. -1 * i)
  250. if (isnum(cadr(p7)) && cdddr(p7) == symbol(NIL)) {
  251. push(stack[h]);
  252. push(cadr(p7));
  253. multiply_numbers();
  254. stack[h] = pop();
  255. push(caddr(p7));
  256. } else
  257. push(p7);
  258. } else
  259. push(p7);
  260. }
  261. int gp[17][17] = {
  262. {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  263. {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  264. {0,0,1,-6,-7,-8,-3,-4,-5,13,14,15,-16,9,10,11,-12},
  265. {0,0,6,-1,-11,10,-2,-15,14,12,-5,4,-9,16,-8,7,-13},
  266. {0,0,7,11,-1,-9,15,-2,-13,5,12,-3,-10,8,16,-6,-14},
  267. {0,0,8,-10,9,-1,-14,13,-2,-4,3,12,-11,-7,6,16,-15},
  268. {0,0,3,2,15,-14,1,11,-10,16,-8,7,13,12,-5,4,9},
  269. {0,0,4,-15,2,13,-11,1,9,8,16,-6,14,5,12,-3,10},
  270. {0,0,5,14,-13,2,10,-9,1,-7,6,16,15,-4,3,12,11},
  271. {0,0,13,12,-5,4,16,-8,7,-1,-11,10,-3,-2,-15,14,-6},
  272. {0,0,14,5,12,-3,8,16,-6,11,-1,-9,-4,15,-2,-13,-7},
  273. {0,0,15,-4,3,12,-7,6,16,-10,9,-1,-5,-14,13,-2,-8},
  274. {0,0,16,-9,-10,-11,-13,-14,-15,-3,-4,-5,1,-6,-7,-8,2},
  275. {0,0,9,-16,8,-7,-12,5,-4,-2,-15,14,6,-1,-11,10,3},
  276. {0,0,10,-8,-16,6,-5,-12,3,15,-2,-13,7,11,-1,-9,4},
  277. {0,0,11,7,-6,-16,4,-3,-12,-14,13,-2,8,-10,9,-1,5},
  278. {0,0,12,13,14,15,9,10,11,-6,-7,-8,-2,-3,-4,-5,-1}
  279. };
  280. #if 0
  281. static void
  282. combine_gammas(int h)
  283. {
  284. int n;
  285. n = gp[(int) p1->gamma][(int) p2->gamma];
  286. if (n < 0) {
  287. n = -n;
  288. push(stack[h]);
  289. negate();
  290. stack[h] = pop();
  291. }
  292. if (n > 1)
  293. push(_gamma[n]);
  294. }
  295. #endif
  296. void
  297. multiply_noexpand(void)
  298. {
  299. int x;
  300. x = expanding;
  301. expanding = 0;
  302. multiply();
  303. expanding = x;
  304. }
  305. // multiply n factors on stack
  306. void
  307. multiply_all(int n)
  308. {
  309. int h, i;
  310. if (n == 1)
  311. return;
  312. if (n == 0) {
  313. push(one);
  314. return;
  315. }
  316. h = tos - n;
  317. push(stack[h]);
  318. for (i = 1; i < n; i++) {
  319. push(stack[h + i]);
  320. multiply();
  321. }
  322. stack[h] = pop();
  323. tos = h + 1;
  324. }
  325. void
  326. multiply_all_noexpand(int n)
  327. {
  328. int x;
  329. x = expanding;
  330. expanding = 0;
  331. multiply_all(n);
  332. expanding = x;
  333. }
  334. //-----------------------------------------------------------------------------
  335. //
  336. // Symbolic division
  337. //
  338. // Input: Dividend and divisor on stack
  339. //
  340. // Output: Quotient on stack
  341. //
  342. //-----------------------------------------------------------------------------
  343. void
  344. divide(void)
  345. {
  346. if (isnum(stack[tos - 2]) && isnum(stack[tos - 1]))
  347. divide_numbers();
  348. else {
  349. inverse();
  350. multiply();
  351. }
  352. }
  353. void
  354. inverse(void)
  355. {
  356. if (isnum(stack[tos - 1]))
  357. invert_number();
  358. else {
  359. push_integer(-1);
  360. power();
  361. }
  362. }
  363. void
  364. reciprocate(void)
  365. {
  366. if (isnum(stack[tos - 1]))
  367. invert_number();
  368. else {
  369. push_integer(-1);
  370. power();
  371. }
  372. }
  373. void
  374. negate(void)
  375. {
  376. if (isnum(stack[tos - 1]))
  377. negate_number();
  378. else {
  379. push_integer(-1);
  380. multiply();
  381. }
  382. }
  383. void
  384. negate_expand(void)
  385. {
  386. int x;
  387. x = expanding;
  388. expanding = 1;
  389. negate();
  390. expanding = x;
  391. }
  392. void
  393. negate_noexpand(void)
  394. {
  395. int x;
  396. x = expanding;
  397. expanding = 0;
  398. negate();
  399. expanding = x;
  400. }
  401. //-----------------------------------------------------------------------------
  402. //
  403. // Normalize radical factors
  404. //
  405. // Input: stack[h] Coefficient factor, possibly 1
  406. //
  407. // stack[h + 1] Second factor
  408. //
  409. // stack[tos - 1] Last factor
  410. //
  411. // Output: Reduced coefficent and normalized radicals (maybe)
  412. //
  413. // Example: 2*2^(-1/2) -> 2^(1/2)
  414. //
  415. // (power number number) is guaranteed to have the following properties:
  416. //
  417. // 1. Base is an integer
  418. //
  419. // 2. Absolute value of exponent < 1
  420. //
  421. // These properties are assured by the power function.
  422. //
  423. //-----------------------------------------------------------------------------
  424. #define A p1
  425. #define B p2
  426. #define BASE p3
  427. #define EXPO p4
  428. #define TMP p5
  429. static int __is_radical_number(U *);
  430. static void
  431. __normalize_radical_factors(int h)
  432. {
  433. int i;
  434. // if coeff is 1 or floating then don't bother
  435. if (isplusone(stack[h]) || isminusone(stack[h]) || isdouble(stack[h]))
  436. return;
  437. // if no radicals then don't bother
  438. for (i = h + 1; i < tos; i++)
  439. if (__is_radical_number(stack[i]))
  440. break;
  441. if (i == tos)
  442. return;
  443. // ok, try to simplify
  444. save();
  445. // numerator
  446. push(stack[h]);
  447. mp_numerator();
  448. A = pop();
  449. for (i = h + 1; i < tos; i++) {
  450. if (isplusone(A) || isminusone(A))
  451. break;
  452. if (!__is_radical_number(stack[i]))
  453. continue;
  454. BASE = cadr(stack[i]);
  455. EXPO = caddr(stack[i]);
  456. // exponent must be negative
  457. if (!isnegativenumber(EXPO))
  458. continue;
  459. // numerator divisible by BASE?
  460. push(A);
  461. push(BASE);
  462. divide();
  463. TMP = pop();
  464. if (!isinteger(TMP))
  465. continue;
  466. // reduce numerator
  467. A = TMP;
  468. // invert radical
  469. push_symbol(POWER);
  470. push(BASE);
  471. push(one);
  472. push(EXPO);
  473. add();
  474. list(3);
  475. stack[i] = pop();
  476. }
  477. // denominator
  478. push(stack[h]);
  479. mp_denominator();
  480. B = pop();
  481. for (i = h + 1; i < tos; i++) {
  482. if (isplusone(B))
  483. break;
  484. if (!__is_radical_number(stack[i]))
  485. continue;
  486. BASE = cadr(stack[i]);
  487. EXPO = caddr(stack[i]);
  488. // exponent must be positive
  489. if (isnegativenumber(EXPO))
  490. continue;
  491. // denominator divisible by BASE?
  492. push(B);
  493. push(BASE);
  494. divide();
  495. TMP = pop();
  496. if (!isinteger(TMP))
  497. continue;
  498. // reduce denominator
  499. B = TMP;
  500. // invert radical
  501. push_symbol(POWER);
  502. push(BASE);
  503. push(EXPO);
  504. push(one);
  505. subtract();
  506. list(3);
  507. stack[i] = pop();
  508. }
  509. // reconstitute the coefficient
  510. push(A);
  511. push(B);
  512. divide();
  513. stack[h] = pop();
  514. restore();
  515. }
  516. // don't include i
  517. static int
  518. __is_radical_number(U *p)
  519. {
  520. // don't use i
  521. if (car(p) == symbol(POWER) && isnum(cadr(p)) && isnum(caddr(p)) && !isminusone(cadr(p)))
  522. return 1;
  523. else
  524. return 0;
  525. }
  526. //-----------------------------------------------------------------------------
  527. //
  528. // > a*hilbert(2)
  529. // ((a,1/2*a),(1/2*a,1/3*a))
  530. //
  531. // Note that "a" is presumed to be a scalar. Is this correct?
  532. //
  533. // Yes, because "*" has no meaning if "a" is a tensor.
  534. // To multiply tensors, "dot" or "outer" should be used.
  535. //
  536. // > dot(a,hilbert(2))
  537. // dot(a,((1,1/2),(1/2,1/3)))
  538. //
  539. // In this case "a" could be a scalar or tensor so the result is not
  540. // expanded.
  541. //
  542. //-----------------------------------------------------------------------------
  543. #if SELFTEST
  544. static char *s[] = {
  545. "0*a",
  546. "0",
  547. "a*0",
  548. "0",
  549. "1*a",
  550. "a",
  551. "a*1",
  552. "a",
  553. "a*a",
  554. "a^2",
  555. "a^2*a",
  556. "a^3",
  557. "a*a^2",
  558. "a^3",
  559. "a^2*a^2",
  560. "a^4",
  561. "2^a*2^(3-a)", // symbolic exponents cancel
  562. "8",
  563. "sqrt(2)/2",
  564. "2^(-1/2)",
  565. "2/sqrt(2)",
  566. "2^(1/2)",
  567. "-sqrt(2)/2",
  568. "-1/(2^(1/2))",
  569. "2^(1/2-a)*2^a/10",
  570. "1/(5*2^(1/2))",
  571. "i/4",
  572. "1/4*i",
  573. "1/(4 i)",
  574. "-1/4*i",
  575. // ensure 1.0 is not discarded
  576. "1.0 pi 1/2",
  577. "0.5*pi",
  578. "1.0 1/2 pi",
  579. "0.5*pi",
  580. };
  581. void
  582. test_multiply(void)
  583. {
  584. test(__FILE__, s, sizeof s / sizeof (char *));
  585. }
  586. #endif