minimize/1 is not rearranging the order of solutions

78 views Asked by At

For Colombia's Observatorio Fiscal[1], I am coding a simple tax minimization problem, using CLP(R) (in SWI-Prolog). I want to use minimize/1 to find the least solution first. It is instead listing the bigger solution first. Here is the code:

:- use_module(library(clpr)).

deduction(_,3).            % Anyone can take the standard deduction.
deduction(Who,D) :- itemizedDeduction(Who,D). % Or they can itemize.

income(joe,10).            % Joe makes $10 a year.
itemizedDeduction(joe,4).  % He can deduct more if he itemizes.

taxableIncome(Who,TI) :-
   deduction(Who,D),
   income(Who,I),
   TI is I - D,
   minimize(TI).

Here is what an interactive session looks like:

?- taxableIncome(joe,N).
N = 7 ;
N = 6 ;
false.

If I switch the word "minimize" to "maximize" it behaves identically. If I include no minimize or maximize clause, it doesn't look for a third solution, but otherwise it behaves the same:

?- taxableIncome(joe,N).
N = 7 ;
N = 6.

[1] The Observatorio Fiscal is a new organization that aims to model the Colombian economy, in order to anticipate the effects of changes in the law, similar to what the Congressional Budget Office or the Tax Policy Center do in the United States.

2

There are 2 answers

1
mat On

First, let's add the following definition to the program:

:- op(950,fy, *).
*_.

Using (*)/1, we can generalize away individual goals in the program.

For example, let us generalize away the minimize/1 goal by placing * in front:

taxableIncome(Who,TI) :-
        deduction(Who,D),
        income(Who,I),
        TI #= I - D,
        * minimize(TI).

We now get:

?- taxableIncome(X, Y).
X = joe,
Y = 7 ;
X = joe,
Y = 6.

This shows that CLP(R) in fact has nothing to do with this issue! These answers show that everything is already instantiated at the time minimize/1 is called, so there is nothing left to minimize.

To truly benefit from minimize/1, you must express the task in the form of CLP(R)—or better: CLP(Q)— constraints, then apply minimize/1 on a constrained expression.

Note also that in SWI-Prolog, both CLP(R) and CLP(Q) have elementary mistakes, and you cannot trust their results.

0
Jeffrey Benjamin Brown On

Per Mat's response, I rewrote the program expressing the constraints using CLP. The tricky bit was that I had to first collect all (both) possible values for deduction, then convert those values into a CLP domain. I couldn't get that conversion to work in CLP(R), but I could in CLP(FD):

:- use_module(library(clpfd)).

deduction(_,3).     % Anyone can take the same standard deduction.
deduction(Who,D) :- % Or they can itemize.
    itemizedDeduction(Who,D).

income(joe,10).
itemizedDeduction(joe,4).

listToDomain([Elt],Elt).
listToDomain([Elt|MoreElts],Elt \/ MoreDom) :-
    MoreElts \= []
    , listToDomain(MoreElts,MoreDom).

taxableIncome(Who,TI) :- 
    income(Who,I)
    , findall(D,deduction(Who,D),DList)
    , listToDomain(DList,DDomain)
    % Next are the CLP constraints.
    , DD in DDomain
    , TI #= I-DD
    , labeling([min(TI)],[TI]).