/usr/share/acl2-8.0dfsg/other-processes.lisp is in acl2-source 8.0dfsg-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 | ; ACL2 Version 8.0 -- A Computational Logic for Applicative Common Lisp
; Copyright (C) 2017, Regents of the University of Texas
; This version of ACL2 is a descendent of ACL2 Version 1.9, Copyright
; (C) 1997 Computational Logic, Inc. See the documentation topic NOTE-2-0.
; This program is free software; you can redistribute it and/or modify
; it under the terms of the LICENSE file distributed with ACL2.
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; LICENSE for more details.
; Written by: Matt Kaufmann and J Strother Moore
; email: Kaufmann@cs.utexas.edu and Moore@cs.utexas.edu
; Department of Computer Science
; University of Texas at Austin
; Austin, TX 78712 U.S.A.
(in-package "ACL2")
; Our top-level function for generating variables attempts to feed
; genvar roots that generate names suggestive of the term being
; replaced by the variable. We now develop the code for generating
; these roots. It involves a recursive descent through a term. At
; the bottom, we see variable symbols, e.g., ABC123, and we wish to
; generate the root '("ABC" . 124).
(defun strip-final-digits1 (lst)
; See strip-final-digits.
(cond ((null lst) (mv "" 0))
((member (car lst) '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
(mv-let (str n)
(strip-final-digits1 (cdr lst))
(mv str (+ (let ((c (car lst)))
(case c
(#\0 0)
(#\1 1)
(#\2 2)
(#\3 3)
(#\4 4)
(#\5 5)
(#\6 6)
(#\7 7)
(#\8 8)
(otherwise 9)))
(* 10 n)))))
(t (mv (coerce (reverse lst) 'string) 0))))
(defun strip-final-digits (str)
; Given a string, such as "ABC123", we strip off the final digits in it,
; and compute the number they represent. We return two things,
; the string and the number, e.g., "ABC" and 123.
(strip-final-digits1 (reverse (coerce str 'list))))
; For non-variable, non-quote terms we try first the idea of
; generating a name based on the type of the term. The following
; constant associates with selected type sets the names of some
; variables that we find pleasing and suggestive of the type. When we
; generalize a term we look at its type and if it is a subtype of one
; of those listed we prefer to use the variables given. The first
; variable in each family is additionally used as the root for a
; gensym, should it come to that. This list can be extended
; arbitrarily without affecting soundness, as long as (a) the car of
; each pair below is a type set and (b) the cdr is a true-list of
; symbols. Arbitrary overlaps between the types and between the
; symbols are permitted.
;; Historical Comment from Ruben Gamboa:
;; I changed rational to real and complex-rational to complex in
;; the list below, since the new types are supersets of the old types,
;; so it should be harmless.
(defconst *var-families-by-type*
(list (cons *ts-integer* '(I J K L M N))
(cons #+:non-standard-analysis
*ts-real*
#-:non-standard-analysis
*ts-rational*
'(R S I J K L M N))
(cons #+:non-standard-analysis
*ts-complex*
#-:non-standard-analysis
*ts-complex-rational*
'(Z R S I J K L M N))
(cons *ts-cons* '(L LST))
(cons *ts-boolean* '(P Q R))
(cons *ts-symbol* '(A B C D E))
(cons *ts-string* '(S STR))
(cons *ts-character* '(C CH))))
; The following function is used to find the family of vars, given the
; type set of a term:
(defun assoc-ts-subsetp (ts alist)
; Like assoc except we compare with ts-subsetp.
(cond ((null alist) nil)
((ts-subsetp ts (caar alist)) (car alist))
(t (assoc-ts-subsetp ts (cdr alist)))))
; And here is how we look for an acceptable variable.
(defun first-non-member-eq (lst1 lst2)
; Return the first member of lst1 that is not a member-eq of lst2.
(cond ((null lst1) nil)
((member-eq (car lst1) lst2)
(first-non-member-eq (cdr lst1) lst2))
(t (car lst1))))
; If the above techniques don't lead to a choice we generate a string
; from the term by abbreviating the first symbol in the term. Here is
; how we abbreviate:
(defun abbreviate-hyphenated-string1 (str i maximum prev-c)
; We return a list of characters that, when coerced to a string,
; abbreviates string str from position i to (but not including) maximum.
; Currently, it returns the first character after each block of "hyphens"
; and the last character. Thus, "PITON-TEMP-STK" is abbreviated
; "PTSK".
; If prev-char is T it means we output the character we last saw.
; If prev-char is NIL it means the character we last saw was a "hyphen".
; Otherwise, prev-char is the previous character. "Hyphen" here means
; any one of several commonly used "word separators" in symbols.
; This function can be changed arbitrarily as long as it returns a
; list of characters.
(cond
((< i maximum)
(let ((c (char str i)))
(cond
((member c '(#\- #\_ #\. #\/ #\+))
(abbreviate-hyphenated-string1 str (1+ i) maximum nil))
((null prev-c)
(cons c (abbreviate-hyphenated-string1 str (1+ i) maximum t)))
(t (abbreviate-hyphenated-string1 str (1+ i) maximum c)))))
((characterp prev-c) (list prev-c))
(t nil)))
(defun abbreviate-hyphenated-string (str)
; The function scans a string and collects the first and last character
; and every character immediately after a block of "hyphens" as defined
; above.
(let ((lst (abbreviate-hyphenated-string1 str 0 (length str) nil)))
(coerce
(cond ((or (null lst)
(member (car lst) *suspiciously-first-numeric-chars*))
(cons #\V lst))
(t lst))
'string)))
; Just as strip-final-digits produces the genvar root for a variable,
; the following function produces the genvar root for a nonvariable term.
(defun generate-variable-root1 (term avoid-lst type-alist ens wrld)
; Term is a nonvariable, non-quote term. This function returns two
; results, str and n, such that (str . n) is a "root" for genvar.
; In fact, it tries to return a root that when fed to genvar will
; create a variable symbol that is suggestive of term and which does
; not occur in avoid-lst. But the function is correct as long as it
; returns any root, which could be any string.
(mv-let
(ts ttree)
(type-set term t nil type-alist ens wrld nil nil nil)
; Note: We don't really know that the guards have been checked and we
; don't split on the 'assumptions we have forced. But our only use of
; type set here is heuristic. This also explains why we just use the
; global enabled structure and ignore the ttree.
(declare (ignore ttree))
(let* ((family (cdr (assoc-ts-subsetp ts *var-families-by-type*)))
(var (first-non-member-eq family avoid-lst)))
(cond (var
; If the type set of term is one of those for which we have a var family
; and some member of that family does not occur in avoid-lst, then we will
; use the symbol-name of var as the root from which to generate a
; variable symbol for term. This will almost certainly result in the
; generation of the symbol var by genvar. The only condition under which
; this won't happen is if var is an illegal variable symbol, in which case
; genvar will suffix it with some sufficiently large natural.
(mv (symbol-name var) nil))
(family
; If we have a family for this type of term but all the members are
; to be avoided, we'll genvar from the first member of the family and
; we might as well start suffixing immediately (from 0) because we
; know the unsuffixed var is in avoid-lst.
(mv (symbol-name (car family)) 0))
(t
; Otherwise, we will genvar from an abbreviated version of the "first
; symbol" in term.
(mv (abbreviate-hyphenated-string
(symbol-name
(cond ((variablep term) 'z) ; never happens
((fquotep term) 'z) ; never happens
((flambda-applicationp term) 'z)
(t (ffn-symb term)))))
nil))))))
; And here we put them together with one last convention. The
; root for (CAR ...) is just the root for ..., except we force
; there to be a suffix. Thus, the root for (CAR X4) is going to be
; ("X" . 5).
(defun generate-variable-root (term avoid-lst type-alist ens wrld)
(cond
((variablep term)
(mv-let (str n)
(strip-final-digits (symbol-name term))
(mv str (1+ n))))
((fquotep term) (mv "CONST" 0))
((eq (ffn-symb term) 'car)
(mv-let (str n)
(generate-variable-root (fargn term 1) avoid-lst type-alist ens
wrld)
(mv str (or n 0))))
((eq (ffn-symb term) 'cdr)
(mv-let (str n)
(generate-variable-root (fargn term 1) avoid-lst type-alist ens
wrld)
(mv str (or n 0))))
(t (generate-variable-root1 term avoid-lst type-alist ens wrld))))
(defun generate-variable (term avoid-lst type-alist ens wrld)
; We generate a legal variable symbol that does not occur in avoid-lst. We use
; term, type-alist, ens, and wrld in a heuristic way to suggest a preferred
; name for the symbol. Generally speaking, the symbol we generate will be used
; to replace term in some conjecture, so we try to generate a symbol that we
; think "suggests" term.
(mv-let (str n)
(generate-variable-root term avoid-lst type-alist ens wrld)
(genvar (find-pkg-witness term) str n avoid-lst)))
(defun generate-variable-lst (term-lst avoid-lst type-alist ens wrld)
; And here we generate a list of variable names sequentially, one for
; each term in term-lst.
; See also generate-variable-lst-simple, which only requires the first two of
; the formals above.
(cond ((null term-lst) nil)
(t
(let ((var (generate-variable (car term-lst) avoid-lst
type-alist ens wrld)))
(cons var (generate-variable-lst (cdr term-lst)
(cons var avoid-lst)
type-alist ens wrld))))))
; That completes the code for generating new variable names.
; An elim-rule, as declared below, denotes a theorem of the form
; (implies hyps (equal lhs rhs)), where rhs is a variable symbol and
; lhs involves the terms destructor-terms, each of which is of the
; form (dfn v1 ... vn), where the vi are distinct variables and {v1
; ... vn} are all the variables in the formula. We call rhs the
; "crucial variable". It is the one we will "puff up" to eliminate
; the destructor terms. For example, in (CONSP X) -> (CONS (CAR X)
; (CDR X)) = X, X is the crucial variable and puffing it up to (CONS A
; B) we can eliminate (CAR X) and (CDR X). We store an elim-rule
; under the function symbol, dfn, of each destructor term. The rule
; we store for (dfn v1 ... vn) has that term as the car of destructor-
; terms and has crucial-position j where (nth j '(v1 ... vn)) = rhs.
; (Thus, the crucial-position is the position in the args at which the
; crucial variable occurs and for these purposes we enumerate the args
; from 0 (as by nth) rather than from 1 (as by fargn).)
(defrec elim-rule
(((nume . crucial-position) . (destructor-term . destructor-terms))
(hyps . equiv)
(lhs . rhs)
. rune) nil)
(defun occurs-nowhere-else (var args c i)
; Index the elements of args starting at i. Scan all args except the
; one with index c and return nil if var occurs in one of them and t
; otherwise.
(cond ((null args) t)
((int= c i)
(occurs-nowhere-else var (cdr args) c (1+ i)))
((dumb-occur var (car args)) nil)
(t (occurs-nowhere-else var (cdr args) c (1+ i)))))
(defun first-nomination (term votes nominations)
; See nominate-destructor-candidate for an explanation.
(cons (cons term (cons term votes))
nominations))
(defun second-nomination (term votes nominations)
; See nominate-destructor-candidate for an explanation.
(cond ((null nominations) nil)
((equal term (car (car nominations)))
(cons (cons term
(union-equal votes (cdr (car nominations))))
(cdr nominations)))
(t (cons (car nominations)
(second-nomination term votes (cdr nominations))))))
(defun some-hyp-probably-nilp (hyps type-alist ens wrld)
; The name of this function is meant to limit its use to heuristics.
; In fact, if this function says some hyp is probably nil then in fact
; some hyp is known to be nil under the given type-alist, wrld and
; some forced 'assumptions.
; Since the function actually ignores 'assumptions generated, its use
; must be limited to heuristic situations. When it says "yes, some
; hyp is probably nil" we choose not to pursue the establishment of
; those hyps.
(cond
((null hyps) nil)
(t (mv-let
(knownp nilp ttree)
(known-whether-nil
(car hyps) type-alist ens (ok-to-force-ens ens)
nil ; dwp
wrld nil)
(declare (ignore ttree))
(cond ((and knownp nilp) t)
(t (some-hyp-probably-nilp (cdr hyps) type-alist ens wrld)))))))
(mutual-recursion
(defun sublis-expr (alist term)
; Alist is of the form ((a1 . b1) ... (ak . bk)) where the ai and bi are
; all terms. We substitute bi for each occurrence of ai in term.
; Thus, if the ai are distinct variables, this function is equivalent to
; sublis-var. We do not look for ai's properly inside of quoted objects.
; Thus,
; (sublis-expr '(('3 . x)) '(f '3)) = '(f x)
; but
; (sublis-expr '(('3 . x)) '(f '(3 . 4))) = '(f '(3 . 4)).
(let ((temp (assoc-equal term alist)))
(cond (temp (cdr temp))
((variablep term) term)
((fquotep term) term)
(t (cons-term (ffn-symb term)
(sublis-expr-lst alist (fargs term)))))))
(defun sublis-expr-lst (alist lst)
(cond ((null lst) nil)
(t (cons (sublis-expr alist (car lst))
(sublis-expr-lst alist (cdr lst))))))
)
(defun nominate-destructor-candidate
(term eliminables type-alist clause ens wrld votes nominations)
; This function recognizes candidates for destructor elimination. It
; is assumed that term is a non-variable, non-quotep term. To be a
; candidate the term must not be a lambda application and the function
; symbol of the term must have an enabled destructor elimination rule.
; Furthermore, the crucial argument position of the term must be
; occupied by a variable symbol that is a member of the eliminables,
; that occurs only in equiv-hittable positions within the clause,
; and that occurs nowhere else in the arguments of the term, or else
; the crucial argument position must be occupied by a term that itself
; is recursively a candidate. (Note that if the crucial argument is
; an eliminable term then when we eliminate it we will introduce a
; suitable distinct var into the crucial argument of this term and
; hence it will be eliminable.) Finally, the instantiated hypotheses
; of the destructor elimination rule must not be known nil under the
; type-alist.
; Votes and nominations are accumulators. Votes is a list of terms
; that contain term and will be candidates if term is eliminated.
; Nominations are explained below.
; If term is a candidate we either "nominate" it, by adding a
; "nomination" for term to the running accumulator nominations, or
; else we "second" a prior nomination for it. A nomination of a term
; is a list of the form (dterm . votes) where dterm is the innermost
; eliminable candidate in term and votes is a list of all the terms
; that will be eliminable if dterm is eliminated. To "second" a
; nomination is simply to add yourself as a vote.
; For example, if X is eliminable then (CAR (CAR (CAR X))) is a
; candidate. If nominations is initially nil then at the conclusion
; of this function it will be
; (((CAR X) (CAR X) (CAR (CAR X)) (CAR (CAR (CAR X))))).
; We always return a nominations list.
(cond
((flambda-applicationp term) nominations)
(t (let ((rule (getpropc (ffn-symb term) 'eliminate-destructors-rule nil
wrld)))
(cond
((or (null rule)
(not (enabled-numep (access elim-rule rule :nume) ens)))
nominations)
(t (let ((crucial-arg (nth (access elim-rule rule :crucial-position)
(fargs term))))
(cond
((variablep crucial-arg)
; Next we wish to determine that every occurrence of the crucial
; argument -- outside of the destructor nests themselves -- is equiv
; hittable. For example, for car-cdr-elim, where we have A as the
; crucial arg (meaning term, above, is (CAR A) or (CDR A)), we wish to
; determine that every A in the clause is equal-hittable, except those
; A's occurring inside the (CAR A) and (CDR A) destructors. Suppose
; the clause is p(A,(CAR A),(CDR A)). The logical explanation of what
; elim does is to replace the A's not in the destructor nests by (CONS
; (CAR A) (CDR A)) and then generalize (CAR A) to HD and (CDR A) to
; TL. This will produce p((CONS HD TL), HD, TL). Observe that we do
; not actually hit the A's inside the CAR and CDR. So we do not
; require that they be equiv-hittable. (This situation actually
; arises in the elim rule for sets, where equiv tests equality on the
; canonicalizations. In this setting, equiv is not a congruence for
; the destructors.) So the question then is how do we detect that all
; the ``naked'' A's are equiv-hittable? We ``ought'' to generalize
; away the instantiated destructor terms and then ask whether all the
; A's are equiv-hittable. But we do not want to pay the price of
; generating n distinct new variable symbols. So we just replace
; every destructor term by NIL. This creates a ``pseudo-clause;'' the
; ``terms'' in it are not really legal -- NIL is not a variable
; symbol. We only use this pseudo-clause to answer the question of
; whether the crucial variable, which certainly isn't NIL, is
; equiv-hittable in every occurrence.
(let* ((alist (pairlis$
(fargs
(access elim-rule rule :destructor-term))
(fargs term)))
(inst-destructors
(sublis-var-lst
alist
(cons (access elim-rule rule :destructor-term)
(access elim-rule rule :destructor-terms))))
(pseudo-clause (sublis-expr-lst
(pairlis$ inst-destructors nil)
clause)))
(cond
((not (every-occurrence-equiv-hittablep-in-clausep
(access elim-rule rule :equiv)
crucial-arg
pseudo-clause ens wrld))
nominations)
((assoc-equal term nominations)
(second-nomination term votes nominations))
((member crucial-arg eliminables)
(cond
((occurs-nowhere-else crucial-arg
(fargs term)
(access elim-rule rule
:crucial-position)
0)
(let* ((inst-hyps
(sublis-var-lst alist
(access elim-rule rule :hyps))))
(cond
((some-hyp-probably-nilp inst-hyps
type-alist ens wrld)
nominations)
(t (first-nomination term votes nominations)))))
(t nominations)))
(t nominations))))
(t (nominate-destructor-candidate crucial-arg
eliminables
type-alist
clause
ens
wrld
(cons term votes)
nominations))))))))))
(mutual-recursion
(defun nominate-destructor-candidates
(term eliminables type-alist clause ens wrld nominations)
; We explore term and accumulate onto nominations all the nominations.
(cond ((variablep term) nominations)
((fquotep term) nominations)
(t (nominate-destructor-candidates-lst
(fargs term)
eliminables
type-alist
clause
ens
wrld
(nominate-destructor-candidate term
eliminables
type-alist
clause
ens
wrld
nil
nominations)))))
(defun nominate-destructor-candidates-lst
(terms eliminables type-alist clause ens wrld nominations)
(cond ((null terms) nominations)
(t (nominate-destructor-candidates-lst
(cdr terms)
eliminables
type-alist
clause
ens
wrld
(nominate-destructor-candidates (car terms)
eliminables
type-alist
clause
ens
wrld
nominations)))))
)
; We next turn to the problem of choosing which candidate we will eliminate.
; We want to eliminate the most complicated one. We measure them with
; max-level-no, which is also used by the defuns principle to store the
; level-no of each fn. Max-level-no was originally defined here, but it is
; mutually recursive with get-level-no, a function we call earlier in the ACL2
; sources, in sort-approved1-rating1.
(defun sum-level-nos (lst wrld)
; Lst is a list of non-variable, non-quotep terms. We sum the
; level-no of the function symbols of the terms. For the level no of
; a lambda expression we use the max level no of its body, just as
; would be done if a non-recursive function with the same body were
; being applied.
(cond ((null lst) 0)
(t (+ (if (flambda-applicationp (car lst))
(max-level-no (lambda-body (ffn-symb (car lst))) wrld)
(or (getpropc (ffn-symb (car lst)) 'level-no
nil wrld)
0))
(sum-level-nos (cdr lst) wrld)))))
(defun pick-highest-sum-level-nos (nominations wrld dterm max-score)
; Nominations is a list of pairs of the form (dterm . votes), where
; votes is a list of terms. The "score" of a dterm is the
; sum-level-nos of its votes. We scan nominations and return a dterm
; with maximal score, assuming that dterm and max-score are the
; winning dterm and its score seen so far.
(cond
((null nominations) dterm)
(t (let ((score (sum-level-nos (cdr (car nominations)) wrld)))
(cond
((> score max-score)
(pick-highest-sum-level-nos (cdr nominations) wrld
(caar nominations) score))
(t
(pick-highest-sum-level-nos (cdr nominations) wrld
dterm max-score)))))))
(defun select-instantiated-elim-rule (clause type-alist eliminables ens wrld)
; Clause is a clause to which we wish to apply destructor elimination.
; Type-alist is the type-alist obtained by assuming all literals of cl nil.
; Eliminables is the list of legal "crucial variables" which can be
; "puffed up" to do an elim. For example, to eliminate (CAR X), X
; must be puffed up to (CONS A B). X is the crucial variable in (CAR
; X). Upon entry to the destructor elimination process we consider
; all the variables eliminable (except the ones historically
; introduced by elim). But once we get going within the elim process,
; the only eliminable variables are the ones we introduce ourselves
; (because they won't be eliminable by subsequent processes since they
; were introduced by elim).
; If there is at least one nomination for an elim, we choose the one
; with maximal score and return an instantiated version of the
; elim-rule corresponding to it. Otherwise we return nil.
(let ((nominations
(nominate-destructor-candidates-lst clause
eliminables
type-alist
clause
ens
wrld
nil)))
(cond
((null nominations) nil)
(t
(let* ((dterm (pick-highest-sum-level-nos nominations wrld nil -1))
(rule (getpropc (ffn-symb dterm) 'eliminate-destructors-rule
nil wrld))
(alist (pairlis$ (fargs (access elim-rule rule :destructor-term))
(fargs dterm))))
(change elim-rule rule
:hyps (sublis-var-lst alist (access elim-rule rule :hyps))
:lhs (sublis-var alist (access elim-rule rule :lhs))
:rhs (sublis-var alist (access elim-rule rule :rhs))
:destructor-term
(sublis-var alist (access elim-rule rule :destructor-term))
:destructor-terms
(sublis-var-lst
alist
(access elim-rule rule :destructor-terms))))))))
; We now take a break from elim and develop the code for the generalization
; that elim uses. We want to be able to replace terms by variables
; (sublis-expr, above), we want to be able to restrict the new variables by
; noting type-sets of the terms replaced, and we want to be able to use
; generalization rules provided in the database.
(defun type-restriction-segment (cl terms vars type-alist ens wrld)
; Warning: This function calls clausify using the sr-limit from the world, not
; from the rewrite-constant. Do not call this function from the simplifier
; without thinking about passing in the sr-limit.
; Cl is a clause. Terms is a list of terms and is in 1:1
; correspondence with vars, which is a list of vars. Type-alist is
; the result of assuming false every literal of cl. This function
; returns three results. The first is a list of literals that can be
; disjoined to cl without altering the validity of cl. The second is
; a subset of vars. The third is an extension of ttree. Technically
; speaking, this function may return any list of terms with the
; property that every term in it is false (under the assumptions in
; type-alist) and any subset of vars, provided the ttree returned is
; an extension of ttree and justifies the falsity of the terms
; returned. The final ttree must be 'assumption-free and is if the
; initial ttree is also.
; As for motivation, we are about to generalize cl by replacing each
; term in terms by the corresponding var in vars. It is sound, of
; course, to restrict the new variable to have whatever properties the
; corresponding term has. This function is responsible for selecting
; the restrictions we want to place on each variable, based on
; type-set reasoning alone. Thus, if t is known to have properties h1
; & ... & hk, then we can include (not h1), ..., (not hk) in our first
; answer to restrict the variable introduced for t. We will include
; the corresponding var in our second answer to indicate that we have
; a type restriction on that variable.
; We do not want our type restrictions to cause the new clause to
; explode into cases. Therefore, we adopt the following heuristic.
; We convert the type set of each term t into a term (hyp t) known to
; be true of t. We negate (hyp t) and clausify the result. If that
; produces a single clause (segment) then that segment is added to our
; answer. Otherwise, we add no restriction. There are probably
; better ways to do this than to call the full-blown
; convert-type-set-to-term and clausify. But this is simple, elegant,
; and lets us take advantage of improvements to those two utilities.
(cond
((null terms) (mv nil nil nil))
(t
(mv-let
(ts ttree1)
(type-set (car terms) nil nil type-alist ens wrld nil nil nil)
(mv-let
(term ttree1)
(convert-type-set-to-term (car terms) ts ens wrld ttree1)
(let ((clauses (clausify (dumb-negate-lit term) nil t
; Notice that we obtain the sr-limit from the world; see Warning above.
(sr-limit wrld))))
(mv-let
(lits restricted-vars ttree)
(type-restriction-segment cl
(cdr terms)
(cdr vars)
type-alist ens wrld)
(cond ((null clauses)
; If the negation of the type restriction term clausifies to the empty set
; of clauses, then the term is nil. Since we get to assume it, we're done.
; But this can only happen if the type-set of the term is empty. We don't think
; this will happen, but we test for it nonetheless, and toss a nil hypothesis
; into our answer literals if it happens.
(mv (add-to-set-equal *nil* lits)
(cons (car vars) restricted-vars)
(cons-tag-trees ttree1 ttree)))
((and (null (cdr clauses))
(not (null (car clauses))))
; If there is only one clause and it is not the empty clause, we'll
; assume everything in it. (If the clausify above produced '(NIL)
; then the type restriction was just *t* and we ignore it.) It is
; possible that the literals we are about to assume are already in cl.
; If so, we are not fooled into thinking we've restricted the new var.
(cond
((subsetp-equal (car clauses) cl)
(mv lits restricted-vars ttree))
(t (mv (disjoin-clauses (car clauses) lits)
(cons (car vars) restricted-vars)
(cons-tag-trees ttree1 ttree)))))
(t
; There may be useful type information we could extract, but we don't.
; It is always sound to exit here, giving ourselves no additional
; assumptions.
(mv lits restricted-vars ttree))))))))))
(mutual-recursion
(defun subterm-one-way-unify (pat term)
; This function searches pat for a non-variable non-quote subterm s such that
; (one-way-unify s term) returns t and a unify-subst. If it finds one, it
; returns t and the unify-subst. Otherwise, it returns two nils.
(cond ((variablep pat) (mv nil nil))
((fquotep pat) (mv nil nil))
(t (mv-let (ans alist)
(one-way-unify pat term)
(cond (ans (mv ans alist))
(t (subterm-one-way-unify-lst (fargs pat) term)))))))
(defun subterm-one-way-unify-lst (pat-lst term)
(cond
((null pat-lst) (mv nil nil))
(t (mv-let (ans alist)
(subterm-one-way-unify (car pat-lst) term)
(cond (ans (mv ans alist))
(t (subterm-one-way-unify-lst (cdr pat-lst) term)))))))
)
(defrec generalize-rule (nume formula . rune) nil)
(defun apply-generalize-rule (gen-rule term ens)
; Gen-rule is a generalization rule, and hence has a name and a
; formula component. Term is a term which we are intending to
; generalize by replacing it with a new variable. We return two
; results. The first is either t or nil indicating whether gen-rule
; provides a useful restriction on the generalization of term. If the
; first result is nil, so is the second. Otherwise, the second result
; is an instantiation of the formula of gen-rule in which term appears.
; Our heuristic for deciding whether to use gen-rule is: (a) the rule
; must be enabled, (b) term must unify with a non-variable subterm of
; the formula of the rule, (c) the unifying substitution must leave no
; free vars in that formula, and (d) the function symbol of term must
; not occur in the instantiation of the formula except in the
; occurrences of term itself.
(cond
((not (enabled-numep (access generalize-rule gen-rule :nume) ens))
(mv nil nil))
(t (mv-let
(ans unify-subst)
(subterm-one-way-unify (access generalize-rule gen-rule :formula)
term)
(cond
((null ans)
(mv nil nil))
((free-varsp (access generalize-rule gen-rule :formula)
unify-subst)
(mv nil nil))
(t (let ((inst-formula (sublis-var unify-subst
(access generalize-rule
gen-rule
:formula))))
(cond ((ffnnamep (ffn-symb term)
(subst-expr 'x term inst-formula))
(mv nil nil))
(t (mv t inst-formula))))))))))
(defun generalize-rule-segment1 (generalize-rules term ens)
; Given a list of :GENERALIZE rules and a term we return two results:
; the list of instantiated negated formulas of those applicable rules
; and the runes of all applicable rules. The former list is suitable
; for splicing into a clause to add the formulas as hypotheses.
(cond
((null generalize-rules) (mv nil nil))
(t (mv-let (ans formula)
(apply-generalize-rule (car generalize-rules) term ens)
(mv-let (formulas runes)
(generalize-rule-segment1 (cdr generalize-rules)
term ens)
(cond (ans (mv (add-literal (dumb-negate-lit formula)
formulas nil)
(cons (access generalize-rule
(car generalize-rules)
:rune)
runes)))
(t (mv formulas runes))))))))
(defun generalize-rule-segment (terms vars ens wrld)
; Given a list of terms and a list of vars in 1:1 correspondence, we
; return two results. The first is a clause segment containing the
; instantiated negated formulas derived from every applicable
; :GENERALIZE rule for each term in terms. This segment can be spliced
; into a clause to restrict the range of a generalization of terms.
; The second answer is an alist pairing some of the vars in vars to
; the runes of all :GENERALIZE rules in wrld that are applicable to the
; corresponding term in terms. The second answer is of interest only
; to output routines.
(cond
((null terms) (mv nil nil))
(t (mv-let (segment1 runes1)
(generalize-rule-segment1 (global-val 'generalize-rules wrld)
(car terms) ens)
(mv-let (segment2 alist)
(generalize-rule-segment (cdr terms) (cdr vars) ens wrld)
(cond
((null runes1) (mv segment2 alist))
(t (mv (disjoin-clauses segment1 segment2)
(cons (cons (car vars) runes1) alist)))))))))
(defun generalize1 (cl type-alist terms vars ens wrld)
; Cl is a clause. Type-alist is a type-alist obtained by assuming all
; literals of cl false. Terms and vars are lists of terms and
; variables, respectively, in 1:1 correspondence. We assume no var in
; vars occurs in cl. We generalize cl by substituting vars for the
; corresponding terms. We restrict the variables by using type-set
; information about the terms and by using :GENERALIZE rules in wrld.
; We return four results. The first is the new clause. The second
; is a list of the variables for which we added type restrictions.
; The third is an alist pairing some variables with the runes of
; generalization rules used to restrict them. The fourth is a ttree
; justifying our work; it is 'assumption-free.
(mv-let (tr-seg restricted-vars ttree)
(type-restriction-segment cl terms vars type-alist ens wrld)
(mv-let (gr-seg alist)
(generalize-rule-segment terms vars ens wrld)
(mv (sublis-expr-lst (pairlis$ terms vars)
(disjoin-clauses tr-seg
(disjoin-clauses gr-seg
cl)))
restricted-vars
alist
ttree))))
; This completes our brief flirtation with generalization. We now
; have enough machinery to finish coding destructor elimination.
; However, it might be noted that generalize1 is the main subroutine
; of the generalize-clause waterfall processor.
(defun apply-instantiated-elim-rule (rule cl type-alist avoid-vars ens wrld)
; This function takes an instantiated elim-rule, rule, and applies it to a
; clause cl. Avoid-vars is a list of variable names to avoid when we generate
; new ones. See eliminate-destructors-clause for an explanation of that.
; An instantiated :ELIM rule has hyps, lhs, rhs, and destructor-terms, all
; instantiated so that the car of the destructor terms occurs somewhere in the
; clause. To apply such an instantiated :ELIM rule to a clause we assume the
; hyps (adding their negations to cl), we generalize away the destructor terms
; occurring in the clause and in the lhs of the rule, and then we substitute
; that generalized lhs for the rhs into the generalized cl to obtain the final
; clause. The generalization step above may involve adding additional
; hypotheses to the clause and using generalization rules in wrld.
; We return three things. The first is the clause described above, which
; implies cl when the hyps of the rule are known to be true, the second is the
; set of elim variables we have just introduced into it, and the third is a
; list describing this application of the rune of the rule, as explained below.
; The list returned as the third value will become an element in the
; 'elim-sequence list in the ttree of the history entry for this elimination
; process. The "elim-sequence element" we return has the form:
; (rune rhs lhs alist restricted-vars var-to-runes-alist ttree)
; and means "use rune to replace rhs by lhs, generalizing as specified by alist
; (which maps destructors to variables), restricting the restricted-vars
; variables by type (as justified by ttree) and restricting the
; var-to-runes-alist variables by the named generalize rules." The ttree is
; 'assumption-free.
(let* ((rune (access elim-rule rule :rune))
(hyps (access elim-rule rule :hyps))
(lhs (access elim-rule rule :lhs))
(rhs (access elim-rule rule :rhs))
(dests (access elim-rule rule :destructor-terms))
(negated-hyps (dumb-negate-lit-lst hyps)))
(mv-let
(contradictionp type-alist0 ttree0)
(type-alist-clause negated-hyps nil nil type-alist ens wrld
nil nil)
; Before Version_2.9.3, we just punted when contradictionp is true here, and
; this led to infinite loops reported by Sol Swords and then (shortly
; thereafter) Doug Harper, who both sent examples. Our initial fix was to punt
; without going into the infinite loop, but then we implemented the current
; scheme in which we simply perform the elimination without generating clauses
; for the impossible "pathological" cases corresponding to falsity of each of
; the instantiated :elim rule's hypotheses. Both fixes avoid the infinite loop
; in both examples. We kept the present fix because at the time it actually
; proved the latter example (shown here) without induction:
; (include-book "ihs/@logops" :dir :system)
; (thm (implies (integerp (* 1/2 n)) (equal (mod n 2) 0)))
; However, the fix was buggy. When we fixed those bugs after Version_3.6.1,
; the thm above no longer proved; but we still avoided the infinite loop. That
; loop is easily seen in the following example sent by Eric Smith, which proved
; from Versions 2.9.3 through 3.6.1 by exploiting that bug and looped in
; Versions before 2.9.3:
; (defthmd true-listp-of-cdr
; (implies (true-listp (cdr x))
; (true-listp x))
; :hints (("Goal" :in-theory (disable true-listp))))
(let* ((type-alist (if contradictionp type-alist type-alist0))
(cl-with-hyps (disjoin-clauses negated-hyps cl))
(elim-vars (generate-variable-lst dests
(all-vars1-lst cl-with-hyps
avoid-vars)
type-alist ens wrld))
(alist (pairlis$ dests elim-vars))
(generalized-lhs (sublis-expr alist lhs)))
(cond
(contradictionp
; The negation of the clause implies that the type-alist holds, and thus one of
; the negated-hyps holds. Then since contradictionp is true, the conjunction
; of the hyps implies the clause. That is, *true-clause* implies cl when the
; hyps of the rule are known to be true.
(mv *true-clause*
nil ; actual-elim-vars
(list rune rhs
generalized-lhs
alist
nil ; restricted-vars
nil ; var-to-runes-alist
ttree0)))
(t
(let* ((cl-with-hyps (disjoin-clauses negated-hyps cl))
(elim-vars (generate-variable-lst dests
(all-vars1-lst cl-with-hyps
avoid-vars)
type-alist ens wrld)))
(mv-let (generalized-cl-with-hyps
restricted-vars
var-to-runes-alist
ttree)
(generalize1 cl-with-hyps type-alist dests elim-vars ens wrld)
(let* ((final-cl
(subst-var-lst generalized-lhs
rhs
generalized-cl-with-hyps))
(actual-elim-vars
(intersection-eq elim-vars
(all-vars1-lst final-cl nil))))
(mv final-cl
actual-elim-vars
(list rune rhs generalized-lhs alist
restricted-vars
var-to-runes-alist
(cons-tag-trees ttree0 ttree))))))))))))
(defun eliminate-destructors-clause1 (cl eliminables avoid-vars ens wrld
top-flg)
; Cl is a clause we are trying to prove. Eliminables is the set of variables
; on which we will permit a destructor elimination. Avoid-vars is a list of
; variable names we are to avoid when generating new names. In addition, we
; avoid the variables in cl. We look for an eliminable destructor, select the
; highest scoring one and get its instantiated rule, split on the hyps of that
; rule to produce a "pathological" case of cl for each hyp and apply the rule
; to cl to produce the "normal" elim case. Then we iterate until there is
; nothing more to eliminate.
; The handling of the eliminables needs explanation however. At the top-level
; (when top-flg is t) eliminables is the set of all variables occurring in cl
; except those historically introduced by destructor elimination. It is with
; respect to that set that we select our first elimination rule. Thereafter
; (when top-flg is nil) the set of eliminables is always just the set of
; variables we have introduced into the clauses. We permit these variables to
; be eliminated by this elim and this elim only. For example, the top-level
; entry might permit elimination of (CAR X) and of (CAR Y). Suppose we choose
; X, introducing A and B. Then on the second iteration, we'll allow
; eliminations of A and B, but not of Y.
; We return three things. The first is a set of clauses to prove instead of
; cl. The second is the set of variable names introduced by this destructor
; elimination step. The third is an "elim-sequence list" that documents this
; step. If the list is nil, it means we did nothing. Otherwise it is a list,
; in order, of the "elim-sequence elements" described in
; apply-instantiated-elim-rule above. This list should become the
; 'elim-sequence entry in the ttree for this elim process.
; Historical Remark on Nqthm.
; This code is spiritually very similar to that of Nqthm. However, it is much
; more elegant and easy to understand. Nqthm managed the "iteration" with a
; "todo" list which grew and then shrank. In addition, while we select the
; best rule on each round from scratch, Nqthm kept an ordered list of
; candidates (which it culled appropriately when eliminations removed some of
; them from the clause or when the crucial variables were no longer among
; eliminables). Finally, and most obscurely, Nqthm used an inscrutable test on
; the "process history" (related to our elim-sequence) and a subtle invariant
; about the candidates to switch from our top-flg t mode to top-flg nil mode.
; We have spent about a week coding destructor elimination in ACL2 and we have
; thrown away more code that we have kept as we at first transcribed and then
; repeatedly refined the Nqthm code. We are much happier with the current code
; than Nqthm's and believe it will be much easier to modify in the future. Oh,
; one last remark: Nqthm's destructor elimination code had almost no comments
; and everything was done in a single big function with lots of ITERATEs. It
; is no wonder it was so hard to decode.
; Our first step is to get the type-alist of cl. It is used in two different
; ways: to identify contradictory hypotheses of candidate :ELIM lemmas and to
; generate names for new variables.
(mv-let
(contradictionp type-alist ttree)
(type-alist-clause cl nil
; The force-flg must be nil, or else apply-instantiated-elim-rule may call
; generalize1 with a type-alist whose ttrees are not all assumption-free,
; resulting in the return of such a ttree by generalize1 (contrary to its
; specification). The following example was admitted in Version_2.4 and
; Version_4.1, and presumably versions inbetween and perhaps older.
; (progn
; (defun app (x y)
; (if (consp x)
; (cons (car x) (app (cdr x) y))
; y))
; (defun rev (x)
; (if (consp x)
; (app (rev (cdr x)) (cons (car x) nil))
; x))
; (defthm rev-type
; (implies (force (true-listp x))
; (true-listp (rev x)))
; :rule-classes :type-prescription)
; (defthm false
; (equal (rev (rev x)) x)
; :rule-classes nil)
; (defthm true
; (equal (rev (rev '(a b . c)))
; '(a b))
; :rule-classes nil)
; (defthm bug
; nil
; :hints (("Goal" :use (true (:instance false (x '(a b . c))))))
; :rule-classes nil))
nil ; force-flg; see comment above
nil ens wrld
nil nil)
(declare (ignore ttree))
(cond
(contradictionp
; This is unusual. We don't really expect to find a contradiction here. We'll
; return an answer indicating that we didn't do anything. We ignore the
; possibly non-nil ttree here, which is valid given that we are returning the
; same goal clause rather than actually relying on the contradiction. We thus
; ignore ttree everywhere because it is nil when contradictionp is nil.
(mv (list cl) nil nil))
(t
(let ((rule (select-instantiated-elim-rule cl type-alist eliminables
ens wrld)))
(cond ((null rule) (mv (list cl) nil nil))
(t (mv-let (new-clause elim-vars1 ele)
(apply-instantiated-elim-rule rule cl type-alist
avoid-vars ens wrld)
(let ((clauses1 (split-on-assumptions
(access elim-rule rule :hyps)
cl nil)))
; Clauses1 is a set of clauses obtained by splitting on the instantiated hyps
; of the rule. It contains n clauses, each obtained by adding one member of
; inst-hyps to cl. (If any of these new clauses is a tautology, it will be
; deleted, thus there may not be as many clauses as there are inst-hyps.)
; Because these n clauses are all "pathological" wrt the destructor term, e.g.,
; we're assuming (not (consp x)) in a clause involving (car x), we do no
; further elimination down those paths. Note the special case where
; contradictionp is true, meaning that we have ascertained that the
; pathological cases are all impossible.
(cond
((equal new-clause *true-clause*)
(mv clauses1 elim-vars1 (list ele)))
(t
(mv-let (clauses2 elim-vars2 elim-seq)
(eliminate-destructors-clause1
new-clause
(if top-flg
elim-vars1
(union-eq elim-vars1
(remove1-eq
(access elim-rule rule :rhs)
eliminables)))
avoid-vars
ens
wrld
nil)
(mv (conjoin-clause-sets clauses1 clauses2)
(union-eq elim-vars1 elim-vars2)
(cons ele elim-seq))))))))))))))
(defun owned-vars (process mine-flg history)
; This function takes a process name, e.g., 'eliminate-destructors-
; clause, a flag which must be either nil or t, and a clause history.
; If the flag is t, it returns all of the variables introduced into
; the history by the given process. If the flag is nil, it returns
; all of the variables introduced into the history by any other
; process. Note: the variables returned may not even occur in the
; clause whose history we scan.
; For example, if the only two processes that introduce variables are
; destructor elimination and generalization, then when given
; 'eliminate-destructors-clause and mine-flg nil this function will
; return all the variables introduced by 'generalize-clause.
; In order to work properly, a process that introduces variables must
; so record it by adding a tagged object to the ttree of the process.
; The tag should be 'variables and the object should be a list of the
; variables introduced at that step. There should be at most one
; occurrence of that tag in the ttree.
; Why are we interested in this concept? Destructor elimination is
; controlled by a heuristic meant to prevent indefinite elim loops
; involving simplification. For example, suppose you eliminate (CDR
; X0) by introducing (CONS A X1) for X0, and then open a recursive
; function so as to produce (CDR X1). It is easy to cause a loop if
; you then eliminate (CDR X1) by replacing X1 it with (CONS B X2),
; etc. To prevent this, we do not allow destructor elimination to
; work on a variable that was introduced by destructor elimination
; (except within the activation of the elim process that introduces
; that variable).
; That raises the question of telling how a variable was introduced
; into a clause. In ACL2 we adopt the convention described above and
; follow the rule that no process shall introduce a variable into a
; clause that has been introduced by a different process in the
; history of that clause. Thus, if X1 is introduced by elim into the
; history, then X1 cannot also be introduced by generalization, even
; if X1 is new for the clause when generalization occurs. By
; following this rule we know that if a variable is in a clause and
; that variable was introduced into the history of the clause by elim
; then that variable was introduced into the clause by elim. If
; generalize could "re-use" a variable that was already "owned" by
; elim in the history, then we could not accurately determine by
; syntactic means the elim variables in the clause.
; Historical Remark on Nqthm:
; Nqthm solved this problem by allocating a fixed set of variable names
; to elim and a disjoint set to generalize. At the top of the waterfall it
; removed from those two fixed sets the variables that occurred in the
; input clause. Thereafter, if a variable was found to be in the (locally)
; fixed sets, it was known to be introduced by the given process. The
; limitation to a fixed set caused the famous set-diff-n error message
; when the set was exhausted:
; FATAL ERROR: SET-DIFF-N called with inappropriate arguments.
; In the never-released xnqthm -- the "book version" of Nqthm that was
; in preparation when we began work on ACL2 -- we generated a more
; informative error message and increased the size of the fixed sets
; from 18 to over 600. But that meant copying a list of length 600 at
; the top of the waterfall. But the real impetus to the current
; scheme was the irritation over there being a fixed set and the
; attraction of being able to generate mnemonic names from terms. (It
; remains to be seen whether we like the current algorithms. E.g., is
; AENI really a good name for (EXPLODE-NONNEGATIVE-INTEGER N 10 A)?
; In any case, now we are free to experiment with name generation.)
(cond ((null history) nil)
((eq mine-flg
(eq (access history-entry (car history) :processor)
process))
(union-eq (tagged-object 'variables
(access history-entry (car history)
:ttree))
(owned-vars process mine-flg (cdr history))))
(t (owned-vars process mine-flg (cdr history)))))
(defun ens-from-pspv (pspv)
(access rewrite-constant
(access prove-spec-var pspv
:rewrite-constant)
:current-enabled-structure))
(defun eliminate-destructors-clause (clause hist pspv wrld state)
; This is the waterfall processor that eliminates destructors.
; Like all waterfall processors it returns four values: 'hit or 'miss,
; and, if 'hit, a set of clauses, a ttree, and a possibly modified pspv.
(declare (ignore state))
(mv-let
(clauses elim-vars elim-seq)
(eliminate-destructors-clause1 clause
(set-difference-eq
(all-vars1-lst clause nil)
(owned-vars 'eliminate-destructors-clause t
hist))
(owned-vars 'eliminate-destructors-clause nil
hist)
(ens-from-pspv pspv)
wrld
t)
(cond (elim-seq (mv 'hit clauses
(add-to-tag-tree! 'variables elim-vars
(add-to-tag-tree! 'elim-sequence
elim-seq
nil))
pspv))
(t (mv 'miss nil nil nil)))))
; We now develop the code to describe the destructor elimination done,
; starting with printing clauses prettily.
(defun prettyify-clause1 (cl wrld)
(cond ((null (cdr cl)) nil)
(t (cons (untranslate (dumb-negate-lit (car cl)) t wrld)
(prettyify-clause1 (cdr cl) wrld)))))
(defun prettyify-clause2 (cl wrld)
(cond ((null cl) nil)
((null (cdr cl)) (untranslate (car cl) t wrld))
((null (cddr cl)) (list 'implies
(untranslate (dumb-negate-lit (car cl)) t wrld)
(untranslate (cadr cl) t wrld)))
(t (list 'implies
(cons 'and (prettyify-clause1 cl wrld))
(untranslate (car (last cl)) t wrld)))))
; Rockwell Addition: Prettyify-clause now has a new arg to control
; whether we abstract away common subexprs. This will show up many
; times in a compare-windows.
(defun prettyify-clause (cl let*-abstractionp wrld)
; We return an untranslated term that is equivalent to cl. For a simpler
; function that returns a translated term, see prettyify-clause-simple.
(if let*-abstractionp
(mv-let (vars terms)
(maximal-multiples (cons 'list cl) let*-abstractionp)
(cond
((null vars)
(prettyify-clause2 cl wrld))
(t `(let* ,(listlis vars
(untranslate-lst (all-but-last terms)
nil wrld))
,(prettyify-clause2 (cdr (car (last terms))) wrld)))))
(prettyify-clause2 cl wrld)))
(defun prettyify-clause-lst (clauses let*-abstractionp wrld)
(cond ((null clauses) nil)
(t (cons (prettyify-clause (car clauses) let*-abstractionp wrld)
(prettyify-clause-lst (cdr clauses) let*-abstractionp
wrld)))))
(defun prettyify-clause-set (clauses let*-abstractionp wrld)
(cond ((null clauses) t)
((null (cdr clauses))
(prettyify-clause (car clauses) let*-abstractionp wrld))
(t (cons 'and (prettyify-clause-lst clauses let*-abstractionp wrld)))))
(defun tilde-*-elim-phrase/alist1 (alist wrld)
(cond ((null alist) nil)
(t (cons (msg "~p0 by ~x1"
(untranslate (caar alist) nil wrld)
(cdar alist))
(tilde-*-elim-phrase/alist1 (cdr alist) wrld)))))
(defun tilde-*-elim-phrase/alist (alist wrld)
; Alist is never nil, except in the unusual case that
; apply-instantiated-elim-rule detected a tautology where we claim
; none could occur. If that happens we print the phrase "generalizing
; nothing". This is documented simply because it is strange to put
; anything in the 0 case below.
(list* "" " and ~@*" ", ~@*" ", ~@*"
(tilde-*-elim-phrase/alist1 alist wrld)
nil))
(defun tilde-*-elim-phrase3 (var-to-runes-alist)
(cond ((null var-to-runes-alist) nil)
(t (cons (msg "noting the condition imposed on ~x0 by the ~
generalization rule~#1~[~/s~] ~&1"
(caar var-to-runes-alist)
(strip-base-symbols (cdar var-to-runes-alist)))
(tilde-*-elim-phrase3 (cdr var-to-runes-alist))))))
(defun tilde-*-elim-phrase2 (alist restricted-vars var-to-runes-alist ttree wrld)
(list* "" "~@*" "~@* and " "~@*, "
(append
(list (msg "~*0"
(tilde-*-elim-phrase/alist alist wrld)))
(cond
(restricted-vars
(let ((simp-phrase (tilde-*-simp-phrase ttree)))
(cond ((null (cdr restricted-vars))
(list (msg "restrict the type of the new ~
variable ~&0 to be that of the term ~
it replaces~#1~[~/, as established ~
by ~*2~]"
restricted-vars
(if (nth 4 simp-phrase) 1 0)
simp-phrase)))
(t (list (msg "restrict the types of the new ~
variables ~&0 to be those of the ~
terms they replace~#1~[~/, as ~
established by ~*2~]"
restricted-vars
(if (nth 4 simp-phrase) 1 0)
simp-phrase))))))
(t nil))
(tilde-*-elim-phrase3 var-to-runes-alist))
nil))
(defun tilde-*-elim-phrase1 (lst i already-used wrld)
(cond
((null lst) nil)
(t (cons
(cons "(~xi) ~#f~[Use~/Finally, use~] ~#a~[~x0~/~x0, again,~] to ~
replace ~x1 by ~p2~*3. "
(list (cons #\i i)
(cons #\f (if (and (null (cdr lst))
(> i 2))
1
0))
(cons #\a (if (member-equal (nth 0 (car lst)) already-used)
(if (member-equal (nth 0 (car lst))
(cdr (member-equal
(nth 0 (car lst))
already-used)))
0
1)
0))
(cons #\0 (base-symbol (nth 0 (car lst))))
(cons #\1 (nth 1 (car lst)))
(cons #\2 (untranslate (nth 2 (car lst)) nil wrld))
(cons #\3 (tilde-*-elim-phrase2 (nth 3 (car lst))
(nth 4 (car lst))
(nth 5 (car lst))
(nth 6 (car lst))
wrld))))
(tilde-*-elim-phrase1 (cdr lst)
(1+ i)
(cons (nth 0 (car lst))
already-used)
wrld)))))
(defun tilde-*-elim-phrase (lst wrld)
; Lst is the 'elim-sequence list of the ttree of the elim process,
; i.e., it is the third result of eliminate-destructors-clause1 above,
; the third result of apply-instantiated-elim-rule, i.e., a list of
; elements of the form
; (rune rhs lhs alist restricted-vars var-to-runes-alist ttree).
; We generate an object suitable for giving to the tilde-* fmt directive
; that will cause each element of the list to print out a phrase
; describing that step.
(list* ""
"~@*"
"~@*"
"~@*"
(tilde-*-elim-phrase1 lst 1 nil wrld)
nil))
(defun tilde-*-untranslate-lst-phrase (lst flg wrld)
(list* "" "~p*" "~p* and " "~p*, "
(untranslate-lst lst flg wrld)
nil))
(defun eliminate-destructors-clause-msg1 (signal clauses ttree pspv state)
; The arguments to this function are the standard ones for an output
; function in the waterfall. See the discussion of the waterfall.
(declare (ignore signal pspv))
(let ((lst (tagged-object 'elim-sequence ttree))
(n (length clauses))
(wrld (w state)))
(cond
((null (cdr lst))
(fms "The destructor term~#p~[~/s~] ~*0 can be eliminated by using ~x1 ~
to replace ~p2 by ~p3~*4. ~#5~[All the clauses produced are ~
tautological.~/This produces the following goal.~/This produces ~
the following ~n6 goals.~]~|"
(list (cons #\p (nth 3 (car lst)))
(cons #\0 (tilde-*-untranslate-lst-phrase
(strip-cars (nth 3 (car lst))) nil wrld))
(cons #\1 (base-symbol (nth 0 (car lst))))
(cons #\2 (nth 1 (car lst)))
(cons #\3 (untranslate (nth 2 (car lst)) nil wrld))
(cons #\4 (tilde-*-elim-phrase2 (nth 3 (car lst))
(nth 4 (car lst))
(nth 5 (car lst))
(nth 6 (car lst))
wrld))
(cons #\5 (zero-one-or-more n))
(cons #\6 n))
(proofs-co state)
state
(term-evisc-tuple nil state)))
(t
(fms "The destructor term~#p~[~/s~] ~*0 can be eliminated. ~
Furthermore, ~#p~[that term is~/those terms are~] at the root of ~
a chain of ~n1 rounds of destructor elimination. ~*2These steps ~
produce ~#3~[no nontautological goals~/the following goal~/the ~
following ~n4 goals~].~|"
(list (cons #\p (nth 3 (car lst)))
(cons #\0 (tilde-*-untranslate-lst-phrase
(strip-cars (nth 3 (car lst)))
nil wrld))
(cons #\1 (length lst))
(cons #\2 (tilde-*-elim-phrase lst wrld))
(cons #\3 (zero-one-or-more n))
(cons #\4 n))
(proofs-co state)
state
(term-evisc-tuple nil state))))))
; We now develop the cross-fertilization process.
(mutual-recursion
(defun almost-quotep1 (term)
(cond ((variablep term) t)
((fquotep term) t)
((flambda-applicationp term)
(and (almost-quotep1 (lambda-body term))
(almost-quotep1-listp (fargs term))))
((eq (ffn-symb term) 'cons)
(and (almost-quotep1 (fargn term 1))
(almost-quotep1 (fargn term 2))))
(t nil)))
(defun almost-quotep1-listp (terms)
(cond ((null terms) t)
(t (and (almost-quotep1 (car terms))
(almost-quotep1-listp (cdr terms))))))
)
(defun almost-quotep (term)
; A term is "almost a quotep" if it is a non-variablep term that
; consists only of variables, explicit values, and applications of
; cons. Lambda-applications are permitted provided they have
; almost-quotep bodies and args.
; Further work: See equal-x-cons-x-yp.
(and (nvariablep term)
(almost-quotep1 term)))
(defun destructor-applied-to-varsp (term ens wrld)
; We determine whether term is of the form (destr v1 ... vn)
; where destr has an enabled 'eliminate-destructors-rule
; and all the vi are variables.
(cond ((variablep term) nil)
((fquotep term) nil)
((flambda-applicationp term) nil)
(t (and (all-variablep (fargs term))
(let ((rule (getpropc (ffn-symb term)
'eliminate-destructors-rule
nil
wrld)))
(and rule
(enabled-numep (access elim-rule rule :nume)
ens)))))))
(defun dumb-occur-lst-except (term lst lit)
; Like dumb-occur-lst except that it does not look into the first
; element of lst that is equal to lit. If you think of lst as a
; clause and lit as a literal, we ask whether term occurs in some
; literal of clause other than lit. In Nqthm we looked for an eq
; occurrence of lit, which we can't do here. But if there are two
; occurrences of lit in lst, then normally in Nqthm they would not
; be eq and hence we'd look in one of them. Thus, here we look in
; all the literals of lst after we've seen lit. This is probably
; unnecessarily complicated.
(cond ((null lst) nil)
((equal lit (car lst))
(dumb-occur-lst term (cdr lst)))
(t (or (dumb-occur term (car lst))
(dumb-occur-lst-except term (cdr lst) lit)))))
(defun fertilize-feasible (lit cl hist term ens wrld)
; Lit is a literal of the form (not (equiv term val)) (or the commuted
; form). We determine if it is feasible to substitute val for term in
; clause cl. By that we mean that term is neither a near constant nor
; a destructor, term does occur elsewhere in the clause, every
; occurrence of term is equiv-hittable, and we haven't already
; fertilized with this literal.
(and (not (almost-quotep term))
(not (destructor-applied-to-varsp term ens wrld))
(dumb-occur-lst-except term cl lit)
(every-occurrence-equiv-hittablep-in-clausep (ffn-symb (fargn lit 1))
term cl ens wrld)
(not (already-used-by-fertilize-clausep lit hist t))))
(mutual-recursion
(defun fertilize-complexity (term wrld)
; The fertilize-complexity of (fn a1 ... an) is the level number of fn
; plus the maximum fertilize complexity of ai.
(cond ((variablep term) 0)
((fquotep term) 0)
(t (+ (get-level-no (ffn-symb term) wrld)
(maximize-fertilize-complexity (fargs term) wrld)))))
(defun maximize-fertilize-complexity (terms wrld)
(cond ((null terms) 0)
(t (max (fertilize-complexity (car terms) wrld)
(maximize-fertilize-complexity (cdr terms) wrld)))))
)
(defun first-fertilize-lit (lst cl hist ens wrld)
; We find the first literal lst of the form (not (equiv lhs1 rhs1))
; such that a fertilization of one side for the other into cl is
; feasible. We return six values. The first is either nil, meaning
; no such lit was found, or a direction of 'left-for-right or
; 'right-for-left. The second is the literal found. The last three are
; the equiv, lhs, and rhs of the literal, and the length of the tail of
; cl after lit.
(cond
((null lst) (mv nil nil nil nil nil nil))
(t (let ((lit (car lst)))
(case-match
lit
(('not (equiv lhs rhs))
(cond
((equivalence-relationp equiv wrld)
(cond
((fertilize-feasible lit cl hist lhs ens wrld)
(cond
((fertilize-feasible lit cl hist rhs ens wrld)
(cond ((< (fertilize-complexity lhs wrld)
(fertilize-complexity rhs wrld))
(mv 'left-for-right lit equiv lhs rhs (len (cdr lst))))
(t (mv 'right-for-left lit equiv lhs rhs
(len (cdr lst))))))
(t (mv 'right-for-left lit equiv lhs rhs (len (cdr lst))))))
((fertilize-feasible lit cl hist rhs ens wrld)
(mv 'left-for-right lit equiv lhs rhs (len (cdr lst))))
(t (first-fertilize-lit (cdr lst) cl hist ens wrld))))
(t (first-fertilize-lit (cdr lst) cl hist ens wrld))))
(& (first-fertilize-lit (cdr lst) cl hist ens wrld)))))))
(defun cross-fertilizep/c (equiv cl direction lhs1 rhs1)
; See condition (c) of cross-fertilizep.
(cond ((null cl) nil)
((and (nvariablep (car cl))
(not (fquotep (car cl)))
(equal (ffn-symb (car cl)) equiv)
(if (eq direction 'left-for-right)
(dumb-occur rhs1 (fargn (car cl) 2))
(dumb-occur lhs1 (fargn (car cl) 1))))
t)
(t (cross-fertilizep/c equiv (cdr cl) direction lhs1 rhs1))))
(defun cross-fertilizep/d (equiv cl direction lhs1 rhs1)
; See condition (d) of cross-fertilizep.
(cond ((null cl) nil)
((and (nvariablep (car cl))
(not (fquotep (car cl)))
(equal (ffn-symb (car cl)) equiv)
(if (eq direction 'left-for-right)
(dumb-occur rhs1 (fargn (car cl) 1))
(dumb-occur lhs1 (fargn (car cl) 2))))
t)
(t (cross-fertilizep/d equiv (cdr cl) direction lhs1 rhs1))))
(defun cross-fertilizep (equiv cl pspv direction lhs1 rhs1)
; We have found a literal, (not (equiv lhs1 rhs1)), of cl such that a
; fertilization is feasible in the indicated direction. We want to
; know whether this will be a cross-fertilization or not. Suppose,
; without loss of generality, that the direction is 'left-for-right,
; i.e., we are going to substitute lhs1 for rhs1. A cross-
; fertilization is performed only if (a) neither lhs1 nor rhs1 is an
; explicit value, (b) we are under an induction (thus our interest in
; pspv), (c) there is some equiv literal, (equiv lhs2 rhs2), in the
; clause such that rhs1 occurs in rhs2 (thus we'll hit rhs2) and (d)
; there is some equiv literal such that rhs1 occurs in lhs2 (thus,
; cross fertilization will actually prevent us from hitting something
; massive substitution would hit). Note that since we know the
; fertilization is feasible, every occurrence of the target is in an
; equiv-hittable slot. Thus, we can use equivalence-insensitive occur
; checks rather than being prissy.
(and (not (quotep lhs1))
(not (quotep rhs1))
(assoc-eq 'being-proved-by-induction
(access prove-spec-var pspv :pool))
; David Hardin sent an example in March 2015, for which Codewalker generates a
; goal that fails to prove under induction but is proved at the top level. The
; reason turned out to be that cross-fertilization is used under induction but
; not at the top level. Since the point of cross-fertilization is to prepare
; for generalization, and since generalization often fails, we arrange just
; below to avoid cross-fertilization if generalization is turned off (instead,
; fully fertilizing with the equivalence). This makes it easy for applications
; (such as Codewalker) to avoid the limited substitution formed by
; cross-fertilization.
(not (member-eq 'generalize-clause
(cdr (assoc-eq :do-not
(access prove-spec-var pspv
:hint-settings)))))
(cross-fertilizep/c equiv cl direction lhs1 rhs1)
(cross-fertilizep/d equiv cl direction lhs1 rhs1)))
(defun delete-from-ttree (tag val ttree)
(let ((objects (tagged-objects tag ttree)))
(cond (objects (cond
((member-equal val objects)
(let ((new-objects (remove1-equal val objects))
(new-ttree (remove-tag-from-tag-tree! tag ttree)))
(cond (new-objects
(extend-tag-tree tag new-objects new-ttree))
(t new-ttree))))
(t ttree)))
(t ttree))))
(defun fertilize-clause1 (cl lit1 equiv lhs1 rhs1
direction
cross-fert-flg
delete-lit-flg
ens
wrld
state
ttree)
; Cl is a clause we are fertilizing with lit1, which is one of its
; literals and which is of the form (not (equiv lhs1 rhs1)). Direction is
; 'left-for-right or 'right-for-left, indicating which way we're to
; substitute. Cross-fert-flg is t if we are to hit only (equiv lhs2
; rhs2) and do it in a cross-fertilize sort of way (left for right
; into right or right for left into left); otherwise we substitute for
; all occurrences. Delete-lit-flg is t if we are to delete the first
; occurrence of lit when we see it. We return two things: the new
; clause and a ttree indicating the congruences used.
(cond
((null cl) (mv nil ttree))
(t
(let* ((lit2 (car cl))
(lit2-is-lit1p (equal lit2 lit1)))
; First, we substitute into lit2 as appropriate. We obtain new-lit2
; and a ttree. We ignore the hitp result always returned by
; subst-equiv-expr.
; What do we mean by "as appropriate"? We consider three cases on
; lit2, the literal into which we are substituting: lit2 is (equiv lhs
; rhs), lit2 is (not (equiv lhs rhs)), or otherwise. We also consider
; whether we are cross fertilizing or just substituting for all
; occurrences. Here is a table that explains our actions below.
; lit2 (equiv lhs rhs) (not (equiv lhs rhs)) other
; xfert xfert subst no action
; subst subst subst subst
; The only surprising part of this table is that in the case of
; cross-fertilizing into (not (equiv lhs rhs)), i.e., into another
; equiv hypothesis, we do a full-fledged substitution rather than a
; cross-fertilization. I do not give an example of why we do this.
; However, it is exactly what Nqthm does (in the only comparable case,
; namely, when equiv is EQUAL).
(mv-let
(hitp new-lit2 ttree)
(cond
(lit2-is-lit1p (mv nil lit2 ttree))
((or (not cross-fert-flg)
(case-match lit2
(('not (equiv-sym & &)) (equal equiv-sym equiv))
(& nil)))
(cond ((eq direction 'left-for-right)
(subst-equiv-expr equiv lhs1 rhs1
*geneqv-iff*
lit2 ens wrld state ttree))
(t (subst-equiv-expr equiv rhs1 lhs1
*geneqv-iff*
lit2 ens wrld state ttree))))
(t
; Caution: There was once a bug below. We are cross fertilizing.
; Suppose we see (equiv lhs2 rhs2) and want to substitute lhs1 for
; rhs1 in rhs2. What geneqv do we maintain? The bug, which was
; completely nonsensical, was that we maintained *geneqv-iff*, just as
; above. But in fact we must maintain whatever geneqv maintains
; *geneqv-iff* in the second arg of equiv. Geneqv-lst returns a list
; of geneqvs, one for each argument position of equiv. We select the
; one in the argument position corresponding to the side we are
; changing. Actually, the two geneqvs for an equivalence relation
; ought to be the identical, but it would be confusing to exploit
; that.
; In the days when this bug was present there was another problem! We
; only substituted into (equal lhs2 rhs2)! (That is, the case-match
; below was on ('equal lhs2 rhs2) rather than (equiv-sym lhs2 rhs2).)
; So here is an example of a screwy substitution we might have done:
; Suppose (equiv a b) is a hypothesis and (equal (f a) (f b)) is a
; conclusion and that we are to do a cross-fertilization of a for b.
; We ought not to substitute into equal except maintaining equality.
; But we actually would substitute into (f b) maintaining iff! Now
; suppose we knew that (equiv x y) -> (iff (f x) (f y)). Then we
; could derive (equal (f a) (f a)), which would be t and unsound. The
; preconditions for this screwy situation are exhibited by:
; (defun squash (x)
; (cond ((null x) nil)
; ((integerp x) 1)
; (t t)))
;
; (defun equiv (x y)
; (equal (squash x) (squash y)))
;
; (defequiv equiv)
;
; (defun f (x) x)
;
; (defcong equiv iff (f x) 1)
;
; In particular, (implies (equiv a b) (equal (f a) (f b))) is not a
; theorem (a=1 and b=2 are counterexamples), but this function, if
; called with that input clause, ((not (equiv a b)) (equal (f a) (f
; b))), and the obvious lit1, etc., would return (equal (f a) (f a)),
; which is T. (Here we are substituting left for right, a for b.) So
; there was a soundness bug in the old version of this function.
; But it turns out that this bug could never be exploited. The bug
; can be provoked only if we are doing cross-fertilization. And
; cross-fertilization is only done if the fertilization is "feasible".
; That means that every occurrence of b in the clause is equiv
; hittable, as per every-occurrence-equiv-hittablep-in-clausep. In
; our example, the b in (f b) is not equiv hittable. Indeed, if every
; occurrence of b is equiv hittable then no matter what braindamaged
; geneqv we use below, the result will be sound! A braindamaged
; geneqv might prevent us from hitting some, but any hit it allowed is
; ok.
; This bug was first noticed by Bill McCune (September, 1998), who
; reported an example in which the system io indicated that a was
; substituted for b but in fact no substitution occurred. No
; substitution occurred because we didn't have the congruence theorem
; shown above -- not a surprising lack considering the random nature
; of the problem. At first I was worried about soundness but then saw
; the argument above.
(case-match
lit2
((equiv-sym lhs2 rhs2)
(cond ((not (equal equiv-sym equiv)) (mv nil lit2 ttree))
((eq direction 'left-for-right)
(mv-let (hitp new-rhs2 ttree)
(subst-equiv-expr equiv lhs1 rhs1
(cadr (geneqv-lst equiv
*geneqv-iff*
ens wrld))
rhs2 ens wrld state ttree)
(declare (ignore hitp))
(mv nil
(mcons-term* equiv lhs2 new-rhs2)
ttree)))
(t
(mv-let (hitp new-lhs2 ttree)
(subst-equiv-expr equiv rhs1 lhs1
(car (geneqv-lst equiv
*geneqv-iff*
ens wrld))
lhs2 ens wrld state ttree)
(declare (ignore hitp))
(mv nil
(mcons-term* equiv new-lhs2 rhs2)
ttree)))))
(& (mv nil lit2 ttree)))))
(declare (ignore hitp))
; Second, we recursively fertilize appropriately into the rest of the clause.
(mv-let (new-tail ttree)
(fertilize-clause1 (cdr cl) lit1 equiv lhs1 rhs1
direction
cross-fert-flg
(if lit2-is-lit1p
nil
delete-lit-flg)
ens wrld state ttree)
; Finally, we combine the two, deleting the lit if required.
(cond
(lit2-is-lit1p
(cond (delete-lit-flg
(mv new-tail
(cond ((eq direction 'left-for-right)
(add-binding-to-tag-tree
rhs1 lhs1 ttree))
(t
(add-binding-to-tag-tree
lhs1 rhs1 ttree)))))
(t (mv-let (not-flg atm)
(strip-not lit2)
(prog2$
(or not-flg
(er hard 'fertilize-clause1
"We had thought that we only ~
fertilize with negated literals, ~
unlike ~x0!"
new-lit2))
(prog2$
(or (equal lit2 new-lit2) ; should be eq
(er hard 'fertilize-clause1
"Internal error in ~
fertilize-clause1!~|Old lit2: ~
~x0.~|New lit2: ~x1"
lit2 new-lit2))
(mv (cons (mcons-term* 'not
(mcons-term* 'hide
atm))
new-tail)
ttree)))))))
(t (mv (cons new-lit2 new-tail) ttree)))))))))
(defun fertilize-clause (cl-id cl hist pspv wrld state)
; A standard clause processor of the waterfall.
; We return 4 values. The first is a signal that is either 'hit, or
; 'miss. When the signal is 'miss, the other 3 values are irrelevant.
; When the signal is 'hit, the second result is the list of new
; clauses, the third is a ttree that will become that component of the
; history-entry for this fertilization, and the fourth is an
; unmodified pspv. (We return the fourth thing to adhere to the
; convention used by all clause processors in the waterfall (q.v.).)
; The ttree we return has seven tagged objects in it plus a bunch
; of 'lemmas indicating the :CONGRUENCE rules used.
; 'literal - the literal from cl we used, guaranteed to be of
; the form (not (equiv lhs rhs)).
; 'clause-id - the current clause-id
; 'hyp-phrase - a tilde-@ phrase that describes literal in cl.
; 'equiv - the equivalence relation
; 'bullet - the term we substituted
; 'target - the term we substituted for
; 'cross-fert-flg - whether we did a cross fertilization
; 'delete-lit-flg - whether we deleted literal from the
; clause.
(mv-let (direction lit equiv lhs rhs len-tail)
(first-fertilize-lit cl cl hist
(ens-from-pspv pspv)
wrld)
(cond
((null direction) (mv 'miss nil nil nil))
(t (let ((cross-fert-flg
(cross-fertilizep equiv cl pspv direction lhs rhs))
(delete-lit-flg
(and
(not (quotep lhs))
(not (quotep rhs))
(assoc-eq 'being-proved-by-induction
(access prove-spec-var
pspv
:pool)))))
(mv-let (new-cl ttree)
(fertilize-clause1 cl lit equiv lhs rhs
direction
cross-fert-flg
delete-lit-flg
(ens-from-pspv pspv)
wrld
state
nil)
(mv 'hit
(list new-cl)
(add-to-tag-tree!
'literal lit
(add-to-tag-tree!
'hyp-phrase (tilde-@-hyp-phrase len-tail cl)
(add-to-tag-tree!
'cross-fert-flg cross-fert-flg
(add-to-tag-tree!
'equiv equiv
(add-to-tag-tree!
'bullet (if (eq direction 'left-for-right)
lhs
rhs)
(add-to-tag-tree!
'target (if (eq direction 'left-for-right)
rhs
lhs)
(add-to-tag-tree!
'clause-id cl-id
(add-to-tag-tree!
'delete-lit-flg delete-lit-flg
(if delete-lit-flg
ttree
(push-lemma (fn-rune-nume 'hide nil nil
wrld)
ttree))))))))))
pspv)))))))
(defun fertilize-clause-msg1 (signal clauses ttree pspv state)
; The arguments to this function are the standard ones for an output
; function in the waterfall. See the discussion of the waterfall.
(declare (ignore signal pspv clauses))
(let* ((hyp-phrase (tagged-object 'hyp-phrase ttree))
(wrld (w state))
(ttree
; We can get away with eliminating the :definition of hide from the ttree
; because fertilize-clause1 only pushes lemmas by way of subst-equiv-expr,
; which are either about geneqvs (from geneqv-refinementp) or are executable
; counterparts (from scons-term). If we do not delete the definition of hide
; from ttree here, we get a bogus "validity of this substitution relies upon
; the :definition HIDE" message.
(delete-from-ttree 'lemma (fn-rune-nume 'hide nil nil wrld) ttree)))
(fms "We now use ~@0 by ~#1~[substituting~/cross-fertilizing~] ~p2 for ~p3 ~
and ~#4~[hiding~/throwing away~] the ~@5.~#6~[~/ The validity of ~
this substitution relies upon ~*7.~] This produces~|"
(list
(cons #\0 hyp-phrase)
(cons #\1 (if (tagged-object 'cross-fert-flg ttree)
1
0))
(cons #\2 (untranslate (tagged-object 'bullet ttree) nil wrld))
(cons #\3 (untranslate (tagged-object 'target ttree) nil wrld))
(cons #\4 (if (tagged-object 'delete-lit-flg ttree)
1
0))
(cons #\5 (if (and (consp hyp-phrase)
(null (cdr hyp-phrase)))
"conclusion"
"hypothesis"))
(cons #\6 (if (tagged-objectsp 'lemma ttree)
1
0))
(cons #\7 (tilde-*-simp-phrase ttree)))
(proofs-co state)
state
(term-evisc-tuple nil state))))
; And now we do generalization...
(defun collectable-fnp (fn ens wrld)
; A common collectable term is a non-quoted term that is an
; application of a collectable-fnp. Most functions are common
; collectable. The ones that are not are cons, open lambdas, and the
; (enabled) destructors of wrld.
(cond ((flambdap fn) nil)
((eq fn 'cons) nil)
(t (let ((rule (getpropc fn 'eliminate-destructors-rule nil wrld)))
(cond ((and rule
(enabled-numep (access elim-rule rule :nume) ens))
nil)
(t t))))))
(mutual-recursion
(defun smallest-common-subterms1 (term1 term2 ens wrld ans)
; This is the workhorse of smallest-common-subterms, but the arguments are
; arranged so that we know that term1 is the smaller. We add to ans
; every subterm x of term1 that (a) occurs in term2, (b) is
; collectable, and (c) has no collectable subterms in common with
; term2.
; We return two values. The first is the modified ans. The second is
; t or nil according to whether term1 occurs in term2 but neither it
; nor any of its subterms is collectable. This latter condition is
; said to be the ``potential'' of term1 participating in a collection
; vicariously. What does that mean? Suppose a1, ..., an, all have
; potential. Then none of them are collected (because they aren't
; collectable) but each occurs in term2. Thus, a term such as (fn a1
; ... an) might actually be collected because it may occur in term2
; (all of its args do, at least), it may be collectable, and none of
; its subterms are. So those ai have the potential to participate
; vicariously in a collection.
(cond ((or (variablep term1)
(fquotep term1))
; Since term1 is not collectable, we don't add it to ans. But we return
; t as our second value if term1 occurs in term2, i.e., term1 has
; potential.
(mv ans (occur term1 term2)))
(t (mv-let
(ans all-potentials)
(smallest-common-subterms1-lst (fargs term1) term2 ens wrld ans)
(cond ((null all-potentials)
; Ok, some arg did not have potential. Either it did not occur or it
; was collected. In either case, term1 should not be collected and
; furthermore, has no potential for participating later.
(mv ans nil))
((not (occur term1 term2))
; Every arg of term1 had potential but term1 doesn't occur in
; term2. That means we don't collect it and it hasn't got
; potential.
(mv ans nil))
((collectable-fnp (ffn-symb term1) ens wrld)
; So term1 occurs, none of its subterms were collected, and term1
; is collectable. So we collect it, but it no longer has potential
; (because it got collected).
(mv (add-to-set-equal term1 ans)
nil))
(t
; Term1 occurs, none of its subterms were collected, and term1
; was not collected. So it has potential to participate vicariously.
(mv ans t)))))))
(defun smallest-common-subterms1-lst (terms term2 ens wrld ans)
; We accumulate onto ans every subterm of every element of terms
; that (a) occurs in term2, (b) is collectable, and (c) has no
; collectable subterms in common with term2. We return the modified
; ans and the flag indicating whether all of the terms have potential.
(cond
((null terms) (mv ans t))
(t (mv-let
(ans car-potential)
(smallest-common-subterms1 (car terms) term2 ens wrld ans)
(mv-let
(ans cdr-potential)
(smallest-common-subterms1-lst (cdr terms) term2 ens wrld ans)
(mv ans
(and car-potential
cdr-potential)))))))
)
(defun dumb-fn-count-1 (flg x acc)
(declare (xargs :guard (and (if flg
(pseudo-term-listp x)
(pseudo-termp x))
(natp acc))))
(cond (flg (cond ((null x)
acc)
(t
(dumb-fn-count-1 t (cdr x)
(dumb-fn-count-1 nil (car x) acc)))))
((or (variablep x) (fquotep x))
acc)
(t (dumb-fn-count-1 t (fargs x) (1+ acc)))))
(defun dumb-fn-count (x)
; Originally we had this upside-down call tree, where cons-count was a function
; that counts the number of conses in an object.
; cons-count
; smallest-common-subterms
; generalizable-terms-across-relations
; generalizable-terms
; generalizable-terms-across-literals1
; generalizable-terms-across-literals
; generalizable-terms
; generalize-clause
; But the role of evgs disappears if we use dumb-occur instead of occur in our
; algorithm for finding common subterms, which seems anyhow like the right
; thing to do if the point is to generalize common subterms to variables.
; Evg-occur is called by occur but not by dumb-occur, and evg-occur is
; potentially expensive on galactic objects. So we no longer use cons-count to
; compute the smallest-common-subterms; we use fn-count-dumb.
(dumb-fn-count-1 nil x 0))
(defun smallest-common-subterms (term1 term2 ens wrld ans)
; We accumulate onto ans and return the list of every subterm x of
; term1 that is also a subterm of term2, provided x is ``collectable''
; and no subterm of x is collectable. A term is a collectable if it
; is an application of a collectable-fnp and is not an explicit value.
; Our aim is to collect the ``innermost'' or ``smallest'' collectable
; subterms.
(mv-let (ans potential)
(cond ((> (dumb-fn-count term1) (dumb-fn-count term2))
(smallest-common-subterms1 term2 term1 ens wrld ans))
(t (smallest-common-subterms1 term1 term2 ens wrld ans)))
(declare (ignore potential))
ans))
(defun generalizing-relationp (term wrld)
; Term occurs as a literal of a clause. We want to know whether
; we should generalize common subterms occurring in its arguments.
; Right now the answer is geared to the special case that term is
; a binary relation -- or at least that only two of the arguments
; encourage generalizations. We return three results. The first
; is t or nil indicating whether the other two are important.
; The other two are the two terms we should explore for common
; subterms.
; For example, for (equal lhs rhs), (not (equal lhs rhs)), (< lhs
; rhs), and (not (< lhs rhs)), we return t, lhs, and rhs. We also
; generalize across any known equivalence relation, but this code has
; built into the assumption that all such relations have arity at
; least 2 and just returns the first two args. For (member x y), we
; return three nils.
(mv-let (neg-flg atm)
(strip-not term)
(declare (ignore neg-flg))
(cond ((or (variablep atm)
(fquotep atm)
(flambda-applicationp atm))
(mv nil nil nil))
((or (eq (ffn-symb atm) 'equal)
(eq (ffn-symb atm) '<)
(equivalence-relationp (ffn-symb atm) wrld))
(mv t (fargn atm 1) (fargn atm 2)))
(t (mv nil nil nil)))))
(defun generalizable-terms-across-relations (cl ens wrld ans)
; We scan clause cl for each literal that is a generalizing-relationp,
; e.g., (equal lhs rhs), and collect into ans all the smallest common
; subterms that occur in each lhs and rhs. We return the final ans.
(cond ((null cl) ans)
(t (mv-let (genp lhs rhs)
(generalizing-relationp (car cl) wrld)
(generalizable-terms-across-relations
(cdr cl) ens wrld
(if genp
(smallest-common-subterms lhs rhs ens wrld ans)
ans))))))
(defun generalizable-terms-across-literals1 (lit1 cl ens wrld ans)
(cond ((null cl) ans)
(t (generalizable-terms-across-literals1
lit1 (cdr cl) ens wrld
(smallest-common-subterms lit1 (car cl) ens wrld ans)))))
(defun generalizable-terms-across-literals (cl ens wrld ans)
; We consider each pair of literals, lit1 and lit2, in cl and
; collect into ans the smallest common subterms that occur in
; both lit1 and lit2. We return the final ans.
(cond ((null cl) ans)
(t (generalizable-terms-across-literals
(cdr cl) ens wrld
(generalizable-terms-across-literals1 (car cl) (cdr cl)
ens wrld ans)))))
(defun generalizable-terms (cl ens wrld)
; We return the list of all the subterms of cl that we will generalize.
; We look for common subterms across equalities and inequalities, and
; for common subterms between the literals of cl.
(generalizable-terms-across-literals
cl ens wrld
(generalizable-terms-across-relations
cl ens wrld nil)))
(defun generalize-clause (cl hist pspv wrld state)
; A standard clause processor of the waterfall.
; We return 4 values. The first is a signal that is either 'hit, or 'miss.
; When the signal is 'miss, the other 3 values are irrelevant. When the signal
; is 'hit, the second result is the list of new clauses, the third is a ttree
; that will become that component of the history-entry for this generalization,
; and the fourth is an unmodified pspv. (We return the fourth thing to adhere
; to the convention used by all clause processors in the waterfall (q.v.).)
; The ttree we return is 'assumption-free.
(declare (ignore state))
(cond
((not (assoc-eq 'being-proved-by-induction
(access prove-spec-var pspv :pool)))
(mv 'miss nil nil nil))
(t (let* ((ens (ens-from-pspv pspv))
(terms (generalizable-terms cl ens wrld)))
(cond
((null terms)
(mv 'miss nil nil nil))
(t
(mv-let
(contradictionp type-alist ttree)
(type-alist-clause cl nil
; The force-flg probably needs to be nil, to avoid an inappropriate call of
; generalize1. See the comment about a similar call of type-alist-clause in
; eliminate-destructors-clause1.
nil ; force-flg
nil ens wrld
nil nil)
(declare (ignore ttree))
(cond
(contradictionp
; We compute the type-alist of the clause to allow us to generate nice variable
; names and to restrict the coming generalization. A contradiction will not
; arise if this clause survived simplification (which it has, unless :do-not
; hints specified that simplification was not to be used). However, we will
; return an accurate answer just to be rugged. We'll report that we couldn't
; do anything! That's really funny. We just proved our goal and we're saying
; we can't do anything. But if we made this fn sometimes return the empty set
; of clauses we'd want to fix the io handler for it and we'd have to respect
; the 'assumptions in the ttree and we don't. Do we? As usual, we ignore the
; ttree in this case, and hence we ignore it totally since it is known to be
; nil when contradictionp is nil.
(mv 'miss nil nil nil))
(t
(let ((gen-vars
(generate-variable-lst terms
(all-vars1-lst cl
(owned-vars
'generalize-clause
nil
hist))
type-alist ens wrld)))
(mv-let (generalized-cl restricted-vars var-to-runes-alist ttree)
(generalize1 cl type-alist terms gen-vars ens wrld)
(mv 'hit
(list generalized-cl)
(add-to-tag-tree!
'variables gen-vars
(add-to-tag-tree!
'terms terms
(add-to-tag-tree!
'restricted-vars restricted-vars
(add-to-tag-tree!
'var-to-runes-alist var-to-runes-alist
(add-to-tag-tree!
'ts-ttree ttree
nil)))))
pspv))))))))))))
(defun tilde-*-gen-phrase/alist1 (alist wrld)
(cond ((null alist) nil)
(t (cons (msg "~p0 by ~x1"
(untranslate (caar alist) nil wrld)
(cdar alist))
(tilde-*-gen-phrase/alist1 (cdr alist) wrld)))))
(defun tilde-*-gen-phrase/alist (alist wrld)
; Alist is never nil
(list* "" "~@*" "~@* and " "~@*, "
(tilde-*-gen-phrase/alist1 alist wrld)
nil))
(defun tilde-*-gen-phrase (alist restricted-vars var-to-runes-alist ttree wrld)
(list* "" "~@*" "~@* and " "~@*, "
(append
(list (msg "~*0"
(tilde-*-gen-phrase/alist alist wrld)))
(cond
(restricted-vars
(let* ((runes (tagged-objects 'lemma ttree))
(primitive-type-reasoningp
(member-equal *fake-rune-for-type-set* runes))
(symbols
(strip-base-symbols
(remove1-equal *fake-rune-for-type-set* runes))))
(cond ((member-eq nil symbols)
(er hard 'tilde-*-gen-phrase
"A fake rune other than ~
*fake-rune-for-type-set* was found in the ~
ts-ttree generated by generalize-clause. ~
The list of runes in the ttree is ~x0."
runes))
((null (cdr restricted-vars))
(list (msg "restricting the type of the new ~
variable ~&0 to be that of the term ~
it replaces~#1~[~/, as established ~
by primitive type reasoning~/, as ~
established by ~&2~/, as established ~
by primitive type reasoning and ~&2~]"
restricted-vars
(cond ((and symbols
primitive-type-reasoningp)
3)
(symbols 2)
(primitive-type-reasoningp 1)
(t 0))
symbols)))
(t (list (msg "restricting the types of the new ~
variables ~&0 to be those of the ~
terms they replace~#1~[~/, as ~
established by primitive type ~
reasoning~/, as established by ~
~&2~/, as established by primitive ~
type reasoning and ~&2~]"
restricted-vars
(cond ((and symbols
primitive-type-reasoningp)
3)
(symbols 2)
(primitive-type-reasoningp 1)
(t 0))
symbols))))))
(t nil))
(tilde-*-elim-phrase3 var-to-runes-alist))
nil))
(defun generalize-clause-msg1 (signal clauses ttree pspv state)
; The arguments to this function are the standard ones for an output
; function in the waterfall. See the discussion of the waterfall.
(declare (ignore signal pspv clauses))
(fms "We generalize this conjecture, replacing ~*0. This produces~|"
(list
(cons #\0
(tilde-*-gen-phrase
(pairlis$ (tagged-object 'terms ttree)
(tagged-object 'variables ttree))
(tagged-object 'restricted-vars ttree)
(tagged-object 'var-to-runes-alist ttree)
(tagged-object 'ts-ttree ttree)
(w state))))
(proofs-co state)
state
(term-evisc-tuple nil state)))
; The elimination of irrelevance is defined in the same file as induct
; because elim uses m&m.
|