:- module(ordset).
:- export ord_union / 4.
:- export ord_union / 3.
:- export ord_union / 2.
:- export ord_symdiff / 3.
:- export ord_superset / 2.
:- export ord_subtract / 3.
:- export ord_subset / 2.
:- export ord_seteq / 2.
:- export ord_selectchk / 3.
:- export ord_proper_superset / 2.
:- export ord_proper_subset / 2.
:- export ord_nonmember / 2.
:- export ord_memberchk / 2.
:- export ord_intersection / 5.
:- export ord_intersection / 3.
:- export ord_intersection / 2.
:- export ord_intersect / 3.
:- export ord_intersect / 2.
:- export ord_insert / 3.
:- export ord_disjoint_union / 3.
:- export ord_disjoint / 2.
:- export ord_del_element / 3.
:- export ord_compare / 3.
:- export ord_add_element / 3.
:- export list_to_ord_set / 2.
:- export is_ordset / 1.
:- comment(summary, "Ordered set manipulation utilities").
:- comment(author, "R.A.O'Keefe and Joachim Schimpf").
:- comment(copyright, 'This file is in the public domain').
:- comment(date, "$Date: 2006/09/23 01:55:30 $").
:- comment(desc, html("<P>\tIn this module, sets are represented by ordered lists with no\n\tduplicates.  Thus the set {c,r,a,f,t} would be [a,c,f,r,t].  The\n\tordering is defined by the @< family of term comparison predicates,\n\twhich is the ordering used by sort/2 and setof/3.\n\t</P><P>\n\tThe benefit of the ordered representation is that the elementary\n\tset operations can be done in time proportional to the Sum of\n\tthe argument sizes rather than their Product.  Some of the\n\tunordered set routines, such as member/2, length/2, select/3\n\tcan be used unchanged.\n\t</P><P>\n\tThe implementation allows nonground set elements. The only problem\n\twith this is that a set can lose its set property as a result of\n\tvariable bindings: unifications can create duplicates or change\n\tthe element's position in the term order. The set can be repaired\n\tby applying list_to_ord_set/2 again, i.e. re-sorting it.\n\t</P><P>\n\tNote that the predicates of this library do no error checking.\n\tWhen called with the wrong argument types or modes, the result is\n\tundefined.\n\t</P>\n    ")).
:- comment(is_ordset / 1, [amode : (is_ordset(?) is semidet), args : ["Term" : "Any Term"], summary : "Checks whether term is an ordered set in the sense of lib(ordset)", see_also : [(@<) / 2], desc : html("\tChecks whether term is an ordered set in the sense of lib(ordset),\n\ti.e. a proper, duplicate-free list with elements in increasing order.\n    ")]).
:- comment(list_to_ord_set / 2, [amode : (list_to_ord_set(+, -) is det), args : ["List" : "A list of terms", "Set" : "A set or variable"], summary : "Converts a list to a set", see_also : [sort / 2], desc : html("\tSucceeds when Set is the ordered representation of the set\n\trepresented by the unordered representation List.  The only\n\treason for giving it a name at all is that you may not have\n\trealised that sort/2 could be used this way.")]).
:- comment(ord_add_element / 3, [amode : (ord_add_element(+, +, -) is det), args : ["Set1" : "A set", "Element" : "A term", "Set2" : "A set or variable"], summary : "Adds an element to a set", see_also : [ord_insert / 3], desc : html("\tSet2 is the set resulting from adding Element to Set1. It should\n\tgive exactly the same result as merge(Set1, [Element], Set2).\n\tThis is a synonym of ord_insert/3.\n    ")]).
:- comment(ord_compare / 3, [amode : (ord_compare(-, +, +) is semidet), args : ["Rel" : "A variable or an atom", "Set1" : "A set", "Set2" : "A set"], summary : "Rel is the ordering relationship between Set1 and Set2", see_also : [(@<) / 2, ord_seteq / 2, ord_proper_subset / 2, ord_proper_superset / 2], fail_if : "Fails if the sets are not comparable", desc : html("\tRel is the ordering relationship between Set1 and Set2.\n\tRel is one of the atoms =, &gt; or &lt;\n\t<PRE>\n\t=    The sets are identical (in the sense of ==/2)\n\t&gt;    Set1 is a proper superset of Set2\n\t&lt;    Set1 is a proper subset of Set2\n\t</PRE>\n\tOtherwise the predicate fails.")]).
:- comment(ord_del_element / 3, [amode : (ord_del_element(+, ?, -) is det), args : ["Set" : "A set", "Term" : "Any Term", "Remainder" : "A variable or set"], summary : "Remainder is the set Set without the element Term", see_also : [ord_selectchk / 3], desc : html("\tRemainder is the set Set without the element Term. If Term is not\n\tin Set, Remainder is identical to Set.")]).
:- comment(ord_disjoint / 2, [amode : (ord_disjoint(+, +) is semidet), args : ["Set1" : "A set", "Set2" : "A set"], summary : "Checks whether two sets are disjoint", see_also : [ord_intersect / 2], desc : html("\tSucceeds when the two ordered sets have no element in common.\n    ")]).
:- comment(ord_disjoint_union / 3, [amode : (ord_disjoint_union(+, +, -) is semidet), args : ["Set1" : "A set", "Set2" : "A set", "Union" : "A set or variable"], summary : "Computes the union of Set1 and Set2 when they are disjoint", see_also : [ord_union / 4, ord_union / 2], fail_if : "Fails if the sets are not disjoint", desc : html("\tSucceeds when Union is the union of disjoint sets Set1 and Set2.\n\tFails if Set1 and Set2 are not disjoint, i.e. if they have a\n\tnon-empty intersection.\n    ")]).
:- comment(ord_insert / 3, [amode : (ord_insert(+, +, -) is det), args : ["Set1" : "A set", "Element" : "A term", "Set2" : "A set or variable"], summary : "Adds an element to a set", see_also : [ord_add_element / 3], desc : html("\tSet2 is the set resulting from adding Element to Set1. It should\n\tgive exactly the same result as merge(Set1, [Element], Set2).\n\tThis is a synonym of ord_add_element/3.\n    ")]).
:- comment(ord_intersect / 2, [amode : (ord_intersect(+, +) is semidet), args : ["Set1" : "A set", "Set2" : "A set"], summary : "Checks whether two sets have a non-empty intersection", see_also : [ord_disjoint / 2], desc : html("\tSucceeds when the two ordered sets have at least one element\n\tin common.  Note that the test is == rather than = .\n    ")]).
:- comment(ord_intersect / 3, [amode : (ord_intersect(+, +, -) is det), args : ["Set1" : "A set", "Set2" : "A set", "Intersection" : "A set"], summary : "Computes the intersection of two sets", see_also : [ord_intersection / 3], desc : html("<P>\tSucceeds when Intersection is the intersection of Set1 \n\tand Set2, provided that Set1 and Set2 are ordered sets.\n\t</P><P>\n\tThe use of ord_intersection/3 is preferred.\n\t</P>\n    ")]).
:- comment(ord_intersection / 2, [amode : (ord_intersection(+, -) is det), args : ["Sets" : "A list of sets", "Intersection" : "A set or variable"], summary : "Computes the intersection of all sets in Sets", see_also : [ord_intersection / 3, ord_union / 2], desc : html("\tSucceeds when Intersection is the intersection of all sets in\n\tthe list Sets.\n    ")]).
:- comment(ord_intersection / 3, [amode : (ord_intersection(+, +, -) is det), args : ["Set1" : "A set", "Set2" : "A set", "Intersection" : "A set"], summary : "Computes the intersection of two sets", see_also : [ord_intersect / 2, ord_intersection / 5], desc : html("\tSucceeds when Intersection is the intersection of Set1 \n\tand Set2, provided that Set1 and Set2 are ordered sets.\n    ")]).
:- comment(ord_intersection / 5, [amode : (ord_intersection(+, +, -, -, -) is det), args : ["Set1" : "A set", "Set2" : "A set", "Intersection" : "A variable or set", "Only1" : "A variable or set", "Only2" : "A variable or set"], summary : "Computes the intersection and the differences of two sets", see_also : [ord_intersection / 3, ord_subtract / 3, ord_symdiff / 3], desc : html("\tSucceeds when Intersection is the intersection of the ordered\n\tsets Set1 and Set2, Only1 is the set of elements that are only\n\tin Set1, and Only2 is the set of elements that are only in Set2.\n    ")]).
:- comment(ord_memberchk / 2, [amode : (ord_memberchk(?, +) is semidet), args : ["Term" : "Any Term", "Set" : "A set"], summary : "Checks whether Term is a member of Set", see_also : [member / 2, ord_nonmember / 2, ord_selectchk / 3], fail_if : "Term is not a member of Set"]).
:- comment(ord_nonmember / 2, [amode : (ord_nonmember(?, +) is semidet), args : ["Term" : "Any Term", "Set" : "A set"], summary : "Term is not a member of Set", see_also : [ord_memberchk / 2], fail_if : "Term is a member of Set"]).
:- comment(ord_proper_subset / 2, [amode : (ord_proper_subset(+, +) is semidet), args : ["Set1" : "A set", "Set2" : "A set"], summary : "Checks whether Set1 is a proper subset of Set2", see_also : [ord_subset / 2, ord_compare / 3], desc : html("\tSucceeds when every element of the ordered set Set1 appears\n\tin the ordered set Set2, and Set2 has at least on element that\n\tdoes not occur in Set1.\n    ")]).
:- comment(ord_proper_superset / 2, [amode : (ord_proper_superset(+, +) is semidet), args : ["Set1" : "A set", "Set2" : "A set"], summary : "Checks whether Set1 is a proper superset of Set2", see_also : [ord_superset / 2, ord_compare / 3], desc : html("\tSucceeds when every element of the ordered set Set2 appears\n\tin the ordered set Set1, and Set1 has at least on element that\n\tdoes not occur in Set2.\n    ")]).
:- comment(ord_selectchk / 3, [amode : (ord_selectchk(?, +, -) is semidet), args : ["Term" : "Any Term", "Set" : "A set", "Remainder" : "A variable or set"], summary : "Set contains Term, and Remainder is the set Set without Term", fail_if : "Term is not a member of Set", see_also : [ord_del_element / 3, delete / 3], desc : html("\tIf Set contains Term, Remainder is the set Set without the Term.\n\tOtherwise the predicate fails.")]).
:- comment(ord_seteq / 2, [amode : (ord_seteq(+, +) is semidet), args : ["Set1" : "A set", "Set2" : "A set"], summary : "Compares two sets for identity", see_also : [(==) / 2, ord_compare / 3], desc : html("\tSucceeds when the two arguments represent the same set.  Since they\n\tare assumed to be ordered representations, they must be identical.\n    ")]).
:- comment(ord_subset / 2, [amode : (ord_subset(+, +) is semidet), args : ["Set1" : "A set", "Set2" : "A set"], summary : "Checks whether Set1 is a subset of Set2", see_also : [ord_proper_subset / 2, subset / 2, ord_compare / 3], desc : html("\tSucceeds when every element of the ordered set Set1 appears\n\tin the ordered set Set2.\n    ")]).
:- comment(ord_subtract / 3, [amode : (ord_subtract(+, +, -) is det), args : ["Set1" : "A set", "Set2" : "A set", "Difference" : "A set or variable"], summary : "Subtracts Set2 from Set1", see_also : [ord_symdiff / 3], desc : html("\tSucceeds when Difference contains all and only the elements\n\tof Set1 which are not also in Set2.\n    ")]).
:- comment(ord_superset / 2, [amode : (ord_superset(+, +) is semidet), args : ["Set1" : "A set", "Set2" : "A set"], summary : "Checks whether Set1 is a superset of Set2", see_also : [ord_proper_superset / 2, subset / 2, ord_compare / 3], desc : html("\tSucceeds when every element of the ordered set Set2 appears\n\tin the ordered set Set1.\n    ")]).
:- comment(ord_symdiff / 3, [amode : (ord_symdiff(+, +, -) is det), args : ["Set1" : "A set", "Set2" : "A set", "Difference" : "A set or variable"], summary : "Computes the symmetric difference of Set1 and Set2", see_also : [ord_subtract / 3], desc : html("\tSucceeds when Difference is the symmetric difference of Set1 and Set2.\n\tThese are the elements that occur either only in Set1 or only in Set2,\n\tbut not both.\n    ")]).
:- comment(ord_union / 2, [amode : (ord_union(+, -) is det), args : ["Sets" : "A list of sets", "Union" : "A set or variable"], summary : "Computes the union of all sets in Sets", see_also : [ord_union / 3, ord_intersection / 2], desc : html("\tSucceeds when Union is the union of all sets in the list Sets.\n    ")]).
:- comment(ord_union / 3, [amode : (ord_union(+, +, -) is det), args : ["Set1" : "A set", "Set2" : "A set", "Union" : "A set or variable"], summary : "Computes the union of Set1 and Set2", see_also : [ord_disjoint_union / 3, ord_union / 4, ord_union / 2], desc : html("\tSucceeds when Union is the union of Set1 and Set2.  Note that when\n\tsomething occurs in both sets, we want to retain only one copy.\n    ")]).
:- comment(ord_union / 4, [amode : (ord_union(+, +, -, -) is det), args : ["Set1" : "A set", "Set2" : "A set", "Union" : "A set or variable", "New" : "A set or variable"], summary : "Computes the union and difference of Set2 and Set1", see_also : [ord_disjoint_union / 3, ord_union / 3, ord_union / 2], desc : html("\tSucceeds when Union is the union of Set1 and Set2, and New is the\n\tset of elements that are in Set2 but not in Set1.  This is useful\n\tin order to know which elements were newly added when incrementally\n\tmerging sets.\n    ")]).
