[eclipse-clp-users] product configuration problems

From: Tobias Tischler <tischler_at_acatec.de>
Date: Wed, 04 Jun 2008 18:18:19 +0200
Hi all,

we're working at a product configurator and want to implement a few new 
features. I think one of them is a CSP.
It consists of a database of products and some constraints between them. 
In the GUI we want to use comboboxes to display the content of the DB - 
each DB attribute in a separate combobox.
The main task of the program will be to determine all remaining 
possibilities of values for the comboboxes when the user selects the 
content of some of theses boxes to be one specific value.
When this is implemented, the bonus task will be to repair a wrong 
selection of values by the user: the program has to suggest another 
selection that differs in as little attributes as possible from the 
user-selection. In step 1 the programm can choose the attributes to 
change. In step 2 the user can point out the attributes that the 
programm may change.

Because I'm fairly new to Prolog and ECLiPSe and because I couldn't find 
anything alike this in the standard examples I'm asking you if you know 
of either an example I have missed or (even better :-) ) a solution for 
this problem.

So far I have implemented the DB as following:

:- lib(ic).

:-local struct( hdd(id, formfactor, capacity, sone) ).
hdd{id:'HD1', formfactor:'2.5', capacity:200, sone:0.9}.
hdd{id:'HD2', formfactor:'2.5', capacity:750, sone:3.0}.
hdd{id:'HD3', formfactor:'2.5', capacity:500, sone:1.2}.
hdd{id:'HD4', formfactor:'2.5', capacity:300, sone:1.5}.

:-local struct( case(id, type, color, power, formfactor) ).
case{id:'C1', type:'Big', color:'grey', power:500, formfactor:['ATX', 
'microATX']}.
case{id:'C2', type:'Midi', color:'grey', power:350, formfactor:['ATX', 
'BTX']}.
case{id:'C3', type:'Mini', color:'grey', power:200, 
formfactor:['microATX']}.

:-local struct( motherboard(id, socket, ram, formfactor, slot) ).
motherboard{id:'MB1', socket:'775', ram:32, formfactor:'ATX', 
slot:['PCI-E']}.
motherboard{id:'MB2', socket:'AM2', ram:32, formfactor:'ATX', 
slot:['PCI-E']}.
motherboard{id:'MB3', socket:'754', ram:8, formfactor:'microTX', 
slot:['AGP']}.
motherboard{id:'MB4', socket:'478', ram:16, formfactor:'ATX', 
slot:['PCI-E', 'AGP']}.
motherboard{id:'MB5', socket:'7', ram:4, formfactor:'BTX', slot:['AGP']}.

:-local struct( cpu(id, type, manufacturer, freqmin, freqmax, socket, 
power) ).
cpu{id:'C1', type:'Athlon64', manufacturer:'AMD', freqmin:1.8, 
freqmax:2.4, socket:'754', power:100}.
cpu{id:'C2', type:'Athlon64', manufacturer:'AMD', freqmin:1.8, 
freqmax:2.6, socket:'939', power:115}.
cpu{id:'C3', type:'Athlon64', manufacturer:'AMD', freqmin:2.0, 
freqmax:2.6, socket:'AM2', power:130}.
cpu{id:'C4', type:'Turion64', manufacturer:'AMD', freqmin:1.6, 
freqmax:2.4, socket:'754', power:80}.
cpu{id:'C5', type:'Core2Duo', manufacturer:'Intel', freqmin:1.8, 
freqmax:3.2, socket:'775', power:90}.
cpu{id:'C6', type:'Pentium4', manufacturer:'Intel', freqmin:1.3, 
freqmax:2.0, socket:'775', power:120}.
cpu{id:'C7', type:'Pentium4', manufacturer:'Intel', freqmin:1.3, 
freqmax:2.0, socket:'478', power:120}.

:-local struct( gpu(id, slot, power, benchmark) ).
gpu{id:'G1', slot:'AGP', power:125, benchmark:1000}.
gpu{id:'G2', slot:'PCI-E', power:160, benchmark:1500}.
gpu{id:'G3', slot:'PCI-E', power:250, benchmark:2000}.


% The method to get one solution is (until now):

main( HDD_ID, HDD_FORMFACTOR, HDD_CAPACITY, HDD_SONE,
       C_ID, C_TYPE, C_COLOR, C_POWER, C_FORMFACTOR,
       M_ID, M_SOCKET, M_RAM, M_FORMFACTOR, M_SLOT,
       CPU_ID, CPU_TYPE, CPU_MANUFACTURER, CPU_FREQMIN, CPU_FREQMAX, 
CPU_SOCKET, CPU_POWER,
       GPU_ID, GPU_SLOT, GPU_POWER, GPU_BENCHMARK )
        :-
          %% structs
           hdd{id:HDD_ID, formfactor:HDD_FORMFACTOR, 
capacity:HDD_CAPACITY, sone:HDD_SONE},
           case{id:C_ID, type:C_TYPE, color:C_COLOR, power:C_POWER, 
formfactor:C_FORMFACTOR},
           motherboard{id:M_ID, socket:M_SOCKET, ram:M_RAM, 
formfactor:M_FORMFACTOR, slot:M_SLOT},
           cpu{id:CPU_ID, type:CPU_TYPE, manufacturer:CPU_MANUFACTURER, 
freqmin:CPU_FREQMIN, freqmax:CPU_FREQMAX, socket:CPU_SOCKET, 
power:CPU_POWER},
           gpu{id:GPU_ID, slot:GPU_SLOT, power:GPU_POWER, 
benchmark:GPU_BENCHMARK},
          %% constraints (foreign keys for the DB)
           M_SOCKET = CPU_SOCKET,
           member(M_FORMFACTOR, C_FORMFACTOR),
           member(GPU_SLOT, M_SLOT),
           +(GPU_POWER, CPU_POWER, Temp1),
           /(Temp1, 1.4, Temp2),
           C_POWER >= Temp2,
          %% management constraints (the boss says, this has to be!!)
           constraint1(GPU_BENCHMARK, C_TYPE).

constraint1(GPU_BENCHMARK, 'Big') :- GPU_BENCHMARK >= 2000.
constraint1(GPU_BENCHMARK, _) :- GPU_BENCHMARK < 2000.


With the main-method I get all solutions one by one. But I just need the 
remaining domains reduced by invalid domain values, but not all possible 
remaining solutions.
This could be extracted by looping all solutions and listing all domain 
values that occur at least once (using findall/3 or setof/3 or something 
alike), but this works too slow.

Based on this example I am interested in the following answers:

1. at start no initial values -> find all possible solutions one by one
2. at start some fine initial values -> find remaining domain values
3. at start some fine and some invalid values -> find solution by 
adjusting minimum invalid values
4. at start some required and some tentative values -> find solution by 
adjusting tentative values only

So now I hope one of you can help me with this problem or at least can 
show me a direction where to search for a solution.

Thanks,
Tobias



Received on Wed Jun 04 2008 - 09:18:29 CEST

This archive was generated by hypermail 2.2.0 : Thu Feb 02 2012 - 02:31:58 CET