dave@lsuc.UUCP (David Sherman) (05/20/86)
First, thanks to everyone who responded to my plea for help in avoiding circularity in my definition of tptype. Most people suggested using two different predicates, one for stated facts and one for conclusions. It turns out not to be quite so simple, but I think that suggestion contains the seeds of the solution I need. I'm still working on finalizing it. Second, I've developed an interesting predicate which I call "aggregate" which I'd like to share with the net. It comes from the tendency of the Income Tax Act to say things like "the aggregate of his taxable capital gains for the year". I wanted to be able to take an arbitrary predicate which puts a number into its last argument, call it as many times as will succeed, and total up the numbers. Thus, if I have taxablecapitalgain(Taxpayer, Year, TCG) which itself is defined in terms of more basic things (like transactions, dispositions, proceeds, cost and so on), then I can say aggregate(taxablecapitalgain, fred, 1986, Aggr). and get fred's 1986 taxable capital gains returned in Aggr. Here's my code. I have no idea whether it will be useful to anyone, but I'm curious as to what those more experienced with Prolog think of it. It's probably either ingenious or stupid, but it does work. It uses the "findall" predicate from Clocksin & Mellish chapter 7. aggregate(Goal, Arg1, Arg2, Aggr) :- Z =.. [Goal, Arg1, Arg2, Amount], findall(Amount, call(Z), List), listtotal(List, Aggr). (3 other copies of "aggregate" exist, one with only Arg1, one with Arg1, Arg2, Arg3, and one with 4 arguments for the Goal other than the final Amount.) listtotal([], 0). listtotal([H|T], Total) :- integer(H), listtotal(T, Ttotal), Total is H + Ttotal. Third, I'm currently wrestling with the task of generating, for a list, every list which is a subset of that list. Thus, for [a,b,c,d], I want findall to be able to find each of [a,b] [a,c] [a,d] [a,b,c] [a,b,d] [a,c,d] [b,c] [b,d] [b,c,d] [c,d]. I've played with it for a while and can't get a handle on the approach to take. Can anyone help? (The application is generating every possible group of taxpayers from the list of those who own shares in a corporation, so as to determine whether any of them is a "related group" as defined in the Act.) Incidentally, if anyone is interested in knowing more about my project, I'll be happy to mail or post more. It's a comprehensive corporate tax planning system based on the Canadian Income Tax Act. Dave Sherman The Law Society of Upper Canada Osgoode Hall Toronto, Canada M5H 2N6 +1 416 947 3466 -- { ihnp4!utzoo pesnta utcs hcr decvax!utcsri } !lsuc!dave
bertrand@cui.UUCP (IBRAHIM Bertrand) (05/31/86)
> From: dave@lsuc.UUCP > Subject: miscellany re income tax planning system > ... > Third, I'm currently wrestling with the task of generating, > for a list, every list which is a subset of that list. Thus, > for [a,b,c,d], I want findall to be able to find each of > [a,b] [a,c] [a,d] [a,b,c] [a,b,d] [a,c,d] [b,c] [b,d] [b,c,d] [c,d]. As a first attempt to solve your problem, you could use the following "included(X,[a,b,c,d])" predicate: /* included(Set,SuperSet). True if all elements of Set in SuperSet, whatever the order of the elements is. */ included([X|Rest],SuperSet) :- member(X,SuperSet), del(X,SuperSet,SuperRest), included(Rest,SuperRest). included([],_). However, this predicate generates all the permutations of the possible solutions (i.e. [a,b,c] and [a,c,b] will be generated among other solutions). To eliminate these permutations, you can use a slightly different version of the "del" predicate: /* delUpTo(Element,OriginalList,ResultingList). Deletes first elements of OriginalList until it finds Element, then put result in ResultingList. */ delUpTo(X,[X|Rest],Rest). delUpTo(X,[_|ButOne],Rest) :- delUpTo(X,ButOne,Rest). /* included(Set,SuperSet). True if all elements of Set in SuperSet, in same order. Accepts [], [X] & full set. */ included([X|Rest],SuperSet) :- member(X,SuperSet), delUpTo(X,SuperSet,SuperRest), included(Rest,SuperRest). included([],_). There is still a small problem. "included" generates some undesired solutions (i.e. empty list, single element lists and full set). You can filter them: /* subset(Set,SuperSet). Like "included", but rejects [], [X] & full set. */ subset(Set,SuperSet) :- included(Set,SuperSet), filtered(Set,SuperSet). filtered( [] , _ ) :- !,fail. filtered( [_] , _ ) :- !,fail. filtered(FullSet,FullSet) :- !,fail. filtered( _ , _ ). included([X|Rest],SuperSet) :- member(X,SuperSet), delUpTo(X,SuperSet,SuperRest), included(Rest,SuperRest). included([],_). delUpTo(X,[X|Rest],Rest). delUpTo(X,[_|ButOne],Rest) :- delUpTo(X,ButOne,Rest). As you mentioned, you can use the "findall" predicate to generate a list of all solutions: findall(X,subset(X,[a,b,c,d]),ListOfSolutions) Hope this helps. B. Ibrahim IBRAHIM@CGEUGE51.BITNET cernvax!cui!bertrand.uucp cui!bertrand@cernvax.UUCP bertrand@cui.unige.chunet
rjmh@glasgow.glasgow.UUCP (Prof. John Hughes) (06/02/86)
>> From: dave@lsuc.UUCP >> Subject: miscellany re income tax planning system >> ... >> Third, I'm currently wrestling with the task of generating, >> for a list, every list which is a subset of that list. Thus, >> for [a,b,c,d], I want findall to be able to find each of >> [a,b] [a,c] [a,d] [a,b,c] [a,b,d] [a,c,d] [b,c] [b,d] [b,c,d] [c,d]. > This should do the trick: included(Subset,Set) is true if Subset is a subset of Set included([],Set). included([X|Subset],Set):-append(_,[X|Rest],Set),included(Subset,Rest). It only includes subsets whose elements are in the same order as in the original list.