home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume27 / calc-2.9.0 / part06 < prev    next >
Encoding:
Text File  |  1993-12-07  |  59.1 KB  |  2,521 lines

  1. Newsgroups: comp.sources.unix
  2. From: dbell@canb.auug.org.au (David I. Bell)
  3. Subject: v27i133: calc-2.9.0 - arbitrary precision C-like programmable calculator, Part06/19
  4. References: <1.755316719.21314@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: dbell@canb.auug.org.au (David I. Bell)
  9. Posting-Number: Volume 27, Issue 133
  10. Archive-Name: calc-2.9.0/part06
  11.  
  12. #!/bin/sh
  13. # this is part 6 of a multipart archive
  14. # do not concatenate these parts, unpack them in order with /bin/sh
  15. # file calc2.9.0/lint.sed continued
  16. #
  17. CurArch=6
  18. if test ! -r s2_seq_.tmp
  19. then echo "Please unpack part 1 first!"
  20.      exit 1; fi
  21. ( read Scheck
  22.   if test "$Scheck" != $CurArch
  23.   then echo "Please unpack part $Scheck next!"
  24.        exit 1;
  25.   else exit 0; fi
  26. ) < s2_seq_.tmp || exit 1
  27. echo "x - Continuing file calc2.9.0/lint.sed"
  28. sed 's/^X//' << 'SHAR_EOF' >> calc2.9.0/lint.sed
  29. X/: warning: possible pointer alignment problem$/d
  30. X/^Lint pass[0-9][0-9]*:$/d
  31. X/^[a-zA-Z][a-zA-Z0-9_-]*\.c:[     ]*$/d
  32. X/^addglobal, arg\. 2 used inconsistently[     ]/d
  33. X/^addopptr, arg\. 2 used inconsistently[     ]/d
  34. X/^codegen\.c([0-9]*):getassignment returns value which is sometimes ignored$/d
  35. X/^errno used([     ]*func\.c([0-9]*)[     ]*), but not defined$/d
  36. X/^exit value declared inconsistently[     ]/d
  37. X/^fclose returns value which is sometimes ignored$/d
  38. X/^fflush returns value which is always ignored$/d
  39. X/^fprintf returns value which is always ignored$/d
  40. X/^fputc returns value which is always ignored$/d
  41. X/^fputs returns value which is always ignored$/d
  42. X/^free, arg\. 1 used inconsistently[     ]/d
  43. X/^geteuid value declared inconsistently[     ]/d
  44. X/^geteuid value used inconsistently[     ]/d
  45. X/^getpwuid, arg\. 1 used inconsistently[     ]/d
  46. X/^malloc, arg\. 1 used inconsistently[     ]/d
  47. X/^math_setdigits returns value which is always ignored$/d
  48. X/^math_setmode returns value which is sometimes ignored$/d
  49. X/^memcpy returns value which is always ignored$/d
  50. X/^memcpy value declared inconsistently[     ]/d
  51. X/^memcpy, arg\. [1-3] used inconsistently[     ]/d
  52. X/^memset value declared inconsistently[     ]/d
  53. X/^printf returns value which is always ignored$/d
  54. X/^putc returns value which is always ignored$/d
  55. X/^qcfappr, arg\. 2 used inconsistently[     ]/d
  56. X/^realloc, arg\. [1-2] used inconsistently[     ]/d
  57. X/^sprintf returns value which is always ignored/d
  58. X/^strcat returns value which is always ignored/d
  59. X/^strcpy returns value which is always ignored/d
  60. X/^strncpy returns value which is always ignored/d
  61. X/^strncpy, arg\. [1-3] used inconsistently[     ]/d
  62. X/^system returns value which is always ignored/d
  63. X/^times returns value which is always ignored/d
  64. X/^vsprintf returns value which is always ignored/d
  65. SHAR_EOF
  66. echo "File calc2.9.0/lint.sed is complete"
  67. chmod 0644 calc2.9.0/lint.sed || echo "restore of calc2.9.0/lint.sed fails"
  68. set `wc -c calc2.9.0/lint.sed`;Sum=$1
  69. if test "$Sum" != "1807"
  70. then echo original size 1807, current size $Sum;fi
  71. echo "x - extracting calc2.9.0/listfunc.c (Text)"
  72. sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/listfunc.c &&
  73. X/*
  74. X * Copyright (c) 1993 David I. Bell
  75. X * Permission is granted to use, distribute, or modify this source,
  76. X * provided that this copyright notice remains intact.
  77. X *
  78. X * List handling routines.
  79. X * Lists can be composed of any types of values, mixed if desired.
  80. X * Lists are doubly linked so that elements can be inserted or
  81. X * deleted efficiently at any point in the list.  A pointer is
  82. X * kept to the most recently indexed element so that sequential
  83. X * accesses are fast.
  84. X */
  85. X
  86. X#include "value.h"
  87. X
  88. X
  89. Xstatic LISTELEM *elemalloc MATH_PROTO((void));
  90. Xstatic LISTELEM *listelement MATH_PROTO((LIST *lp, long index));
  91. Xstatic void elemfree MATH_PROTO((LISTELEM *ep));
  92. Xstatic void removelistelement MATH_PROTO((LIST *lp, LISTELEM *ep));
  93. X
  94. X
  95. X/*
  96. X * Free lists for list headers and list elements.
  97. X */
  98. Xstatic FREELIST    headerfreelist = {
  99. X    sizeof(LIST),        /* size of list header */
  100. X    20            /* number of free headers to keep */
  101. X};
  102. X
  103. Xstatic FREELIST elementfreelist = {
  104. X    sizeof(LISTELEM),    /* size of list element */
  105. X    1000            /* number of free list elements to keep */
  106. X};
  107. X
  108. X
  109. X/*
  110. X * Insert an element before the first element of a list.
  111. X */
  112. Xvoid
  113. Xinsertlistfirst(lp, vp)
  114. X    LIST *lp;        /* list to put element onto */
  115. X    VALUE *vp;        /* value to be inserted */
  116. X{
  117. X    LISTELEM *ep;        /* list element */
  118. X
  119. X    ep = elemalloc();
  120. X    copyvalue(vp, &ep->e_value);
  121. X    if (lp->l_count == 0)
  122. X        lp->l_last = ep;
  123. X    else {
  124. X        lp->l_cacheindex++;
  125. X        lp->l_first->e_prev = ep;
  126. X        ep->e_next = lp->l_first;
  127. X    }
  128. X    lp->l_first = ep;
  129. X    lp->l_count++;
  130. X}
  131. X
  132. X
  133. X/*
  134. X * Insert an element after the last element of a list.
  135. X */
  136. Xvoid
  137. Xinsertlistlast(lp, vp)
  138. X    LIST *lp;        /* list to put element onto */
  139. X    VALUE *vp;        /* value to be inserted */
  140. X{
  141. X    LISTELEM *ep;        /* list element */
  142. X
  143. X    ep = elemalloc();
  144. X    copyvalue(vp, &ep->e_value);
  145. X    if (lp->l_count == 0)
  146. X        lp->l_first = ep;
  147. X    else {
  148. X        lp->l_last->e_next = ep;
  149. X        ep->e_prev = lp->l_last;
  150. X    }
  151. X    lp->l_last = ep;
  152. X    lp->l_count++;
  153. X}
  154. X
  155. X
  156. X/*
  157. X * Insert an element into the middle of list at the given index (zero based).
  158. X * The specified index will select the new element, so existing elements
  159. X * at or beyond the index will be shifted down one position.  It is legal
  160. X * to specify an index which is right at the end of the list, in which
  161. X * case the element is appended to the list.
  162. X */
  163. Xvoid
  164. Xinsertlistmiddle(lp, index, vp)
  165. X    LIST *lp;        /* list to put element onto */
  166. X    long index;        /* element number to insert in front of */
  167. X    VALUE *vp;        /* value to be inserted */
  168. X{
  169. X    LISTELEM *ep;        /* list element */
  170. X    LISTELEM *oldep;    /* old list element at desired index */
  171. X
  172. X    if (index == 0) {
  173. X        insertlistfirst(lp, vp);
  174. X        return;
  175. X    }
  176. X    if (index == lp->l_count) {
  177. X        insertlistlast(lp, vp);
  178. X        return;
  179. X    }
  180. X    oldep = NULL;
  181. X    if ((index >= 0) && (index < lp->l_count))
  182. X        oldep = listelement(lp, index);
  183. X    if (oldep == NULL)
  184. X        math_error("Index out of bounds for list insertion");
  185. X    ep = elemalloc();
  186. X    copyvalue(vp, &ep->e_value);
  187. X    ep->e_next = oldep;
  188. X    ep->e_prev = oldep->e_prev;
  189. X    ep->e_prev->e_next = ep;
  190. X    oldep->e_prev = ep;
  191. X    lp->l_cache = ep;
  192. X    lp->l_cacheindex = index;
  193. X    lp->l_count++;
  194. X}
  195. X
  196. X
  197. X/*
  198. X * Remove the first element from a list, returning its value.
  199. X * Returns the null value if no more elements exist.
  200. X */
  201. Xvoid
  202. Xremovelistfirst(lp, vp)
  203. X    LIST *lp;        /* list to have element removed */
  204. X    VALUE *vp;        /* location of the value */
  205. X{
  206. X    if (lp->l_count == 0) {
  207. X        vp->v_type = V_NULL;
  208. X        return;
  209. X    }
  210. X    *vp = lp->l_first->e_value;
  211. X    lp->l_first->e_value.v_type = V_NULL;
  212. X    removelistelement(lp, lp->l_first);
  213. X}
  214. X
  215. X
  216. X/*
  217. X * Remove the last element from a list, returning its value.
  218. X * Returns the null value if no more elements exist.
  219. X */
  220. Xvoid
  221. Xremovelistlast(lp, vp)
  222. X    LIST *lp;        /* list to have element removed */
  223. X    VALUE *vp;        /* location of the value */
  224. X{
  225. X    if (lp->l_count == 0) {
  226. X        vp->v_type = V_NULL;
  227. X        return;
  228. X    }
  229. X    *vp = lp->l_last->e_value;
  230. X    lp->l_last->e_value.v_type = V_NULL;
  231. X    removelistelement(lp, lp->l_last);
  232. X}
  233. X
  234. X
  235. X/*
  236. X * Remove the element with the given index from a list, returning its value.
  237. X */
  238. Xvoid
  239. Xremovelistmiddle(lp, index, vp)
  240. X    LIST *lp;        /* list to have element removed */
  241. X    long index;        /* list element to be removed */
  242. X    VALUE *vp;        /* location of the value */
  243. X{
  244. X    LISTELEM *ep;        /* element being removed */
  245. X
  246. X    ep = NULL;
  247. X    if ((index >= 0) && (index < lp->l_count))
  248. X        ep = listelement(lp, index);
  249. X    if (ep == NULL)
  250. X        math_error("Index out of bounds for list deletion");
  251. X    *vp = ep->e_value;
  252. X    ep->e_value.v_type = V_NULL;
  253. X    removelistelement(lp, ep);
  254. X}
  255. X
  256. X
  257. X/*
  258. X * Remove an arbitrary element from a list.
  259. X * The value contained in the element is freed.
  260. X */
  261. Xstatic void
  262. Xremovelistelement(lp, ep)
  263. X    register LIST *lp;        /* list header */
  264. X    register LISTELEM *ep;        /* list element to remove */
  265. X{
  266. X    if ((ep == lp->l_cache) || ((ep != lp->l_first) && (ep != lp->l_last)))
  267. X        lp->l_cache = NULL;
  268. X    if (ep->e_next)
  269. X        ep->e_next->e_prev = ep->e_prev;
  270. X    if (ep->e_prev)
  271. X        ep->e_prev->e_next = ep->e_next;
  272. X    if (ep == lp->l_first) {
  273. X        lp->l_first = ep->e_next;
  274. X        lp->l_cacheindex--;
  275. X    }
  276. X    if (ep == lp->l_last)
  277. X        lp->l_last = ep->e_prev;
  278. X    lp->l_count--;
  279. X    elemfree(ep);
  280. X}
  281. X
  282. X
  283. X/*
  284. X * Search a list for the specified value starting at the specified index.
  285. X * Returns the element number (zero based) of the found value, or -1 if
  286. X * the value was not found.
  287. X */
  288. Xlong
  289. Xlistsearch(lp, vp, index)
  290. X    LIST *lp;
  291. X    VALUE *vp;
  292. X    long index;
  293. X{
  294. X    register LISTELEM *ep;
  295. X
  296. X    if (index < 0)
  297. X        index = 0;
  298. X    ep = listelement(lp, index);
  299. X    while (ep) {
  300. X        if (!comparevalue(&ep->e_value, vp)) {
  301. X            lp->l_cache = ep;
  302. X            lp->l_cacheindex = index;
  303. X            return index;
  304. X        }
  305. X        ep = ep->e_next;
  306. X        index++;
  307. X    }
  308. X    return -1;
  309. X}
  310. X
  311. X
  312. X/*
  313. X * Search a list backwards for the specified value starting at the
  314. X * specified index.  Returns the element number (zero based) of the
  315. X * found value, or -1 if the value was not found.
  316. X */
  317. Xlong
  318. Xlistrsearch(lp, vp, index)
  319. X    LIST *lp;
  320. X    VALUE *vp;
  321. X    long index;
  322. X{
  323. X    register LISTELEM *ep;
  324. X
  325. X    if (index >= lp->l_count)
  326. X        index = lp->l_count - 1;
  327. X    ep = listelement(lp, index);
  328. X    while (ep) {
  329. X        if (!comparevalue(&ep->e_value, vp)) {
  330. X            lp->l_cache = ep;
  331. X            lp->l_cacheindex = index;
  332. X            return index;
  333. X        }
  334. X        ep = ep->e_prev;
  335. X        index--;
  336. X    }
  337. X    return -1;
  338. X}
  339. X
  340. X
  341. X/*
  342. X * Index into a list and return the address for the value corresponding
  343. X * to that index.  Returns NULL if the element does not exist.
  344. X */
  345. XVALUE *
  346. Xlistfindex(lp, index)
  347. X    LIST *lp;        /* list to index into */
  348. X    long index;        /* index of desired element */
  349. X{
  350. X    LISTELEM *ep;
  351. X
  352. X    ep = listelement(lp, index);
  353. X    if (ep == NULL)
  354. X        return NULL;
  355. X    return &ep->e_value;
  356. X}
  357. X
  358. X
  359. X/*
  360. X * Return the element at a specified index number of a list.
  361. X * The list is indexed starting at zero, and negative indices
  362. X * indicate to index from the end of the list.  This routine finds
  363. X * the element by chaining through the list from the closest one
  364. X * of the first, last, and cached elements.  Returns NULL if the
  365. X * element does not exist.
  366. X */
  367. Xstatic LISTELEM *
  368. Xlistelement(lp, index)
  369. X    register LIST *lp;    /* list to index into */
  370. X    long index;        /* index of desired element */
  371. X{
  372. X    register LISTELEM *ep;    /* current list element */
  373. X    long dist;        /* distance to element */
  374. X    long temp;        /* temporary distance */
  375. X    BOOL forward;        /* TRUE if need to walk forwards */
  376. X
  377. X    if (index < 0)
  378. X        index += lp->l_count;
  379. X    if ((index < 0) || (index >= lp->l_count))
  380. X        return NULL;
  381. X    /*
  382. X     * Check quick special cases first.
  383. X     */
  384. X    if (index == 0)
  385. X        return lp->l_first;
  386. X    if (index == 1)
  387. X        return lp->l_first->e_next;
  388. X    if (index == lp->l_count - 1)
  389. X        return lp->l_last;
  390. X    if ((index == lp->l_cacheindex) && lp->l_cache)
  391. X        return lp->l_cache;
  392. X    /*
  393. X     * Calculate whether it is better to go forwards from
  394. X     * the first element or backwards from the last element.
  395. X     */
  396. X    forward = ((index * 2) <= lp->l_count);
  397. X    if (forward) {
  398. X        dist = index;
  399. X        ep = lp->l_first;
  400. X    } else {
  401. X        dist = (lp->l_count - 1) - index;
  402. X        ep = lp->l_last;
  403. X    }
  404. X    /*
  405. X     * Now see if we have a cached element and if so, whether or
  406. X     * not the distance from it is better than the above distance.
  407. X     */
  408. X    if (lp->l_cache) {
  409. X        temp = index - lp->l_cacheindex;
  410. X        if ((temp >= 0) && (temp < dist)) {
  411. X            dist = temp;
  412. X            ep = lp->l_cache;
  413. X            forward = TRUE;
  414. X        }
  415. X        if ((temp < 0) && (-temp < dist)) {
  416. X            dist = -temp;
  417. X            ep = lp->l_cache;
  418. X            forward = FALSE;
  419. X        }
  420. X    }
  421. X    /*
  422. X     * Now walk forwards or backwards from the selected element
  423. X     * until we reach the correct element.  Cache the location of
  424. X     * the found element for future use.
  425. X     */
  426. X    if (forward) {
  427. X        while (dist-- > 0)
  428. X            ep = ep->e_next;
  429. X    } else {
  430. X        while (dist-- > 0)
  431. X            ep = ep->e_prev;
  432. X    }
  433. X    lp->l_cache = ep;
  434. X    lp->l_cacheindex = index;
  435. X    return ep;
  436. X}
  437. X
  438. X
  439. X/*
  440. X * Compare two lists to see if they are identical.
  441. X * Returns TRUE if they are different.
  442. X */
  443. XBOOL
  444. Xlistcmp(lp1, lp2)
  445. X    LIST *lp1, *lp2;
  446. X{
  447. X    LISTELEM *e1, *e2;
  448. X    long count;
  449. X
  450. X    if (lp1 == lp2)
  451. X        return FALSE;
  452. X    if (lp1->l_count != lp2->l_count)
  453. X        return TRUE;
  454. X    e1 = lp1->l_first;
  455. X    e2 = lp2->l_first;
  456. X    count = lp1->l_count;
  457. X    while (count-- > 0) {
  458. X        if (comparevalue(&e1->e_value, &e2->e_value))
  459. X            return TRUE;
  460. X        e1 = e1->e_next;
  461. X        e2 = e2->e_next;
  462. X    }
  463. X    return FALSE;
  464. X}
  465. X
  466. X
  467. X/*
  468. X * Copy a list
  469. X */
  470. XLIST *
  471. Xlistcopy(oldlp)
  472. X    LIST *oldlp;
  473. X{
  474. X    LIST *lp;
  475. X    LISTELEM *oldep;
  476. X
  477. X    lp = listalloc();
  478. X    oldep = oldlp->l_first;
  479. X    while (oldep) {
  480. X        insertlistlast(lp, &oldep->e_value);
  481. X        oldep = oldep->e_next;
  482. X    }
  483. X    return lp;
  484. X}
  485. X
  486. X
  487. X/*
  488. X * Allocate an element for a list.
  489. X */
  490. Xstatic LISTELEM *
  491. Xelemalloc()
  492. X{
  493. X    LISTELEM *ep;
  494. X
  495. X    ep = (LISTELEM *) allocitem(&elementfreelist);
  496. X    if (ep == NULL)
  497. X        math_error("Cannot allocate list element");
  498. X    ep->e_next = NULL;
  499. X    ep->e_prev = NULL;
  500. X    ep->e_value.v_type = V_NULL;
  501. X    return ep;
  502. X}
  503. X
  504. X
  505. X/*
  506. X * Free a list element, along with any contained value.
  507. X */
  508. Xstatic void
  509. Xelemfree(ep)
  510. X    LISTELEM *ep;
  511. X{
  512. X    if (ep->e_value.v_type != V_NULL)
  513. X        freevalue(&ep->e_value);
  514. X    freeitem(&elementfreelist, (FREEITEM *) ep);
  515. X}
  516. X
  517. X
  518. X/*
  519. X * Allocate a new list header.
  520. X */
  521. XLIST *
  522. Xlistalloc()
  523. X{
  524. X    register LIST *lp;
  525. X
  526. X    lp = (LIST *) allocitem(&headerfreelist);
  527. X    if (lp == NULL)
  528. X        math_error("Cannot allocate list header");
  529. X    lp->l_first = NULL;
  530. X    lp->l_last = NULL;
  531. X    lp->l_cache = NULL;
  532. X    lp->l_cacheindex = 0;
  533. X    lp->l_count = 0;
  534. X    return lp;
  535. X}
  536. X
  537. X
  538. X/*
  539. X * Free a list header, along with all of its list elements.
  540. X */
  541. Xvoid
  542. Xlistfree(lp)
  543. X    register LIST *lp;
  544. X{
  545. X    register LISTELEM *ep;
  546. X
  547. X    while (lp->l_count-- > 0) {
  548. X        ep = lp->l_first;
  549. X        lp->l_first = ep->e_next;
  550. X        elemfree(ep);
  551. X    }
  552. X    freeitem(&headerfreelist, (FREEITEM *) lp);
  553. X}
  554. X
  555. X
  556. X/*
  557. X * Print out a list along with the specified number of its elements.
  558. X * The elements are printed out in shortened form.
  559. X */
  560. Xvoid
  561. Xlistprint(lp, max_print)
  562. X    LIST *lp;
  563. X    long max_print;
  564. X{
  565. X    long count;
  566. X    long index;
  567. X    LISTELEM *ep;
  568. X
  569. X    if (max_print > lp->l_count)
  570. X        max_print = lp->l_count;
  571. X    count = 0;
  572. X    ep = lp->l_first;
  573. X    index = lp->l_count;
  574. X    while (index-- > 0) {
  575. X        if ((ep->e_value.v_type != V_NUM) ||
  576. X            (!qiszero(ep->e_value.v_num)))
  577. X                count++;
  578. X        ep = ep->e_next;
  579. X    }
  580. X    if (max_print > 0)
  581. X        math_str("\n");
  582. X    math_fmt("list (%ld element%s, %ld nonzero)", lp->l_count,
  583. X        ((lp->l_count == 1) ? "" : "s"), count);
  584. X    if (max_print <= 0)
  585. X        return;
  586. X
  587. X    /*
  588. X     * Walk through the first few list elements, printing their
  589. X     * value in short and unambiguous format.
  590. X     */
  591. X    math_str(":\n");
  592. X    ep = lp->l_first;
  593. X    for (index = 0; index < max_print; index++) {
  594. X        math_fmt("  [[%ld]] = ", index);
  595. X        printvalue(&ep->e_value, PRINT_SHORT | PRINT_UNAMBIG);
  596. X        math_str("\n");
  597. X        ep = ep->e_next;
  598. X    }
  599. X    if (max_print < lp->l_count)
  600. X        math_str("  ...\n");
  601. X}
  602. X
  603. X
  604. X/*
  605. X * Return a trivial hash value for a list.
  606. X */
  607. XHASH
  608. Xlisthash(lp)
  609. X    LIST *lp;
  610. X{
  611. X    HASH hash;
  612. X
  613. X    hash = lp->l_count * 600011;
  614. X    if (lp->l_count > 0)
  615. X        hash = hash * 600043 + hashvalue(&lp->l_first->e_value);
  616. X    if (lp->l_count > 1)
  617. X        hash = hash * 600053 + hashvalue(&lp->l_last->e_value);
  618. X    return hash;
  619. X}
  620. X
  621. X/* END CODE */
  622. SHAR_EOF
  623. chmod 0644 calc2.9.0/listfunc.c || echo "restore of calc2.9.0/listfunc.c fails"
  624. set `wc -c calc2.9.0/listfunc.c`;Sum=$1
  625. if test "$Sum" != "11559"
  626. then echo original size 11559, current size $Sum;fi
  627. echo "x - extracting calc2.9.0/matfunc.c (Text)"
  628. sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/matfunc.c &&
  629. X/*
  630. X * Copyright (c) 1993 David I. Bell
  631. X * Permission is granted to use, distribute, or modify this source,
  632. X * provided that this copyright notice remains intact.
  633. X *
  634. X * Extended precision rational arithmetic matrix functions.
  635. X * Matrices can contain arbitrary types of elements.
  636. X */
  637. X
  638. X#include "value.h"
  639. X
  640. X
  641. Xstatic void matswaprow MATH_PROTO((MATRIX *m, long r1, long r2));
  642. Xstatic void matsubrow MATH_PROTO((MATRIX *m, long oprow, long baserow,
  643. X    VALUE *mulval));
  644. Xstatic void matmulrow MATH_PROTO((MATRIX *m, long row, VALUE *mulval));
  645. Xstatic MATRIX *matident MATH_PROTO((MATRIX *m));
  646. X
  647. X
  648. X
  649. X/*
  650. X * Add two compatible matrices.
  651. X */
  652. XMATRIX *
  653. Xmatadd(m1, m2)
  654. X    MATRIX *m1, *m2;
  655. X{
  656. X    int dim;
  657. X
  658. X    long min1, min2, max1, max2, index;
  659. X    VALUE *v1, *v2, *vres;
  660. X    MATRIX *res;
  661. X    MATRIX tmp;
  662. X
  663. X    if (m1->m_dim != m2->m_dim)
  664. X        math_error("Incompatible matrix dimensions for add");
  665. X    tmp.m_dim = m1->m_dim;
  666. X    tmp.m_size = m1->m_size;
  667. X    for (dim = 0; dim < m1->m_dim; dim++) {
  668. X        min1 = m1->m_min[dim];
  669. X        max1 = m1->m_max[dim];
  670. X        min2 = m2->m_min[dim];
  671. X        max2 = m2->m_max[dim];
  672. X        if ((min1 && min2 && (min1 != min2)) || ((max1-min1) != (max2-min2)))
  673. X            math_error("Incompatible matrix bounds for add");
  674. X        tmp.m_min[dim] = (min1 ? min1 : min2);
  675. X        tmp.m_max[dim] = tmp.m_min[dim] + (max1 - min1);
  676. X    }
  677. X    res = matalloc(m1->m_size);
  678. X    *res = tmp;
  679. X    v1 = m1->m_table;
  680. X    v2 = m2->m_table;
  681. X    vres = res->m_table;
  682. X    for (index = m1->m_size; index > 0; index--)
  683. X        addvalue(v1++, v2++, vres++);
  684. X    return res;
  685. X}
  686. X
  687. X
  688. X/*
  689. X * Subtract two compatible matrices.
  690. X */
  691. XMATRIX *
  692. Xmatsub(m1, m2)
  693. X    MATRIX *m1, *m2;
  694. X{
  695. X    int dim;
  696. X    long min1, min2, max1, max2, index;
  697. X    VALUE *v1, *v2, *vres;
  698. X    MATRIX *res;
  699. X    MATRIX tmp;
  700. X
  701. X    if (m1->m_dim != m2->m_dim)
  702. X        math_error("Incompatible matrix dimensions for sub");
  703. X    tmp.m_dim = m1->m_dim;
  704. X    tmp.m_size = m1->m_size;
  705. X    for (dim = 0; dim < m1->m_dim; dim++) {
  706. X        min1 = m1->m_min[dim];
  707. X        max1 = m1->m_max[dim];
  708. X        min2 = m2->m_min[dim];
  709. X        max2 = m2->m_max[dim];
  710. X        if ((min1 && min2 && (min1 != min2)) || ((max1-min1) != (max2-min2)))
  711. X            math_error("Incompatible matrix bounds for sub");
  712. X        tmp.m_min[dim] = (min1 ? min1 : min2);
  713. X        tmp.m_max[dim] = tmp.m_min[dim] + (max1 - min1);
  714. X    }
  715. X    res = matalloc(m1->m_size);
  716. X    *res = tmp;
  717. X    v1 = m1->m_table;
  718. X    v2 = m2->m_table;
  719. X    vres = res->m_table;
  720. X    for (index = m1->m_size; index > 0; index--)
  721. X        subvalue(v1++, v2++, vres++);
  722. X    return res;
  723. X}
  724. X
  725. X
  726. X/*
  727. X * Produce the negative of a matrix.
  728. X */
  729. XMATRIX *
  730. Xmatneg(m)
  731. X    MATRIX *m;
  732. X{
  733. X    register VALUE *val, *vres;
  734. X    long index;
  735. X    MATRIX *res;
  736. X
  737. X    res = matalloc(m->m_size);
  738. X    *res = *m;
  739. X    val = m->m_table;
  740. X    vres = res->m_table;
  741. X    for (index = m->m_size; index > 0; index--)
  742. X        negvalue(val++, vres++);
  743. X    return res;
  744. X}
  745. X
  746. X
  747. X/*
  748. X * Multiply two compatible matrices.
  749. X */
  750. XMATRIX *
  751. Xmatmul(m1, m2)
  752. X    MATRIX *m1, *m2;
  753. X{
  754. X    register MATRIX *res;
  755. X    long i1, i2, max1, max2, index, maxindex;
  756. X    VALUE *v1, *v2;
  757. X    VALUE sum, tmp1, tmp2;
  758. X
  759. X    if ((m1->m_dim != 2) || (m2->m_dim != 2))
  760. X        math_error("Matrix dimension must be two for mul");
  761. X    if ((m1->m_max[1] - m1->m_min[1]) != (m2->m_max[0] - m2->m_min[0]))
  762. X        math_error("Incompatible bounds for matrix mul");
  763. X    max1 = (m1->m_max[0] - m1->m_min[0] + 1);
  764. X    max2 = (m2->m_max[1] - m2->m_min[1] + 1);
  765. X    maxindex = (m1->m_max[1] - m1->m_min[1] + 1);
  766. X    res = matalloc(max1 * max2);
  767. X    res->m_dim = 2;
  768. X    res->m_min[0] = m1->m_min[0];
  769. X    res->m_max[0] = m1->m_max[0];
  770. X    res->m_min[1] = m2->m_min[1];
  771. X    res->m_max[1] = m2->m_max[1];
  772. X    for (i1 = 0; i1 < max1; i1++) {
  773. X        for (i2 = 0; i2 < max2; i2++) {
  774. X            sum.v_num = qlink(&_qzero_);
  775. X            sum.v_type = V_NUM;
  776. X            v1 = &m1->m_table[i1 * maxindex];
  777. X            v2 = &m2->m_table[i2];
  778. X            for (index = 0; index < maxindex; index++) {
  779. X                mulvalue(v1, v2, &tmp1);
  780. X                addvalue(&sum, &tmp1, &tmp2);
  781. X                freevalue(&tmp1);
  782. X                freevalue(&sum);
  783. X                sum = tmp2;
  784. X                v1++;
  785. X                v2 += max2;
  786. X            }
  787. X            index = (i1 * max2) + i2;
  788. X            res->m_table[index] = sum;
  789. X        }
  790. X    }
  791. X    return res;
  792. X}
  793. X
  794. X
  795. X/*
  796. X * Square a matrix.
  797. X */
  798. XMATRIX *
  799. Xmatsquare(m)
  800. X    MATRIX *m;
  801. X{
  802. X    register MATRIX *res;
  803. X    long i1, i2, max, index;
  804. X    VALUE *v1, *v2;
  805. X    VALUE sum, tmp1, tmp2;
  806. X
  807. X    if (m->m_dim != 2)
  808. X        math_error("Matrix dimension must be two for square");
  809. X    if ((m->m_max[0] - m->m_min[0]) != (m->m_max[1] - m->m_min[1]))
  810. X        math_error("Squaring non-square matrix");
  811. X    max = (m->m_max[0] - m->m_min[0] + 1);
  812. X    res = matalloc(max * max);
  813. X    res->m_dim = 2;
  814. X    res->m_min[0] = m->m_min[0];
  815. X    res->m_max[0] = m->m_max[0];
  816. X    res->m_min[1] = m->m_min[1];
  817. X    res->m_max[1] = m->m_max[1];
  818. X    for (i1 = 0; i1 < max; i1++) {
  819. X        for (i2 = 0; i2 < max; i2++) {
  820. X            sum.v_num = qlink(&_qzero_);
  821. X            sum.v_type = V_NUM;
  822. X            v1 = &m->m_table[i1 * max];
  823. X            v2 = &m->m_table[i2];
  824. X            for (index = 0; index < max; index++) {
  825. X                mulvalue(v1, v2, &tmp1);
  826. X                addvalue(&sum, &tmp1, &tmp2);
  827. X                freevalue(&tmp1);
  828. X                freevalue(&sum);
  829. X                sum = tmp2;
  830. X                v1++;
  831. X                v2 += max;
  832. X            }
  833. X            index = (i1 * max) + i2;
  834. X            res->m_table[index] = sum;
  835. X        }
  836. X    }
  837. X    return res;
  838. X}
  839. X
  840. X
  841. X/*
  842. X * Compute the result of raising a square matrix to an integer power.
  843. X * Negative powers mean the positive power of the inverse.
  844. X * Note: This calculation could someday be improved for large powers
  845. X * by using the characteristic polynomial of the matrix.
  846. X */
  847. XMATRIX *
  848. Xmatpowi(m, q)
  849. X    MATRIX *m;        /* matrix to be raised */
  850. X    NUMBER *q;        /* power to raise it to */
  851. X{
  852. X    MATRIX *res, *tmp;
  853. X    long power;        /* power to raise to */
  854. X    unsigned long bit;    /* current bit value */
  855. X
  856. X    if (m->m_dim != 2)
  857. X        math_error("Matrix dimension must be two for power");
  858. X    if ((m->m_max[0] - m->m_min[0]) != (m->m_max[1] - m->m_min[1]))
  859. X        math_error("Raising non-square matrix to a power");
  860. X    if (qisfrac(q))
  861. X        math_error("Raising matrix to non-integral power");
  862. X    if (zisbig(q->num))
  863. X        math_error("Raising matrix to very large power");
  864. X    power = (zistiny(q->num) ? z1tol(q->num) : z2tol(q->num));
  865. X    if (qisneg(q))
  866. X        power = -power;
  867. X    /*
  868. X     * Handle some low powers specially
  869. X     */
  870. X    if ((power <= 4) && (power >= -2)) {
  871. X        switch ((int) power) {
  872. X            case 0:
  873. X                return matident(m);
  874. X            case 1:
  875. X                return matcopy(m);
  876. X            case -1:
  877. X                return matinv(m);
  878. X            case 2:
  879. X                return matsquare(m);
  880. X            case -2:
  881. X                tmp = matinv(m);
  882. X                res = matsquare(tmp);
  883. X                matfree(tmp);
  884. X                return res;
  885. X            case 3:
  886. X                tmp = matsquare(m);
  887. X                res = matmul(m, tmp);
  888. X                matfree(tmp);
  889. X                return res;
  890. X            case 4:
  891. X                tmp = matsquare(m);
  892. X                res = matsquare(tmp);
  893. X                matfree(tmp);
  894. X                return res;
  895. X        }
  896. X    }
  897. X    if (power < 0) {
  898. X        m = matinv(m);
  899. X        power = -power;
  900. X    }
  901. X    /*
  902. X     * Compute the power by squaring and multiplying.
  903. X     * This uses the left to right method of power raising.
  904. X     */
  905. X    bit = TOPFULL;
  906. X    while ((bit & power) == 0)
  907. X        bit >>= 1L;
  908. X    bit >>= 1L;
  909. X    res = matsquare(m);
  910. X    if (bit & power) {
  911. X        tmp = matmul(res, m);
  912. X        matfree(res);
  913. X        res = tmp;
  914. X    }
  915. X    bit >>= 1L;
  916. X    while (bit) {
  917. X        tmp = matsquare(res);
  918. X        matfree(res);
  919. X        res = tmp;
  920. X        if (bit & power) {
  921. X            tmp = matmul(res, m);
  922. X            matfree(res);
  923. X            res = tmp;
  924. X        }
  925. X        bit >>= 1L;
  926. X    }
  927. X    if (qisneg(q))
  928. X        matfree(m);
  929. X    return res;
  930. X}
  931. X
  932. X
  933. X/*
  934. X * Calculate the cross product of two one dimensional matrices each
  935. X * with three components.
  936. X *    m3 = matcross(m1, m2);
  937. X */
  938. XMATRIX *
  939. Xmatcross(m1, m2)
  940. X    MATRIX *m1, *m2;
  941. X{
  942. X    MATRIX *res;
  943. X    VALUE *v1, *v2, *vr;
  944. X    VALUE tmp1, tmp2;
  945. X
  946. X    if ((m1->m_dim != 1) || (m2->m_dim != 1))
  947. X        math_error("Matrix not 1d for cross product");
  948. X    if ((m1->m_size != 3) || (m2->m_size != 3))
  949. X        math_error("Matrix not size 3 for cross product");
  950. X    res = matalloc(3L);
  951. X    res->m_dim = 1;
  952. X    res->m_min[0] = 0;
  953. X    res->m_max[0] = 2;
  954. X    v1 = m1->m_table;
  955. X    v2 = m2->m_table;
  956. X    vr = res->m_table;
  957. X    mulvalue(v1 + 1, v2 + 2, &tmp1);
  958. X    mulvalue(v1 + 2, v2 + 1, &tmp2);
  959. X    subvalue(&tmp1, &tmp2, vr + 0);
  960. X    freevalue(&tmp1);
  961. X    freevalue(&tmp2);
  962. X    mulvalue(v1 + 2, v2 + 0, &tmp1);
  963. X    mulvalue(v1 + 0, v2 + 2, &tmp2);
  964. X    subvalue(&tmp1, &tmp2, vr + 1);
  965. X    freevalue(&tmp1);
  966. X    freevalue(&tmp2);
  967. X    mulvalue(v1 + 0, v2 + 1, &tmp1);
  968. X    mulvalue(v1 + 1, v2 + 0, &tmp2);
  969. X    subvalue(&tmp1, &tmp2, vr + 2);
  970. X    freevalue(&tmp1);
  971. X    freevalue(&tmp2);
  972. X    return res;
  973. X}
  974. X
  975. X
  976. X/*
  977. X * Return the dot product of two matrices.
  978. X *    result = matdot(m1, m2);
  979. X */
  980. XVALUE
  981. Xmatdot(m1, m2)
  982. X    MATRIX *m1, *m2;
  983. X{
  984. X    VALUE *v1, *v2;
  985. X    VALUE result, tmp1, tmp2;
  986. X    long len;
  987. X
  988. X    if ((m1->m_dim != 1) || (m2->m_dim != 1))
  989. X        math_error("Matrix not 1d for dot product");
  990. X    if (m1->m_size != m2->m_size)
  991. X        math_error("Incompatible matrix sizes for dot product");
  992. X    v1 = m1->m_table;
  993. X    v2 = m2->m_table;
  994. X    mulvalue(v1, v2, &result);
  995. X    len = m1->m_size;
  996. X    while (--len > 0) {
  997. X        mulvalue(++v1, ++v2, &tmp1);
  998. X        addvalue(&result, &tmp1, &tmp2);
  999. X        freevalue(&tmp1);
  1000. X        freevalue(&result);
  1001. X        result = tmp2;
  1002. X    }
  1003. X    return result;
  1004. X}
  1005. X
  1006. X
  1007. X/*
  1008. X * Scale the elements of a matrix by a specified power of two.
  1009. X */
  1010. XMATRIX *
  1011. Xmatscale(m, n)
  1012. X    MATRIX *m;        /* matrix to be scaled */
  1013. X    long n;
  1014. X{
  1015. X    register VALUE *val, *vres;
  1016. X    VALUE num;
  1017. X    long index;
  1018. X    MATRIX *res;        /* resulting matrix */
  1019. X
  1020. X    if (n == 0)
  1021. X        return matcopy(m);
  1022. X    num.v_type = V_NUM;
  1023. X    num.v_num = itoq(n);
  1024. X    res = matalloc(m->m_size);
  1025. X    *res = *m;
  1026. X    val = m->m_table;
  1027. X    vres = res->m_table;
  1028. X    for (index = m->m_size; index > 0; index--)
  1029. X        scalevalue(val++, &num, vres++);
  1030. X    qfree(num.v_num);
  1031. X    return res;
  1032. X}
  1033. X
  1034. X
  1035. X/*
  1036. X * Shift the elements of a matrix by the specified number of bits.
  1037. X * Positive shift means leftwards, negative shift rightwards.
  1038. X */
  1039. XMATRIX *
  1040. Xmatshift(m, n)
  1041. X    MATRIX *m;        /* matrix to be scaled */
  1042. X    long n;
  1043. X{
  1044. X    register VALUE *val, *vres;
  1045. X    VALUE num;
  1046. X    long index;
  1047. X    MATRIX *res;        /* resulting matrix */
  1048. X
  1049. X    if (n == 0)
  1050. X        return matcopy(m);
  1051. X    num.v_type = V_NUM;
  1052. X    num.v_num = itoq(n);
  1053. X    res = matalloc(m->m_size);
  1054. X    *res = *m;
  1055. X    val = m->m_table;
  1056. X    vres = res->m_table;
  1057. X    for (index = m->m_size; index > 0; index--)
  1058. X        shiftvalue(val++, &num, FALSE, vres++);
  1059. X    qfree(num.v_num);
  1060. X    return res;
  1061. X}
  1062. X
  1063. X
  1064. X/*
  1065. X * Multiply the elements of a matrix by a specified value.
  1066. X */
  1067. XMATRIX *
  1068. Xmatmulval(m, vp)
  1069. X    MATRIX *m;        /* matrix to be multiplied */
  1070. X    VALUE *vp;        /* value to multiply by */
  1071. X{
  1072. X    register VALUE *val, *vres;
  1073. X    long index;
  1074. X    MATRIX *res;
  1075. X
  1076. X    res = matalloc(m->m_size);
  1077. X    *res = *m;
  1078. X    val = m->m_table;
  1079. X    vres = res->m_table;
  1080. X    for (index = m->m_size; index > 0; index--)
  1081. X        mulvalue(val++, vp, vres++);
  1082. X    return res;
  1083. X}
  1084. X
  1085. X
  1086. X/*
  1087. X * Divide the elements of a matrix by a specified value, keeping
  1088. X * only the integer quotient.
  1089. X */
  1090. XMATRIX *
  1091. Xmatquoval(m, vp)
  1092. X    MATRIX *m;        /* matrix to be divided */
  1093. X    VALUE *vp;        /* value to divide by */
  1094. X{
  1095. X    register VALUE *val, *vres;
  1096. X    long index;
  1097. X    MATRIX *res;
  1098. X
  1099. X    if ((vp->v_type == V_NUM) && qiszero(vp->v_num))
  1100. X        math_error("Division by zero");
  1101. X    res = matalloc(m->m_size);
  1102. X    *res = *m;
  1103. X    val = m->m_table;
  1104. X    vres = res->m_table;
  1105. X    for (index = m->m_size; index > 0; index--)
  1106. X        quovalue(val++, vp, vres++);
  1107. X    return res;
  1108. X}
  1109. X
  1110. X
  1111. X/*
  1112. X * Divide the elements of a matrix by a specified value, keeping
  1113. X * only the remainder of the division.
  1114. X */
  1115. XMATRIX *
  1116. Xmatmodval(m, vp)
  1117. X    MATRIX *m;        /* matrix to be divided */
  1118. X    VALUE *vp;        /* value to divide by */
  1119. X{
  1120. X    register VALUE *val, *vres;
  1121. X    long index;
  1122. X    MATRIX *res;
  1123. X
  1124. X    if ((vp->v_type == V_NUM) && qiszero(vp->v_num))
  1125. X        math_error("Division by zero");
  1126. X    res = matalloc(m->m_size);
  1127. X    *res = *m;
  1128. X    val = m->m_table;
  1129. X    vres = res->m_table;
  1130. X    for (index = m->m_size; index > 0; index--)
  1131. X        modvalue(val++, vp, vres++);
  1132. X    return res;
  1133. X}
  1134. X
  1135. X
  1136. XMATRIX *
  1137. Xmattrans(m)
  1138. X    MATRIX *m;            /* matrix to be transposed */
  1139. X{
  1140. X    register VALUE *v1, *v2;    /* current values */
  1141. X    long rows, cols;        /* rows and columns in new matrix */
  1142. X    long row, col;            /* current row and column */
  1143. X    MATRIX *res;
  1144. X
  1145. X    if (m->m_dim != 2)
  1146. X        math_error("Matrix dimension must be two for transpose");
  1147. X    res = matalloc(m->m_size);
  1148. X    res->m_dim = 2;
  1149. X    res->m_min[0] = m->m_min[1];
  1150. X    res->m_max[0] = m->m_max[1];
  1151. X    res->m_min[1] = m->m_min[0];
  1152. X    res->m_max[1] = m->m_max[0];
  1153. X    rows = (m->m_max[1] - m->m_min[1] + 1);
  1154. X    cols = (m->m_max[0] - m->m_min[0] + 1);
  1155. X    v1 = res->m_table;
  1156. X    for (row = 0; row < rows; row++) {
  1157. X        v2 = &m->m_table[row];
  1158. X        for (col = 0; col < cols; col++) {
  1159. X            copyvalue(v2, v1);
  1160. X            v1++;
  1161. X            v2 += rows;
  1162. X        }
  1163. X    }
  1164. X    return res;
  1165. X}
  1166. X
  1167. X
  1168. X/*
  1169. X * Produce a matrix with values all of which are conjugated.
  1170. X */
  1171. XMATRIX *
  1172. Xmatconj(m)
  1173. X    MATRIX *m;
  1174. X{
  1175. X    register VALUE *val, *vres;
  1176. X    long index;
  1177. X    MATRIX *res;
  1178. X
  1179. X    res = matalloc(m->m_size);
  1180. X    *res = *m;
  1181. X    val = m->m_table;
  1182. X    vres = res->m_table;
  1183. X    for (index = m->m_size; index > 0; index--)
  1184. X        conjvalue(val++, vres++);
  1185. X    return res;
  1186. X}
  1187. X
  1188. X
  1189. X/*
  1190. X * Produce a matrix with values all of which have been rounded to the
  1191. X * specified number of decimal places.
  1192. X */
  1193. XMATRIX *
  1194. Xmatround(m, places)
  1195. X    MATRIX *m;
  1196. X    long places;
  1197. X{
  1198. X    register VALUE *val, *vres;
  1199. X    VALUE tmp;
  1200. X    long index;
  1201. X    MATRIX *res;
  1202. X
  1203. X    if (places < 0)
  1204. X        math_error("Negative number of places for matround");
  1205. X    res = matalloc(m->m_size);
  1206. X    *res = *m;
  1207. X    tmp.v_type = V_INT;
  1208. X    tmp.v_int = places;
  1209. X    val = m->m_table;
  1210. X    vres = res->m_table;
  1211. X    for (index = m->m_size; index > 0; index--)
  1212. X        roundvalue(val++, &tmp, vres++);
  1213. X    return res;
  1214. X}
  1215. X
  1216. X
  1217. X/*
  1218. X * Produce a matrix with values all of which have been rounded to the
  1219. X * specified number of binary places.
  1220. X */
  1221. XMATRIX *
  1222. Xmatbround(m, places)
  1223. X    MATRIX *m;
  1224. X    long places;
  1225. X{
  1226. X    register VALUE *val, *vres;
  1227. X    VALUE tmp;
  1228. X    long index;
  1229. X    MATRIX *res;
  1230. X
  1231. X    if (places < 0)
  1232. X        math_error("Negative number of places for matbround");
  1233. X    res = matalloc(m->m_size);
  1234. X    *res = *m;
  1235. X    tmp.v_type = V_INT;
  1236. X    tmp.v_int = places;
  1237. X    val = m->m_table;
  1238. X    vres = res->m_table;
  1239. X    for (index = m->m_size; index > 0; index--)
  1240. X        broundvalue(val++, &tmp, vres++);
  1241. X    return res;
  1242. X}
  1243. X
  1244. X
  1245. X/*
  1246. X * Produce a matrix with values all of which have been truncated to integers.
  1247. X */
  1248. XMATRIX *
  1249. Xmatint(m)
  1250. X    MATRIX *m;
  1251. X{
  1252. X    register VALUE *val, *vres;
  1253. X    long index;
  1254. X    MATRIX *res;
  1255. X
  1256. X    res = matalloc(m->m_size);
  1257. X    *res = *m;
  1258. X    val = m->m_table;
  1259. X    vres = res->m_table;
  1260. X    for (index = m->m_size; index > 0; index--)
  1261. X        intvalue(val++, vres++);
  1262. X    return res;
  1263. X}
  1264. X
  1265. X
  1266. X/*
  1267. X * Produce a matrix with values all of which have only the fraction part left.
  1268. X */
  1269. XMATRIX *
  1270. Xmatfrac(m)
  1271. X    MATRIX *m;
  1272. X{
  1273. X    register VALUE *val, *vres;
  1274. X    long index;
  1275. X    MATRIX *res;
  1276. X
  1277. X    res = matalloc(m->m_size);
  1278. X    *res = *m;
  1279. X    val = m->m_table;
  1280. X    vres = res->m_table;
  1281. X    for (index = m->m_size; index > 0; index--)
  1282. X        fracvalue(val++, vres++);
  1283. X    return res;
  1284. X}
  1285. X
  1286. X
  1287. X/*
  1288. X * Index a matrix normally by the specified set of index values.
  1289. X * Returns the address of the matrix element if it is valid, or generates
  1290. X * an error if the index values are out of range.  The create flag is TRUE
  1291. X * if the element is to be written, but this is ignored here.
  1292. X */
  1293. X/*ARGSUSED*/
  1294. XVALUE *
  1295. Xmatindex(mp, create, dim, indices)
  1296. X    MATRIX *mp;
  1297. X    BOOL create;
  1298. X    long dim;        /* dimension of the indexing */
  1299. X    VALUE *indices;        /* table of values being indexed by */
  1300. X{
  1301. X    NUMBER *q;        /* index value */
  1302. X    long index;        /* index value as an integer */
  1303. X    long offset;        /* current offset into array */
  1304. X    int i;            /* loop counter */
  1305. X
  1306. X    if ((dim <= 0) || (dim > MAXDIM))
  1307. X        math_error("Bad dimension %ld for matrix", dim);
  1308. X    if (mp->m_dim != dim)
  1309. X        math_error("Indexing a %ldd matrix as a %ldd matrix", mp->m_dim, dim);
  1310. X    offset = 0;
  1311. X    for (i = 0; i < dim; i++) {
  1312. X        if (indices->v_type != V_NUM)
  1313. X            math_error("Non-numeric index for matrix");
  1314. X        q = indices->v_num;
  1315. X        if (qisfrac(q))
  1316. X            math_error("Non-integral index for matrix");
  1317. X        index = qtoi(q);
  1318. X        if (zisbig(q->num) || (index < mp->m_min[i]) || (index > mp->m_max[i]))
  1319. X            math_error("Index out of bounds for matrix");
  1320. X        offset *= (mp->m_max[i] - mp->m_min[i] + 1);
  1321. X        offset += (index - mp->m_min[i]);
  1322. X        indices++;
  1323. X    }
  1324. X    return mp->m_table + offset;
  1325. X}
  1326. X
  1327. X
  1328. X/*
  1329. X * Search a matrix for the specified value, starting with the specified index.
  1330. X * Returns the index of the found value, or -1 if the value was not found.
  1331. X */
  1332. Xlong
  1333. Xmatsearch(m, vp, index)
  1334. X    MATRIX *m;
  1335. X    VALUE *vp;
  1336. X    long index;
  1337. X{
  1338. X    register VALUE *val;
  1339. X
  1340. X    if (index < 0)
  1341. X        index = 0;
  1342. X    val = &m->m_table[index];
  1343. X    while (index < m->m_size) {
  1344. X        if (!comparevalue(vp, val))
  1345. X            return index;
  1346. X        index++;
  1347. X        val++;
  1348. X    }
  1349. X    return -1;
  1350. X}
  1351. X
  1352. X
  1353. X/*
  1354. X * Search a matrix backwards for the specified value, starting with the
  1355. X * specified index.  Returns the index of the found value, or -1 if the
  1356. X * value was not found.
  1357. X */
  1358. Xlong
  1359. Xmatrsearch(m, vp, index)
  1360. X    MATRIX *m;
  1361. X    VALUE *vp;
  1362. X    long index;
  1363. X{
  1364. X    register VALUE *val;
  1365. X
  1366. X    if (index >= m->m_size)
  1367. X        index = m->m_size - 1;
  1368. X    val = &m->m_table[index];
  1369. X    while (index >= 0) {
  1370. X        if (!comparevalue(vp, val))
  1371. X            return index;
  1372. X        index--;
  1373. X        val--;
  1374. X    }
  1375. X    return -1;
  1376. X}
  1377. X
  1378. X
  1379. X/*
  1380. X * Fill all of the elements of a matrix with one of two specified values.
  1381. X * All entries are filled with the first specified value, except that if
  1382. X * the matrix is square and the second value pointer is non-NULL, then
  1383. X * all diagonal entries are filled with the second value.  This routine
  1384. X * affects the supplied matrix directly, and doesn't return a copy.
  1385. X */
  1386. Xvoid
  1387. Xmatfill(m, v1, v2)
  1388. X    MATRIX *m;        /* matrix to be filled */
  1389. X    VALUE *v1;        /* value to fill most of matrix with */
  1390. X    VALUE *v2;        /* value for diagonal entries (or NULL) */
  1391. X{
  1392. X    register VALUE *val;
  1393. X    long row, col;
  1394. X    long rows;
  1395. X    long index;
  1396. X
  1397. X    if (v2 && ((m->m_dim != 2) ||
  1398. X        ((m->m_max[0] - m->m_min[0]) != (m->m_max[1] - m->m_min[1]))))
  1399. X            math_error("Filling diagonals of non-square matrix");
  1400. X    val = m->m_table;
  1401. X    for (index = m->m_size; index > 0; index--)
  1402. X        freevalue(val++);
  1403. X    val = m->m_table;
  1404. X    if (v2 == NULL) {
  1405. X        for (index = m->m_size; index > 0; index--)
  1406. X            copyvalue(v1, val++);
  1407. X        return;
  1408. X    }
  1409. X    rows = m->m_max[0] - m->m_min[0] + 1;
  1410. X    for (row = 0; row < rows; row++) {
  1411. X        for (col = 0; col < rows; col++) {
  1412. X            copyvalue(((row != col) ? v1 : v2), val++);
  1413. X        }
  1414. X    }
  1415. X}
  1416. X
  1417. X
  1418. X/*
  1419. X * Set a copy of a square matrix to the identity matrix.
  1420. X */
  1421. Xstatic MATRIX *
  1422. Xmatident(m)
  1423. X    MATRIX *m;
  1424. X{
  1425. X    register VALUE *val;    /* current value */
  1426. X    long row, col;        /* current row and column */
  1427. X    long rows;        /* number of rows */
  1428. X    MATRIX *res;        /* resulting matrix */
  1429. X
  1430. X    if (m->m_dim != 2)
  1431. X        math_error("Matrix dimension must be two for setting to identity");
  1432. X    if ((m->m_max[0] - m->m_min[0]) != (m->m_max[1] - m->m_min[1]))
  1433. X        math_error("Matrix must be square for setting to identity");
  1434. X    res = matalloc(m->m_size);
  1435. X    *res = *m;
  1436. X    val = res->m_table;
  1437. X    rows = (res->m_max[0] - res->m_min[0] + 1);
  1438. X    for (row = 0; row < rows; row++) {
  1439. X        for (col = 0; col < rows; col++) {
  1440. X            val->v_type = V_NUM;
  1441. X            val->v_num = ((row == col) ? qlink(&_qone_) : qlink(&_qzero_));
  1442. X            val++;
  1443. X        }
  1444. X    }
  1445. X    return res;
  1446. X}
  1447. X
  1448. X
  1449. X/*
  1450. X * Calculate the inverse of a matrix if it exists.
  1451. X * This is done by using transformations on the supplied matrix to convert
  1452. X * it to the identity matrix, and simultaneously applying the same set of
  1453. X * transformations to the identity matrix.
  1454. X */
  1455. XMATRIX *
  1456. Xmatinv(m)
  1457. X    MATRIX *m;
  1458. X{
  1459. X    MATRIX *res;        /* matrix to become the inverse */
  1460. X    long rows;        /* number of rows */
  1461. X    long cur;        /* current row being worked on */
  1462. X    long row, col;        /* temp row and column values */
  1463. X    VALUE *val;        /* current value in matrix*/
  1464. X    VALUE mulval;        /* value to multiply rows by */
  1465. X    VALUE tmpval;        /* temporary value */
  1466. X
  1467. X    if (m->m_dim != 2)
  1468. X        math_error("Matrix dimension must be two for inverse");
  1469. X    if ((m->m_max[0] - m->m_min[0]) != (m->m_max[1] - m->m_min[1]))
  1470. X        math_error("Inverting non-square matrix");
  1471. X    /*
  1472. X     * Begin by creating the identity matrix with the same attributes.
  1473. X     */
  1474. X    res = matalloc(m->m_size);
  1475. X    *res = *m;
  1476. X    rows = (m->m_max[0] - m->m_min[0] + 1);
  1477. X    val = res->m_table;
  1478. X    for (row = 0; row < rows; row++) {
  1479. X        for (col = 0; col < rows; col++) {
  1480. X            if (row == col)
  1481. X                val->v_num = qlink(&_qone_);
  1482. X            else
  1483. X                val->v_num = qlink(&_qzero_);
  1484. X            val->v_type = V_NUM;
  1485. X            val++;
  1486. X        }
  1487. X    }
  1488. X    /*
  1489. X     * Now loop over each row, and eliminate all entries in the
  1490. X     * corresponding column by using row operations.  Do the same
  1491. X     * operations on the resulting matrix.  Copy the original matrix
  1492. X     * so that we don't destroy it.
  1493. X     */
  1494. X    m = matcopy(m);
  1495. X    for (cur = 0; cur < rows; cur++) {
  1496. X        /*
  1497. X         * Find the first nonzero value in the rest of the column
  1498. X         * downwards from [cur,cur].  If there is no such value, then
  1499. X         * the matrix is not invertible.  If the first nonzero entry
  1500. X         * is not the current row, then swap the two rows to make the
  1501. X         * current one nonzero.
  1502. X         */
  1503. X        row = cur;
  1504. X        val = &m->m_table[(row * rows) + row];
  1505. X        while (testvalue(val) == 0) {
  1506. X            if (++row >= rows) {
  1507. X                matfree(m);
  1508. X                matfree(res);
  1509. X                math_error("Matrix is not invertible");
  1510. X            }
  1511. X            val += rows;
  1512. X        }
  1513. X        invertvalue(val, &mulval);
  1514. X        if (row != cur) {
  1515. X            matswaprow(m, row, cur);
  1516. X            matswaprow(res, row, cur);
  1517. X        }
  1518. X        /*
  1519. X         * Now for every other nonzero entry in the current column, subtract
  1520. X         * the appropriate multiple of the current row to force that entry
  1521. X         * to become zero.
  1522. X         */
  1523. X        val = &m->m_table[cur];
  1524. X        for (row = 0; row < rows; row++, val += rows) {
  1525. X            if ((row == cur) || (testvalue(val) == 0))
  1526. X                continue;
  1527. X            mulvalue(val, &mulval, &tmpval);
  1528. X            matsubrow(m, row, cur, &tmpval);
  1529. X            matsubrow(res, row, cur, &tmpval);
  1530. X            freevalue(&tmpval);
  1531. X        }
  1532. X        freevalue(&mulval);
  1533. X    }
  1534. X    /*
  1535. X     * Now the original matrix has nonzero entries only on its main diagonal.
  1536. X     * Scale the rows of the result matrix by the inverse of those entries.
  1537. X     */
  1538. X    val = m->m_table;
  1539. X    for (row = 0; row < rows; row++) {
  1540. X        if ((val->v_type != V_NUM) || !qisone(val->v_num)) {
  1541. X            invertvalue(val, &mulval);
  1542. X            matmulrow(res, row, &mulval);
  1543. X            freevalue(&mulval);
  1544. X        }
  1545. X        val += (rows + 1);
  1546. X    }
  1547. X    matfree(m);
  1548. X    return res;
  1549. X}
  1550. X
  1551. X
  1552. X/*
  1553. X * Calculate the determinant of a square matrix.
  1554. X * This is done using row operations to create an upper-diagonal matrix.
  1555. X */
  1556. XVALUE
  1557. Xmatdet(m)
  1558. X    MATRIX *m;
  1559. X{
  1560. X    long rows;        /* number of rows */
  1561. X    long cur;        /* current row being worked on */
  1562. X    long row;        /* temp row values */
  1563. X    int neg;        /* whether to negate determinant */
  1564. X    VALUE *val;        /* current value */
  1565. X    VALUE mulval, tmpval;    /* other values */
  1566. X
  1567. X    if (m->m_dim != 2)
  1568. X        math_error("Matrix dimension must be two for determinant");
  1569. X    if ((m->m_max[0] - m->m_min[0]) != (m->m_max[1] - m->m_min[1]))
  1570. X        math_error("Non-square matrix for determinant");
  1571. X    /*
  1572. X     * Loop over each row, and eliminate all lower entries in the
  1573. X     * corresponding column by using row operations.  Copy the original
  1574. X     * matrix so that we don't destroy it.
  1575. X     */
  1576. X    neg = 0;
  1577. X    m = matcopy(m);
  1578. X    rows = (m->m_max[0] - m->m_min[0] + 1);
  1579. X    for (cur = 0; cur < rows; cur++) {
  1580. X        /*
  1581. X         * Find the first nonzero value in the rest of the column
  1582. X         * downwards from [cur,cur].  If there is no such value, then
  1583. X         * the determinant is zero.  If the first nonzero entry is not
  1584. X         * the current row, then swap the two rows to make the current
  1585. X         * one nonzero, and remember that the determinant changes sign.
  1586. X         */
  1587. X        row = cur;
  1588. X        val = &m->m_table[(row * rows) + row];
  1589. X        while (testvalue(val) == 0) {
  1590. X            if (++row >= rows) {
  1591. X                matfree(m);
  1592. X                mulval.v_type = V_NUM;
  1593. X                mulval.v_num = qlink(&_qzero_);
  1594. X                return mulval;
  1595. X            }
  1596. X            val += rows;
  1597. X        }
  1598. X        invertvalue(val, &mulval);
  1599. X        if (row != cur) {
  1600. X            matswaprow(m, row, cur);
  1601. X            neg = !neg;
  1602. X        }
  1603. X        /*
  1604. X         * Now for every other nonzero entry lower down in the current column,
  1605. X         * subtract the appropriate multiple of the current row to force that
  1606. X         * entry to become zero.
  1607. X         */
  1608. X        row = cur + 1;
  1609. X        val = &m->m_table[(row * rows) + cur];
  1610. X        for (; row < rows; row++, val += rows) {
  1611. X            if (testvalue(val) == 0)
  1612. X                continue;
  1613. X            mulvalue(val, &mulval, &tmpval);
  1614. X            matsubrow(m, row, cur, &tmpval);
  1615. X            freevalue(&tmpval);
  1616. X        }
  1617. X        freevalue(&mulval);
  1618. X    }
  1619. X    /*
  1620. X     * Now the matrix is upper-diagonal, and the determinant is the
  1621. X     * product of the main diagonal entries, and is possibly negated.
  1622. X     */
  1623. X    val = m->m_table;
  1624. X    mulval.v_type = V_NUM;
  1625. X    mulval.v_num = qlink(&_qone_);
  1626. X    for (row = 0; row < rows; row++) {
  1627. X        mulvalue(&mulval, val, &tmpval);
  1628. X        freevalue(&mulval);
  1629. X        mulval = tmpval;
  1630. X        val += (rows + 1);
  1631. X    }
  1632. X    matfree(m);
  1633. X    if (neg) {
  1634. X        negvalue(&mulval, &tmpval);
  1635. X        freevalue(&mulval);
  1636. X        return tmpval;
  1637. X    }
  1638. X    return mulval;
  1639. X}
  1640. X
  1641. X
  1642. X/*
  1643. X * Local utility routine to swap two rows of a square matrix.
  1644. X * No checks are made to verify the legality of the arguments.
  1645. X */
  1646. Xstatic void
  1647. Xmatswaprow(m, r1, r2)
  1648. X    MATRIX *m;
  1649. X    long r1, r2;
  1650. X{
  1651. X    register VALUE *v1, *v2;
  1652. X    register long rows;
  1653. X    VALUE tmp;
  1654. X
  1655. X    if (r1 == r2)
  1656. X        return;
  1657. X    rows = (m->m_max[0] - m->m_min[0] + 1);
  1658. X    v1 = &m->m_table[r1 * rows];
  1659. X    v2 = &m->m_table[r2 * rows];
  1660. X    while (rows-- > 0) {
  1661. X        tmp = *v1;
  1662. X        *v1 = *v2;
  1663. X        *v2 = tmp;
  1664. X        v1++;
  1665. X        v2++;
  1666. X    }
  1667. X}
  1668. X
  1669. X
  1670. X/*
  1671. X * Local utility routine to subtract a multiple of one row to another one.
  1672. X * The row to be changed is oprow, the row to be subtracted is baserow.
  1673. X * No checks are made to verify the legality of the arguments.
  1674. X */
  1675. Xstatic void
  1676. Xmatsubrow(m, oprow, baserow, mulval)
  1677. X    MATRIX *m;
  1678. X    long oprow, baserow;
  1679. X    VALUE *mulval;
  1680. X{
  1681. X    register VALUE *vop, *vbase;
  1682. X    register long entries;
  1683. X    VALUE tmp1, tmp2;
  1684. X
  1685. X    entries = (m->m_max[0] - m->m_min[0] + 1);
  1686. X    vop = &m->m_table[oprow * entries];
  1687. X    vbase = &m->m_table[baserow * entries];
  1688. X    while (entries-- > 0) {
  1689. X        mulvalue(vbase, mulval, &tmp1);
  1690. X        subvalue(vop, &tmp1, &tmp2);
  1691. X        freevalue(&tmp1);
  1692. X        freevalue(vop);
  1693. X        *vop = tmp2;
  1694. X        vop++;
  1695. X        vbase++;
  1696. X    }
  1697. X}
  1698. X
  1699. X
  1700. X/*
  1701. X * Local utility routine to multiply a row by a specified number.
  1702. X * No checks are made to verify the legality of the arguments.
  1703. X */
  1704. Xstatic void
  1705. Xmatmulrow(m, row, mulval)
  1706. X    MATRIX *m;
  1707. X    long row;
  1708. X    VALUE *mulval;
  1709. X{
  1710. X    register VALUE *val;
  1711. X    register long rows;
  1712. X    VALUE tmp;
  1713. X
  1714. X    rows = (m->m_max[0] - m->m_min[0] + 1);
  1715. X    val = &m->m_table[row * rows];
  1716. X    while (rows-- > 0) {
  1717. X        mulvalue(val, mulval, &tmp);
  1718. X        freevalue(val);
  1719. X        *val = tmp;
  1720. X        val++;
  1721. X    }
  1722. X}
  1723. X
  1724. X
  1725. X/*
  1726. X * Make a full copy of a matrix.
  1727. X */
  1728. XMATRIX *
  1729. Xmatcopy(m)
  1730. X    MATRIX *m;
  1731. X{
  1732. X    MATRIX *res;
  1733. X    register VALUE *v1, *v2;
  1734. X    register long i;
  1735. X
  1736. X    res = matalloc(m->m_size);
  1737. X    *res = *m;
  1738. X    v1 = m->m_table;
  1739. X    v2 = res->m_table;
  1740. X    i = m->m_size;
  1741. X    while (i-- > 0) {
  1742. X        if (v1->v_type == V_NUM) {
  1743. X            v2->v_type = V_NUM;
  1744. X            v2->v_num = qlink(v1->v_num);
  1745. X        } else
  1746. X            copyvalue(v1, v2);
  1747. X        v1++;
  1748. X        v2++;
  1749. X    }
  1750. X    return res;
  1751. X}
  1752. X
  1753. X
  1754. X/*
  1755. X * Allocate a matrix with the specified number of elements.
  1756. X */
  1757. XMATRIX *
  1758. Xmatalloc(size)
  1759. X    long size;
  1760. X{
  1761. X    MATRIX *m;
  1762. X
  1763. X    m = (MATRIX *) malloc(matsize(size));
  1764. X    if (m == NULL)
  1765. X        math_error("Cannot get memory to allocate matrix of size %d", size);
  1766. X    m->m_size = size;
  1767. X    return m;
  1768. X}
  1769. X
  1770. X
  1771. X/*
  1772. X * Free a matrix, along with all of its element values.
  1773. X */
  1774. Xvoid
  1775. Xmatfree(m)
  1776. X    MATRIX *m;
  1777. X{
  1778. X    register VALUE *vp;
  1779. X    register long i;
  1780. X
  1781. X    vp = m->m_table;
  1782. X    i = m->m_size;
  1783. X    while (i-- > 0) {
  1784. X        if (vp->v_type == V_NUM) {
  1785. X            vp->v_type = V_NULL;
  1786. X            qfree(vp->v_num);
  1787. X        } else
  1788. X            freevalue(vp);
  1789. X        vp++;
  1790. X    }
  1791. X    free(m);
  1792. X}
  1793. X
  1794. X
  1795. X/*
  1796. X * Test whether a matrix has any nonzero values.
  1797. X * Returns TRUE if so.
  1798. X */
  1799. XBOOL
  1800. Xmattest(m)
  1801. X    MATRIX *m;
  1802. X{
  1803. X    register VALUE *vp;
  1804. X    register long i;
  1805. X
  1806. X    vp = m->m_table;
  1807. X    i = m->m_size;
  1808. X    while (i-- > 0) {
  1809. X        if ((vp->v_type != V_NUM) || (!qiszero(vp->v_num)))
  1810. X            return TRUE;
  1811. X        vp++;
  1812. X    }
  1813. X    return FALSE;
  1814. X}
  1815. X
  1816. X
  1817. X/*
  1818. X * Test whether or not two matrices are equal.
  1819. X * Equality is determined by the shape and values of the matrices,
  1820. X * but not by their index bounds.  Returns TRUE if they differ.
  1821. X */
  1822. XBOOL
  1823. Xmatcmp(m1, m2)
  1824. X    MATRIX *m1, *m2;
  1825. X{
  1826. X    VALUE *v1, *v2;
  1827. X    long i;
  1828. X
  1829. X    if (m1 == m2)
  1830. X        return FALSE;
  1831. X    if ((m1->m_dim != m2->m_dim) || (m1->m_size != m2->m_size))
  1832. X        return TRUE;
  1833. X    for (i = 0; i < m1->m_dim; i++) {
  1834. X        if ((m1->m_max[i] - m1->m_min[i]) != (m2->m_max[i] - m2->m_min[i]))
  1835. X        return TRUE;
  1836. X    }
  1837. X    v1 = m1->m_table;
  1838. X    v2 = m2->m_table;
  1839. X    i = m1->m_size;
  1840. X    while (i-- > 0) {
  1841. X        if (comparevalue(v1++, v2++))
  1842. X            return TRUE;
  1843. X    }
  1844. X    return FALSE;
  1845. X}
  1846. X
  1847. X
  1848. X#if 0
  1849. X/*
  1850. X * Test whether or not a matrix is the identity matrix.
  1851. X * Returns TRUE if so.
  1852. X */
  1853. XBOOL
  1854. Xmatisident(m)
  1855. X    MATRIX *m;
  1856. X{
  1857. X    register VALUE *val;    /* current value */
  1858. X    long row, col;        /* row and column numbers */
  1859. X
  1860. X    if ((m->m_dim != 2) ||
  1861. X        ((m->m_max[0] - m->m_min[0]) != (m->m_max[1] - m->m_min[1])))
  1862. X            return FALSE;
  1863. X    val = m->m_table;
  1864. X    for (row = 0; row < m->m_size; row++) {
  1865. X        for (col = 0; col < m->m_size; col++) {
  1866. X            if (val->v_type != V_NUM)
  1867. X                return FALSE;
  1868. X            if (row == col) {
  1869. X                if (!qisone(val->v_num))
  1870. X                    return FALSE;
  1871. X            } else {
  1872. X                if (!qiszero(val->v_num))
  1873. X                    return FALSE;
  1874. X            }
  1875. X            val++;
  1876. X        }
  1877. X    }
  1878. X    return TRUE;
  1879. X}
  1880. X#endif
  1881. X
  1882. X
  1883. X/*
  1884. X * Return a trivial hash value for a matrix.
  1885. X */
  1886. XHASH
  1887. Xmathash(m)
  1888. X    MATRIX *m;
  1889. X{
  1890. X    HASH hash;
  1891. X    long fullsize;
  1892. X    long skip;
  1893. X    int i;
  1894. X    VALUE *vp;
  1895. X
  1896. X    hash = m->m_dim * 500009;
  1897. X    fullsize = 1;
  1898. X    for (i = m->m_dim - 1; i >= 0; i--) {
  1899. X        hash = hash * 500029 + m->m_max[i];
  1900. X        fullsize *= (m->m_max[i] - m->m_min[i] + 1);
  1901. X    }
  1902. X    hash = hash * 500041 + fullsize;
  1903. X    vp = m->m_table;
  1904. X    for (i = 0; ((i < fullsize) && (i < 16)); i++)
  1905. X        hash = hash * 500057 + hashvalue(vp++);
  1906. X    i = 16;
  1907. X    vp = &m->m_table[16];
  1908. X    skip = (fullsize / 11) + 1;
  1909. X    while (i < fullsize) {
  1910. X        hash = hash * 500069 + hashvalue(vp);
  1911. X        i += skip;
  1912. X        vp += skip;
  1913. X    }
  1914. X    return hash;
  1915. X}
  1916. X
  1917. X
  1918. X/*
  1919. X * Print a matrix and possibly few of its elements.
  1920. X * The argument supplied specifies how many elements to allow printing.
  1921. X * If any elements are printed, they are printed in short form.
  1922. X */
  1923. Xvoid
  1924. Xmatprint(m, max_print)
  1925. X    MATRIX *m;
  1926. X    long max_print;
  1927. X{
  1928. X    VALUE *vp;
  1929. X    long fullsize, count, index, num;
  1930. X    int dim, i;
  1931. X    char *msg;
  1932. X    long sizes[MAXDIM];
  1933. X
  1934. X    dim = m->m_dim;
  1935. X    fullsize = 1;
  1936. X    for (i = dim - 1; i >= 0; i--) {
  1937. X        sizes[i] = fullsize;
  1938. X        fullsize *= (m->m_max[i] - m->m_min[i] + 1);
  1939. X    }
  1940. X    msg = ((max_print > 0) ? "\nmat [" : "mat [");
  1941. X    for (i = 0; i < dim; i++) {
  1942. X        if (m->m_min[i])
  1943. X            math_fmt("%s%ld:%ld", msg, m->m_min[i], m->m_max[i]);
  1944. X        else
  1945. X            math_fmt("%s%ld", msg, m->m_max[i] + 1);
  1946. X        msg = ",";
  1947. X    }
  1948. X    if (max_print > fullsize)
  1949. X        max_print = fullsize;
  1950. X    vp = m->m_table;
  1951. X    count = 0;
  1952. X    for (index = 0; index < fullsize; index++) {
  1953. X        if ((vp->v_type != V_NUM) || !qiszero(vp->v_num))
  1954. X            count++;
  1955. X        vp++;
  1956. X    }
  1957. X    math_fmt("] (%ld element%s, %ld nonzero)",
  1958. X        fullsize, (fullsize == 1) ? "" : "s", count);
  1959. X    if (max_print <= 0)
  1960. X        return;
  1961. X
  1962. X    /*
  1963. X     * Now print the first few elements of the matrix in short
  1964. X     * and unambigous format.
  1965. X     */
  1966. X    math_str(":\n");
  1967. X    vp = m->m_table;
  1968. X    for (index = 0; index < max_print; index++) {
  1969. X        msg = "  [";
  1970. X        num = index;
  1971. X        for (i = 0; i < dim; i++) {
  1972. X            math_fmt("%s%ld", msg, m->m_min[i] + (num / sizes[i]));
  1973. X            num %= sizes[i];
  1974. X            msg = ",";
  1975. X        }
  1976. X        math_str("] = ");
  1977. X        printvalue(vp++, PRINT_SHORT | PRINT_UNAMBIG);
  1978. X        math_str("\n");
  1979. X    }
  1980. X    if (max_print < fullsize)
  1981. X        math_str("  ...\n");
  1982. X}
  1983. X
  1984. X/* END CODE */
  1985. SHAR_EOF
  1986. chmod 0644 calc2.9.0/matfunc.c || echo "restore of calc2.9.0/matfunc.c fails"
  1987. set `wc -c calc2.9.0/matfunc.c`;Sum=$1
  1988. if test "$Sum" != "29631"
  1989. then echo original size 29631, current size $Sum;fi
  1990. echo "x - extracting calc2.9.0/obj.c (Text)"
  1991. sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/obj.c &&
  1992. X/*
  1993. X * Copyright (c) 1993 David I. Bell
  1994. X * Permission is granted to use, distribute, or modify this source,
  1995. X * provided that this copyright notice remains intact.
  1996. X *
  1997. X * "Object" handling primatives.
  1998. X * This simply means that user-specified routines are called to perform
  1999. X * the indicated operations.
  2000. X */
  2001. X
  2002. X#include "calc.h"
  2003. X#include "opcodes.h"
  2004. X#include "func.h"
  2005. X#include "symbol.h"
  2006. X#include "string.h"
  2007. X
  2008. X
  2009. X/*
  2010. X * Types of values returned by calling object routines.
  2011. X */
  2012. X#define A_VALUE    0    /* returns arbitrary value */
  2013. X#define A_INT    1    /* returns integer value */
  2014. X#define A_UNDEF    2    /* returns no value */
  2015. X
  2016. X/*
  2017. X * Error handling actions for when the function is undefined.
  2018. X */
  2019. X#define E_NONE    0    /* no special action */
  2020. X#define E_PRINT    1    /* print element */
  2021. X#define E_CMP    2    /* compare two values */
  2022. X#define E_TEST    3    /* test value for nonzero */
  2023. X#define E_POW    4    /* call generic power routine */
  2024. X#define E_ONE    5    /* return number 1 */
  2025. X#define E_INC    6    /* increment by one */
  2026. X#define E_DEC    7    /* decrement by one */
  2027. X#define E_SQUARE 8    /* square value */
  2028. X
  2029. X
  2030. Xstatic struct objectinfo {
  2031. X    short args;    /* number of arguments */
  2032. X    short retval;    /* type of return value */
  2033. X    short error;    /* special action on errors */
  2034. X    char *name;    /* name of function to call */
  2035. X    char *comment;    /* useful comment if any */
  2036. X} objectinfo[] = {
  2037. X    1, A_UNDEF, E_PRINT, "print",    "print value, default prints elements",
  2038. X    1, A_VALUE, E_ONE,   "one",    "multiplicative identity, default is 1",
  2039. X    1, A_INT,   E_TEST,  "test",    "logical test (false,true => 0,1), default tests elements",
  2040. X    2, A_VALUE, E_NONE,  "add",    NULL,
  2041. X    2, A_VALUE, E_NONE,  "sub",    NULL,
  2042. X    1, A_VALUE, E_NONE,  "neg",    "negative",
  2043. X    2, A_VALUE, E_NONE,  "mul",    NULL,
  2044. X    2, A_VALUE, E_NONE,  "div",    "non-integral division",
  2045. X    1, A_VALUE, E_NONE,  "inv",    "multiplicative inverse",
  2046. X    2, A_VALUE, E_NONE,  "abs",    "absolute value within given error",
  2047. X    1, A_VALUE, E_NONE,  "norm",    "square of absolute value",
  2048. X    1, A_VALUE, E_NONE,  "conj",    "conjugate",
  2049. X    2, A_VALUE, E_POW,   "pow",    "integer power, default does multiply, square, inverse",
  2050. X    1, A_INT,   E_NONE,  "sgn",    "sign of value (-1, 0, 1)",
  2051. X    2, A_INT,   E_CMP,   "cmp",    "equality (equal,nonequal => 0,1), default tests elements",
  2052. X    2, A_INT,   E_NONE,  "rel",    "inequality (less,equal,greater => -1,0,1)",
  2053. X    2, A_VALUE, E_NONE,  "quo",    "integer quotient",
  2054. X    2, A_VALUE, E_NONE,  "mod",    "remainder of division",
  2055. X    1, A_VALUE, E_NONE,  "int",    "integer part",
  2056. X    1, A_VALUE, E_NONE,  "frac",    "fractional part",
  2057. X    1, A_VALUE, E_INC,   "inc",    "increment, default adds 1",
  2058. X    1, A_VALUE, E_DEC,   "dec",    "decrement, default subtracts 1",
  2059. X    1, A_VALUE, E_SQUARE,"square",    "default multiplies by itself",
  2060. X    2, A_VALUE, E_NONE,  "scale",    "multiply by power of 2",
  2061. X    2, A_VALUE, E_NONE,  "shift",    "shift left by n bits (right if negative)",
  2062. X    2, A_VALUE, E_NONE,  "round",    "round to given number of decimal places",
  2063. X    2, A_VALUE, E_NONE,  "bround",    "round to given number of binary places",
  2064. X    3, A_VALUE, E_NONE,  "root",    "root of value within given error",
  2065. X    2, A_VALUE, E_NONE,  "sqrt",    "square root within given error",
  2066. X    0, 0, 0, NULL
  2067. X};
  2068. X
  2069. X
  2070. Xstatic STRINGHEAD objectnames;    /* names of objects */
  2071. Xstatic STRINGHEAD elements;    /* element names for parts of objects */
  2072. Xstatic OBJECTACTIONS *objects[MAXOBJECTS]; /* table of actions for objects */
  2073. X
  2074. X
  2075. X/*
  2076. X * Free list of usual small objects.
  2077. X */
  2078. Xstatic FREELIST    freelist = {
  2079. X    sizeof(OBJECT),        /* size of typical objects */
  2080. X    100            /* number of free objects to keep */
  2081. X};
  2082. X
  2083. X
  2084. Xstatic VALUE objpowi MATH_PROTO((VALUE *vp, NUMBER *q));
  2085. Xstatic BOOL objtest MATH_PROTO((OBJECT *op));
  2086. Xstatic BOOL objcmp MATH_PROTO((OBJECT *op1, OBJECT *op2));
  2087. Xstatic void objprint MATH_PROTO((OBJECT *op));
  2088. X
  2089. X
  2090. X/*
  2091. X * Show all the routine names available for objects.
  2092. X */
  2093. Xvoid
  2094. Xshowobjfuncs()
  2095. X{
  2096. X    register struct objectinfo *oip;
  2097. X
  2098. X    printf("\nThe following object routines are definable.\n");
  2099. X    printf("Note: xx represents the actual object type name.\n\n");
  2100. X    printf("Name    Args    Comments\n");
  2101. X    for (oip = objectinfo; oip->name; oip++) {
  2102. X        printf("xx_%-8s %d    %s\n", oip->name, oip->args,
  2103. X            oip->comment ? oip->comment : "");
  2104. X    }
  2105. X    printf("\n");
  2106. X}
  2107. X
  2108. X
  2109. X/*
  2110. X * Call the appropriate user-defined routine to handle an object action.
  2111. X * Returns the value that the routine returned.
  2112. X */
  2113. XVALUE
  2114. Xobjcall(action, v1, v2, v3)
  2115. X    VALUE *v1, *v2, *v3;
  2116. X{
  2117. X    FUNC *fp;        /* function to call */
  2118. X    OBJECTACTIONS *oap;    /* object to call for */
  2119. X    struct objectinfo *oip;    /* information about action */
  2120. X    long index;        /* index of function (negative if undefined) */
  2121. X    VALUE val;        /* return value */
  2122. X    VALUE tmp;        /* temp value */
  2123. X    char name[SYMBOLSIZE+1];    /* full name of user routine to call */
  2124. X
  2125. X    if ((unsigned)action > OBJ_MAXFUNC)
  2126. X        math_error("Illegal action for object call");
  2127. X    oip = &objectinfo[action];
  2128. X    if (v1->v_type == V_OBJ)
  2129. X        oap = v1->v_obj->o_actions;
  2130. X    else if (v2->v_type == V_OBJ)
  2131. X        oap = v2->v_obj->o_actions;
  2132. X    else
  2133. X        math_error("Object routine called with non-object");
  2134. X    index = oap->actions[action];
  2135. X    if (index == 0) {
  2136. X        strcpy(name, oap->name);
  2137. X        strcat(name, "_");
  2138. X        strcat(name, oip->name);
  2139. X        index = adduserfunc(name);
  2140. X        oap->actions[action] = index;
  2141. X    }
  2142. X    fp = NULL;
  2143. X    if (index > 0)
  2144. X        fp = findfunc(index);
  2145. X    if (fp == NULL) {
  2146. X        switch (oip->error) {
  2147. X            case E_PRINT:
  2148. X                objprint(v1->v_obj);
  2149. X                val.v_type = V_NULL;
  2150. X                break;
  2151. X            case E_CMP:
  2152. X                val.v_type = V_INT;
  2153. X                if (v1->v_type != v2->v_type) {
  2154. X                    val.v_int = 1;
  2155. X                    return val;
  2156. X                }
  2157. X                val.v_int = objcmp(v1->v_obj, v2->v_obj);
  2158. X                break;
  2159. X            case E_TEST:
  2160. X                val.v_type = V_INT;
  2161. X                val.v_int = objtest(v1->v_obj);
  2162. X                break;
  2163. X            case E_POW:
  2164. X                if (v2->v_type != V_NUM)
  2165. X                    math_error("Non-real power");
  2166. X                val = objpowi(v1, v2->v_num);
  2167. X                break;
  2168. X            case E_ONE:
  2169. X                val.v_type = V_NUM;
  2170. X                val.v_num = qlink(&_qone_);
  2171. X                break;
  2172. X            case E_INC:
  2173. X                tmp.v_type = V_NUM;
  2174. X                tmp.v_num = &_qone_;
  2175. X                val = objcall(OBJ_ADD, v1, &tmp, NULL_VALUE);
  2176. X                break;
  2177. X            case E_DEC:
  2178. X                tmp.v_type = V_NUM;
  2179. X                tmp.v_num = &_qone_;
  2180. X                val = objcall(OBJ_SUB, v1, &tmp, NULL_VALUE);
  2181. X                break;
  2182. X            case E_SQUARE:
  2183. X                val = objcall(OBJ_MUL, v1, v1, NULL_VALUE);
  2184. X                break;
  2185. X            default:
  2186. X                math_error("Function \"%s\" is undefined", namefunc(index));
  2187. X        }
  2188. X        return val;
  2189. X    }
  2190. X    switch (oip->args) {
  2191. X        case 0:
  2192. X            break;
  2193. X        case 1:
  2194. X            ++stack;
  2195. X            stack->v_addr = v1;
  2196. X            stack->v_type = V_ADDR;
  2197. X            break;
  2198. X        case 2:
  2199. X            ++stack;
  2200. X            stack->v_addr = v1;
  2201. X            stack->v_type = V_ADDR;
  2202. X            ++stack;
  2203. X            stack->v_addr = v2;
  2204. X            stack->v_type = V_ADDR;
  2205. X            break;
  2206. X        case 3:
  2207. X            ++stack;
  2208. X            stack->v_addr = v1;
  2209. X            stack->v_type = V_ADDR;
  2210. X            ++stack;
  2211. X            stack->v_addr = v2;
  2212. X            stack->v_type = V_ADDR;
  2213. X            ++stack;
  2214. X            stack->v_addr = v3;
  2215. X            stack->v_type = V_ADDR;
  2216. X            break;
  2217. X        default:
  2218. X            math_error("Bad number of args to calculate");
  2219. X    }
  2220. X    calculate(fp, oip->args);
  2221. X    switch (oip->retval) {
  2222. X        case A_VALUE:
  2223. X            return *stack--;
  2224. X        case A_UNDEF:
  2225. X            freevalue(stack--);
  2226. X            val.v_type = V_NULL;
  2227. X            break;
  2228. X        case A_INT:
  2229. X            if ((stack->v_type != V_NUM) || qisfrac(stack->v_num))
  2230. X                math_error("Integer return value required");
  2231. X            index = qtoi(stack->v_num);
  2232. X            qfree(stack->v_num);
  2233. X            stack--;
  2234. X            val.v_type = V_INT;
  2235. X            val.v_int = index;
  2236. X            break;
  2237. X        default:
  2238. X            math_error("Bad object return");
  2239. X    }
  2240. X    return val;
  2241. X}
  2242. X
  2243. X
  2244. X/*
  2245. X * Routine called to clear the cache of known undefined functions for
  2246. X * the objects.  This changes negative indices back into positive ones
  2247. X * so that they will all be checked for existence again.
  2248. X */
  2249. Xvoid
  2250. Xobjuncache()
  2251. X{
  2252. X    register int *ip;
  2253. X    int i, j;
  2254. X
  2255. X    i = objectnames.h_count;
  2256. X    while (--i >= 0) {
  2257. X        ip = objects[i]->actions;
  2258. X        for (j = OBJ_MAXFUNC; j-- >= 0; ip++)
  2259. X            if (*ip < 0)
  2260. X                *ip = -*ip;
  2261. X    }
  2262. X}
  2263. X
  2264. X
  2265. X/*
  2266. X * Print the elements of an object in short and unambiguous format.
  2267. X * This is the default routine if the user's is not defined.
  2268. X */
  2269. Xstatic void
  2270. Xobjprint(op)
  2271. X    OBJECT *op;        /* object being printed */
  2272. X{
  2273. X    int count;        /* number of elements */
  2274. X    int i;            /* index */
  2275. X
  2276. X    count = op->o_actions->count;
  2277. X    math_fmt("obj %s {", op->o_actions->name);
  2278. X    for (i = 0; i < count; i++) {
  2279. X        if (i)
  2280. X            math_str(", ");
  2281. X        printvalue(&op->o_table[i], PRINT_SHORT | PRINT_UNAMBIG);
  2282. X    }
  2283. X    math_chr('}');
  2284. X}
  2285. X
  2286. X
  2287. X/*
  2288. X * Test an object for being "nonzero".
  2289. X * This is the default routine if the user's is not defined.
  2290. X * Returns TRUE if any of the elements are "nonzero".
  2291. X */
  2292. Xstatic BOOL
  2293. Xobjtest(op)
  2294. X    OBJECT *op;
  2295. X{
  2296. X    int i;            /* loop counter */
  2297. X
  2298. X    i = op->o_actions->count;
  2299. X    while (--i >= 0) {
  2300. X        if (testvalue(&op->o_table[i]))
  2301. X            return TRUE;
  2302. X    }
  2303. X    return FALSE;
  2304. X}
  2305. X
  2306. X
  2307. X/*
  2308. X * Compare two objects for equality, returning TRUE if they differ.
  2309. X * This is the default routine if the user's is not defined.
  2310. X * For equality, all elements must be equal.
  2311. X */
  2312. Xstatic BOOL
  2313. Xobjcmp(op1, op2)
  2314. X    OBJECT *op1, *op2;
  2315. X{
  2316. X    int i;            /* loop counter */
  2317. X
  2318. X    if (op1->o_actions != op2->o_actions)
  2319. X        return TRUE;
  2320. X    i = op1->o_actions->count;
  2321. X    while (--i >= 0) {
  2322. X        if (comparevalue(&op1->o_table[i], &op2->o_table[i]))
  2323. X            return TRUE;
  2324. X    }
  2325. X    return FALSE;
  2326. X}
  2327. X
  2328. X
  2329. X/*
  2330. X * Raise an object to an integral power.
  2331. X * This is the default routine if the user's is not defined.
  2332. X * Negative powers mean the positive power of the inverse.
  2333. X * Zero means the multiplicative identity.
  2334. X */
  2335. Xstatic VALUE
  2336. Xobjpowi(vp, q)
  2337. X    VALUE *vp;        /* value to be powered */
  2338. X    NUMBER *q;        /* power to raise number to */
  2339. X{
  2340. X    VALUE res, tmp;
  2341. X    long power;        /* power to raise to */
  2342. X    unsigned long bit;    /* current bit value */
  2343. X
  2344. X    if (qisfrac(q))
  2345. X        math_error("Raising object to non-integral power");
  2346. X    if (zisbig(q->num))
  2347. X        math_error("Raising object to very large power");
  2348. X    power = (zistiny(q->num) ? z1tol(q->num) : z2tol(q->num));
  2349. X    if (qisneg(q))
  2350. X        power = -power;
  2351. X    /*
  2352. X     * Handle some low powers specially
  2353. X     */
  2354. X    if ((power <= 2) && (power >= -2)) {
  2355. X        switch ((int) power) {
  2356. X            case 0:
  2357. X                return objcall(OBJ_ONE, vp, NULL_VALUE, NULL_VALUE);
  2358. X            case 1:
  2359. X                res.v_obj = objcopy(vp->v_obj);
  2360. X                res.v_type = V_OBJ;
  2361. X                return res;
  2362. X            case -1:
  2363. X                return objcall(OBJ_INV, vp, NULL_VALUE, NULL_VALUE);
  2364. X            case 2:
  2365. X                return objcall(OBJ_SQUARE, vp, NULL_VALUE, NULL_VALUE);
  2366. X        }
  2367. X    }
  2368. X    if (power < 0)
  2369. X        power = -power;
  2370. X    /*
  2371. X     * Compute the power by squaring and multiplying.
  2372. X     * This uses the left to right method of power raising.
  2373. X     */
  2374. X    bit = TOPFULL;
  2375. X    while ((bit & power) == 0)
  2376. X        bit >>= 1L;
  2377. X    bit >>= 1L;
  2378. X    res = objcall(OBJ_SQUARE, vp, NULL_VALUE, NULL_VALUE);
  2379. X    if (bit & power) {
  2380. X        tmp = objcall(OBJ_MUL, &res, vp, NULL_VALUE);
  2381. X        objfree(res.v_obj);
  2382. X        res = tmp;
  2383. X    }
  2384. X    bit >>= 1L;
  2385. X    while (bit) {
  2386. X        tmp = objcall(OBJ_SQUARE, &res, NULL_VALUE, NULL_VALUE);
  2387. X        objfree(res.v_obj);
  2388. X        res = tmp;
  2389. X        if (bit & power) {
  2390. X            tmp = objcall(OBJ_MUL, &res, vp, NULL_VALUE);
  2391. X            objfree(res.v_obj);
  2392. X            res = tmp;
  2393. X        }
  2394. X        bit >>= 1L;
  2395. X    }
  2396. X    if (qisneg(q)) {
  2397. X        tmp = objcall(OBJ_INV, &res, NULL_VALUE, NULL_VALUE);
  2398. X        objfree(res.v_obj);
  2399. X        return tmp;
  2400. X    }
  2401. X    return res;
  2402. X}
  2403. X
  2404. X
  2405. X/*
  2406. X * Define a (possibly) new class of objects.
  2407. X * The list of indexes for the element names is also specified here,
  2408. X * and the number of elements defined for the object.
  2409. X */
  2410. Xvoid
  2411. Xdefineobject(name, indices, count)
  2412. X    char *name;        /* name of object type */
  2413. X    int indices[];        /* table of indices for elements */
  2414. X{
  2415. X    OBJECTACTIONS *oap;    /* object definition structure */
  2416. X    STRINGHEAD *hp;
  2417. X    int index;
  2418. X
  2419. X    hp = &objectnames;
  2420. X    if (hp->h_list == NULL)
  2421. X        initstr(hp);
  2422. X    index = findstr(hp, name);
  2423. X    if (index >= 0) {
  2424. X        /*
  2425. X         * Object is already defined.  Give an error unless this
  2426. X         * new definition is exactly the same as the old one.
  2427. X         */
  2428. X        oap = objects[index];
  2429. X        if (oap->count == count) {
  2430. X            for (index = 0; ; index++) {
  2431. X                if (index >= count)
  2432. X                    return;
  2433. X                if (oap->elements[index] != indices[index])
  2434. X                    break;
  2435. X            }
  2436. X        }
  2437. X        math_error("Object type \"%s\" is already defined", name);
  2438. X    }
  2439. X
  2440. X    if (hp->h_count >= MAXOBJECTS)
  2441. X        math_error("Too many object types in use");
  2442. X    oap = (OBJECTACTIONS *) malloc(objectactionsize(count));
  2443. X    if (oap)
  2444. X        name = addstr(hp, name);
  2445. X    if ((oap == NULL) || (name == NULL))
  2446. X        math_error("Cannot allocate object type");
  2447. X    oap->name = name;
  2448. X    oap->count = count;
  2449. X    for (index = OBJ_MAXFUNC; index >= 0; index--)
  2450. X        oap->actions[index] = 0;
  2451. X    for (index = 0; index < count; index++)
  2452. X        oap->elements[index] = indices[index];
  2453. X    index = findstr(hp, name);
  2454. X    objects[index] = oap;
  2455. X    return;
  2456. X}
  2457. X
  2458. X
  2459. X/*
  2460. X * Check an object name to see if it is currently defined.
  2461. X * If so, the index for the object type is returned.
  2462. X * If the object name is currently unknown, then -1 is returned.
  2463. X */
  2464. Xint
  2465. Xcheckobject(name)
  2466. X    char *name;
  2467. X{
  2468. X    STRINGHEAD *hp;
  2469. X
  2470. X    hp = &objectnames;
  2471. X    if (hp->h_list == NULL)
  2472. X        return -1;
  2473. X    return findstr(hp, name);
  2474. X}
  2475. X
  2476. X
  2477. X/*
  2478. X * Define a (possibly) new element name for an object.
  2479. X * Returns an index which identifies the element name.
  2480. X */
  2481. Xint
  2482. Xaddelement(name)
  2483. X    char *name;
  2484. X{
  2485. X    STRINGHEAD *hp;
  2486. X    int index;
  2487. X
  2488. X    hp = &elements;
  2489. X    if (hp->h_list == NULL)
  2490. X        initstr(hp);
  2491. X    index = findstr(hp, name);
  2492. X    if (index >= 0)
  2493. X        return index;
  2494. X    if (addstr(hp, name) == NULL)
  2495. X        math_error("Cannot allocate element name");
  2496. X    return findstr(hp, name);
  2497. X}
  2498. X
  2499. X
  2500. X/*
  2501. X * Return the index which identifies an element name.
  2502. X * Returns minus one if the element name is unknown.
  2503. X */
  2504. Xint
  2505. Xfindelement(name)
  2506. X    char *name;        /* element name */
  2507. X{
  2508. X    if (elements.h_list == NULL)
  2509. X        return -1;
  2510. X    return findstr(&elements, name);
  2511. X}
  2512. X
  2513. X
  2514. X/*
  2515. X * Return the value table offset to be used for an object element name.
  2516. SHAR_EOF
  2517. echo "End of part 6"
  2518. echo "File calc2.9.0/obj.c is continued in part 7"
  2519. echo "7" > s2_seq_.tmp
  2520. exit 0
  2521.