dmode.red 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. module dmode; % Functions for defining and using poly domain modes.
  2. % Author: Anthony C. Hearn.
  3. % Modifications by: Stanley L. Kameny.
  4. % Copyright (c) 1992 RAND. All rights reserved.
  5. Comment
  6. *** Description of Definition Requirements for Domain arithmetics ***
  7. Syntactically, such elements have the following form:
  8. <domain element>:=NIL|integer|<structured domain element>
  9. <structured domain element> ::=
  10. (<domain identifier>.<domain structure>),
  11. where NIL represents the domain element zero.
  12. To introduce a new domain, we need to define:
  13. 1) A conversion function from integer to the given mode, stored under
  14. the attribute I2D.
  15. 2) A conversion function from new mode to or from every other mode.
  16. 3) Particular instances of the binary operations +,- and * for this
  17. mode.
  18. 4) Particular instances of ZEROP, ONEP and MINUSP for this mode.
  19. Although ONEP could be defined in terms of ZEROP, we believe it is
  20. more efficient to have both functions (though this has not been
  21. thoroughly tested).
  22. 5) If domain is a field, a quotient must be defined. If domain is a
  23. ring, a gcd and divide must be defined, and also a quotient
  24. function which returns NIL if the division fails.
  25. 6) A printing function for this mode that can print the object in a
  26. linear form. The printing function is associated with the attribute
  27. PRIFN. This printing function should enclose the printed expression
  28. in parentheses if its top level operator has a precedence greater
  29. than +.
  30. 7) A function to convert structure to an appropriate prefix form.
  31. 8) A reading function for this mode.
  32. 9) A DNAME property for the tag, and a TAG property for the DNAME
  33. 10) Optionally, an exponentiation function. If this is not provided,
  34. repeated squaring is used (cf !:expt in dmodeop.red)
  35. To facilitate this, all such modes should be listed in the global
  36. variable DOMAINLIST!*.
  37. The following rules should also be followed when introducing new
  38. domains:
  39. Some modes, such as modular arithmetic, require that integers be
  40. converted to domain elements when input or addition or multiplication
  41. of such objects occurs. Such modes should be flagged "convert".
  42. A domain which holds mutable internal state should be flagged
  43. "resimplify" (no Reduce domains are currently so flagged) which means
  44. that attempts to simplify domain elements will actually do so, rather
  45. than just thinking "domain elements are always simplified".
  46. In ALL cases it is assumed that any domain element that tests true to
  47. the zero test can be converted into an explicit 0 (represented by NIL),
  48. and any that tests true to the onep test can be converted into an
  49. explicit 1. If the domain allows for the conversion of other elements
  50. into equivalent integers, a function under the optional attribute
  51. INTEQUIVFN may also be defined to effect this conversion.
  52. The result of an arithmetic (as opposed to a boolean) operation on
  53. structured domain elements with the same tag must be another structured
  54. domain element with the same tag. In particular, a domain zero must be
  55. returned as a tagged zero in that domain.
  56. In some cases, it is possible to map functions on domain elements to
  57. domain elements. To provide for this capability in the complete
  58. system, one can give such functions the domain tag as an indicator.
  59. The results of this evaluation must be a tagged domain element (or an
  60. integer?), but not necessarily an element from the same domain, or the
  61. evaluation should abort with an error. The error number associated
  62. with this should be in the range 100-150;
  63. fluid '(!*complex dmode!* gdmode!*);
  64. global '(domainlist!*);
  65. symbolic procedure initdmode u;
  66. % Checks that U is a valid domain mode, and sets up appropriate
  67. % interfaces to the system.
  68. begin
  69. dmodechk u;
  70. put(u,'simpfg,list(list(t,list('setdmode,mkquote u,t)),
  71. list(nil,list('setdmode,mkquote u,nil))))
  72. end;
  73. % switch complex!-rational,complex!-rounded;
  74. symbolic procedure setdmode(u,bool);
  75. % Sets polynomial domain mode. If bool is NIL, integers are used,
  76. % or in the case of complex, set to the lower domain.
  77. % Otherwise mode is set to u, or derived from it.
  78. begin scalar x;
  79. if (x := get(u,'dname)) then u := x; % Allow a tag as argument.
  80. if u eq 'complex!-rational then
  81. <<if (x := dmode!*) then x := get(x,'dname);
  82. onoff('complex,bool); onoff('rational,bool);
  83. return x>>
  84. else if u eq 'complex!-rounded then
  85. <<if (x := dmode!*) then x := get(x,'dname);
  86. onoff('complex,bool); onoff('rounded,bool);
  87. return x>>;
  88. if null get(u,'tag)
  89. then rerror(poly,5,
  90. list("Domain mode error:",u,"is not a domain mode"));
  91. if x := get(u,'package!-name) then load!-package x;
  92. return if u eq 'complex or !*complex then setcmpxmode(u,bool)
  93. else setdmode1(u,bool)
  94. end;
  95. symbolic procedure setdmode1(u,bool);
  96. begin scalar x,y,z;
  97. x := get(u,'tag);
  98. y := dmode!*;
  99. if null bool
  100. then return if null y then nil
  101. else if u eq (y := get(y,'dname))
  102. then <<rmsubs(); gdmode!* := dmode!* := nil; y>>
  103. else offmoderr(u,y)
  104. else <<if u memq '(rounded complex!-rounded) then !!mfefix();
  105. if x eq y then return x>>;
  106. % Now make sure there are no other domain switches left on.
  107. if not (z := get(x,'realtype)) then z := x;
  108. for each j in domainlist!* do
  109. if j neq '!:gi!: and not(j eq z)
  110. then set(intern compress
  111. append(explode '!*,explode get(j,'dname)),
  112. nil);
  113. rmsubs();
  114. y := get(y,'dname);
  115. if y then lprim list("Domain mode",y,"changed to",u);
  116. gdmode!* := dmode!* := x;
  117. return y
  118. end;
  119. symbolic procedure offmoderr(u,y);
  120. lpriw("***",list("Failed attempt to turn off",u,"when",y,"is on"));
  121. symbolic procedure dmodechk u;
  122. % Checks to see if U has complete specification for a domain mode.
  123. begin scalar z;
  124. if not(z := get(u,'tag))
  125. then rerror(poly,6,list("Domain mode error:","No tag for",u))
  126. else if not(get(z,'dname) eq u)
  127. then rerror(poly,7,list("Domain mode error:",
  128. "Inconsistent or missing DNAME for",z))
  129. else if not(z memq domainlist!*)
  130. then rerror(poly,8,list("Domain mode error:",
  131. z,"not on domain list"));
  132. u := z;
  133. for each x in domainlist!*
  134. do if u=x then nil
  135. else <<if not get(u,x) then put(u,x,mkdmoderr(u,x));
  136. if not get(x,u) then put(x,u,mkdmoderr(x,u))>>;
  137. % then rederr list("Domain mode error:",
  138. % "No conversion defined between",U,"and",X);
  139. z := '(plus difference times quotient i2d prepfn prifn
  140. minusp onep zerop);
  141. if not flagp(u,'field) then z := 'divide . 'gcd . z;
  142. for each x in z do if not get(u,x)
  143. then rerror(poly,9,list("Domain mode error:",
  144. x,"is not defined for",u))
  145. end;
  146. symbolic procedure dmoderr(u,v);
  147. rerror(poly,10,list("Conversion between",get(u,'dname),
  148. "and",get(v,'dname),"not defined"));
  149. symbolic procedure mkdmoderr(u,v);
  150. list('lambda,'(!*x!*),list('dmoderr,mkquote u,mkquote v));
  151. endmodule;
  152. end;