sets.red 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. module sets; % Operators for basic set theory.
  2. %% Author: F.J.Wright@Maths.QMW.ac.uk.
  3. %% Date: 20 Feb 1994.
  4. %% WARNING: This module patches mk!*sq.
  5. %% To do:
  6. %% Improve symbolic set-Boolean analysis.
  7. %% Rationalize the coding?
  8. %% A nice illustration of fancy maths printing in the graphics mode
  9. %% of PSL-REDUCE under MS-Windows and X, but it works properly only with
  10. %% interface versions compiled from sources dated after 14 Feb 1994.
  11. %% Defines the set-valued infix operators (with synonyms):
  12. %% union, intersection (intersect), setdiff (minus, \),
  13. %% and the Boolean-valued infix operators:
  14. %% member, subset_eq, subset, set_eq.
  15. %% Arguments may be algebraic-mode lists representing explicit sets,
  16. %% or identifiers representing symbolic sets, or set-valued expressions.
  17. %% Lists are converted to sets by deleting any duplicate elements, and
  18. %% sets are sorted into a canonical ordering before being returned.
  19. %% This can also be done explicitly by applying the unary operator
  20. %% mkset. The set-valued operators may remain symbolic, but
  21. %% REDUCE does not currently support this concept for Boolean-valued
  22. %% operators, and so neither does this package (although it could).
  23. %% Set-theoretic simplifications are performed, but probably not fully.
  24. %% A naive power set procedure is included as an algebraic example
  25. %% in the test file (sets.tst).
  26. %% A proposed new coding style:
  27. deflist('((local scalar)), 'newnam);
  28. %% (DEFLIST used because flagged eval -- PUT does not work during
  29. %% faslout!)
  30. %% One good reason not to use `\' in place of `!' ?
  31. newtok '((!\) setdiff);
  32. %% NOTE that this works in graphics mode under Windows or X PSL-REDUCE
  33. %% ONLY with versions compiled from sources dated after 14 Feb 1994.
  34. %% The following statement should really be in fmprint.red:
  35. put('setdiff, 'fancy!-infix!-symbol, "\backslash");
  36. %% A set is sorted before it is returned for purely cosmetic reasons,
  37. %% except that together with duplicate elimination this makes the repre-
  38. %% sentation canonical and so list equality can be used as set equality.
  39. create!-package('(sets),'(contrib misc));
  40. symbolic smacro procedure sort!-set l;
  41. sort(l, function set!-ordp);
  42. symbolic procedure set!-ordp(u, v);
  43. %% Ordp alone (as used by ordn to implement symmetry) looks strange.
  44. %% This seems like a reasonable compromise.
  45. if numberp u and numberp v then u < v else ordp(u, v);
  46. %% Set-valued operators:
  47. %% ====================
  48. infix union, intersection, setdiff;
  49. put('intersect, 'newnam, 'intersection);
  50. put('minus, 'newnam, 'setdiff); % cf. Maple!
  51. precedence setdiff, -;
  52. precedence union, setdiff;
  53. precedence intersection, union;
  54. %% Must be simpfns for let rules to be applicable.
  55. put('union, 'simpfn, 'simpunion);
  56. put('intersection, 'simpfn, 'simpintersection);
  57. put('setdiff, 'simpfn, 'simpsetdiff);
  58. flag('(union intersection), 'nary); % associativity
  59. put('union, 'unary, 'union); % for completeness
  60. put('intersection, 'unary, 'intersection);
  61. listargp union, intersection; % necessary for unary case
  62. %% Symmetry is normally implemented by simpiden, which is not
  63. %% used here and the symmetry is implemented explicitly,
  64. %% but the symmetric flag is also used when applying let rules.
  65. flag('(union intersection), 'symmetric); % commutativity
  66. %% Intersection distributes over union, which is implemented
  67. %% as a rule list at the end of this file.
  68. global '(empty_set); symbolic(empty_set := '(list));
  69. %% Below ordn sorts for symmetry as in simpiden for symmetric operators
  70. symbolic procedure simpunion args;
  71. %% x union {} = x, union x = x
  72. !*kk2q(if car r eq 'union
  73. then if cdr(r := delete(empty_set, cdr r))
  74. then 'union . ordn r else car r
  75. else r)
  76. where r = applysetop('union, args);
  77. symbolic procedure simpintersection args;
  78. %% x intersect {} = {}, intersection x = x
  79. !*kk2q(if car r eq 'intersection
  80. then if empty_set member(r := cdr r) then empty_set
  81. else if cdr r then 'intersection . ordn r else car r
  82. else r)
  83. where r = applysetop('intersection, args);
  84. symbolic procedure simpsetdiff args;
  85. %% x setdiff x = {} setdiff x = {}, x setdiff {} = x.
  86. !*kk2q(if car r eq 'setdiff
  87. then if cadr r = caddr r or cadr r = empty_set then empty_set
  88. else if caddr r = empty_set then cadr r else r
  89. else r)
  90. where r = applysetop('setdiff, args);
  91. %% The following mechanism allows unevaluated operators to remain
  92. %% symbolic and supports n-ary union and intersection.
  93. %% Allow set-valued expressions as sets:
  94. flag('(union, intersection, setdiff), 'setvalued);
  95. symbolic procedure applysetop(setop, args);
  96. %% Apply binary Lisp-level set functions to pairs of explicit
  97. %% set args and collect symbolic args:
  98. begin local set_arg, sym_args, setdiff_args;
  99. set_arg := 0; % cannot use nil as initial value
  100. setdiff_args := for each u in args collect
  101. %% reval form makes handling kernels and sorting easier:
  102. if eqcar(u := reval u, 'list) then
  103. << u := delete!-dups cdr u;
  104. set_arg := if set_arg = 0 then u
  105. else apply2(setop, set_arg, u);
  106. make!-set u >>
  107. else if idp u or (pairp u and flagp(car u, 'setvalued)) then
  108. %% Implement idempotency for union and intersection:
  109. << if not(u member sym_args)
  110. then sym_args := u . sym_args; u >>
  111. %% else typerr(if eqcar(u,'!*sq) then prepsq cadr u
  112. %% else u,"set");
  113. else typerr(u, "set"); % u was reval'ed
  114. return if sym_args then
  115. setop . if setop eq 'setdiff then setdiff_args else
  116. if set_arg = 0 then sym_args
  117. else make!-set set_arg . sym_args
  118. else aeval make!-set set_arg % aeval NEEDED for consistency
  119. end;
  120. symbolic operator mkset;
  121. symbolic procedure mkset rlist;
  122. %% Make a set from an algebraic-mode list:
  123. make!-set delete!-dups getrlist rlist;
  124. %% The function list2set is already defined in PSL
  125. %% to remove duplicates and PARTIALLY sort,
  126. %% but it is not defined in the REDUCE sources.
  127. symbolic procedure make!-set l;
  128. makelist sort!-set l;
  129. symbolic procedure delete!-dups l;
  130. if l then
  131. if car l member cdr l then delete!-dups(cdr l)
  132. else car l . delete!-dups(cdr l);
  133. %% Boolean-valued operators:
  134. %% ========================
  135. infix subset_eq, subset, set_eq; % member already declared
  136. precedence subset_eq, <;
  137. precedence subset, subset_eq;
  138. precedence set_eq, =;
  139. put('member, 'boolfn, 'evalmember);
  140. put('subset_eq, 'boolfn, 'evalsubset_eq);
  141. put('subset, 'boolfn, 'evalsubset);
  142. put('set_eq, 'boolfn, 'evalset_eq);
  143. %% Boolfns get their arguments aeval'd automatically.
  144. symbolic procedure evalmember(el, rlist);
  145. %% Special case -- only applicable to explicit lists.
  146. member(el, getrlist rlist);
  147. symbolic procedure evalsubset_eq(u, v);
  148. (if atom r then r else apply(function equal, r) or evalsymsubset r)
  149. where r = evalsetbool('subset_eq, u, v);
  150. put('subset_eq, 'setboolfn, function subsetp);
  151. symbolic procedure evalsubset(u, v);
  152. (if atom r then r else evalsymsubset r)
  153. where r = evalsetbool('subset, u, v);
  154. put('subset, 'setboolfn, function subsetneqp);
  155. symbolic procedure subsetneqp(u, v);
  156. subsetp(u,v) and not subsetp(v,u);
  157. symbolic procedure evalsymsubset args;
  158. %% This analysis assumes symbolic sets are non-empty, otherwise
  159. %% the relation may be equality rather than strict inclusion.
  160. %% Could or should this analysis be extended?
  161. ((eqcar(v, 'union) and u member cdr v) or
  162. (eqcar(u, 'intersection) and v member cdr u) or
  163. (eqcar(u, 'setdiff) and
  164. (cadr u = v or (eqcar(v, 'union) and cadr u member cdr v))))
  165. where u = car args, v = cadr args;
  166. %% Set equality can use list equality provided the representation
  167. %% is canonical (duplicate-free and ordered). The following set
  168. %% equality predicate is independent of set implementation,
  169. %% and implements precisely the formal mathematical definition.
  170. symbolic procedure evalset_eq(u, v);
  171. (if atom r then r else apply(function equal, r))
  172. where r = evalsetbool('set_eq, u, v);
  173. put('set_eq, 'setboolfn, function setequal);
  174. symbolic procedure setequal(u, v);
  175. subsetp(u,v) and subsetp(v,u);
  176. symbolic procedure evalsetbool(setbool, u, v);
  177. begin local r, set_args, sym_args;
  178. r := for each el in {u, v} collect
  179. if eqcar(el, 'list) then
  180. << set_args := t; cdr el >>
  181. %% reval form makes handling kernels easier:
  182. else if idp(el := reval el) or
  183. (pairp el and flagp(car el, 'setvalued)) then
  184. << sym_args := t; el >>
  185. else typerr(el, "set"); % el was reval'ed
  186. return if set_args then
  187. if sym_args then % RedErr
  188. msgpri("Cannot evaluate", {setbool, reval u, reval v},
  189. "as Boolean-valued set expression", nil, t)
  190. else apply(get(setbool,'setboolfn), r)
  191. else r
  192. end;
  193. %% Boolean evaluation operator:
  194. %% ===========================
  195. %% Nothing to do with sets, but useful for testing Boolean operators:
  196. symbolic operator evalb; % cf. Maple
  197. symbolic procedure evalb condition;
  198. if eval formbool(condition, nil, 'algebraic) then 'true else 'false;
  199. flag('(evalb), 'noval); % because evalb evals its argument itself
  200. %% Note that this does not work - it generates the wrong code:
  201. %% algebraic procedure evalb condition;
  202. %% if condition then true else false;
  203. %% Set simplification rules:
  204. %% ========================
  205. algebraic;
  206. set_distribution_rule := {~x intersection (~y union ~z) =>
  207. (x intersection y) union (x intersection z)};
  208. endmodule;
  209. end;