How to find the best matching fact

hey guy, im trying to build a recommendation system for computer hardware. For now i just want to ask for a game that the user wants to be able to play on his new system and and suggest him a graphiccard and a cpu. So for example he says “minecraft” and minecraft needs 2GB Graphics memory and a processor with 4 cores and 3.9 clockrate. Now i have some different CPUs and GPUs implemented as facts. Obviously there is not everytime a hardware that matches the requirements 100% so i want to give the user the one, that matches the best. So if he needs 3.9 clockrate prolog should also answer with one that has 4.0 if no with 3.9 is available. For now my code only works, if there is one hardware that matches 100% the requierements.

here is my code:

/*Marke,Modell,Kerne,Turbotakt,Prozessorgrafik(true,false),max-ram*/
prozessor(intel,'i7-11850HE',8,4.7,true,128).
prozessor(intel,'i7-8750H',6,4.1,true,64).
prozessor(intel,'i5-8400',6,4.0,true,128).
prozessor(intel,'i3-3220',2,3.3,true,32).
prozessor(amd,'ryzen 5 3600',6,4.2,false,128).
prozessor(amd,'ryzen threadripper 3990X',64,4.3,false,256).


/*marke,modell,grafikspeicher*/
grafikkarte(nvidia,'geforce gtx 1050',2).
grafikkarte(nvidia,'geforce gtx 1050 ti', 4).
grafikkarte(nvidia,'geforce rtx 2080',8).
grafikkarte(nvidia,'geforce rtx 3080',10).

/*Spiele specs (name,ram, gpu, speicher, Kerne, Takt)
*/
spiel('cyberpunk 2077',12,6,70,4,4.0).
spiel('valorant',4,4,8,4,3.4).
spiel('warzone',12,6,175,6,3.7).
spiel('gtav',8,2,72,4,3.6).
spiel('minecraft',4,2,4,4,3.9).

/*Programme kerne,takt, gpuspeicher, ram, speicher*/
programm('photoshop',2.0,2,4,8,4).
programm('after effects',4,3.0,16,4,15). /*32 Ram bei 4K*/
programm('premiere pro',8, 4.0,16,4,8). /*32 Ram bei 4K*/
programm('blender',4, 4.0, 16, 6,0).


go:-
write("Office,Gaming oder Arbeit?"),
read(Typ),
(Typ == 'gaming' -> 
write("Sie möchten also einen GamingPc, welche Spiele möchten Sie spielen?"),nl,
read(Game1),nl,
spiel(Game1,A,Y,B,X,Z),
grafikkarte(V,W,Y),
prozessor(Name,Modell,X,Z,Grafik,Ram),
write("Unsere Empfehlung:"), write(V), write(W), write(" mit "), write(Y), write("GB Grafikspeicher"),nl,
write(Name),write(Modell)
;
Typ == 'office' -> write("office");
Typ == 'arbeit' -> write("workstation"); false).



My first choice would be to use constraints, in particular CLP(FD).

My second choice would be s(CASP). The reason it is second is that at present (10/22/2021) the code is so new it is not even in the devel release much less the stable release.

See:

HTH

first of all thanks for your fast answer, but i dont get that to be honest. Im a newbie :D.
Im planing to use pengines when my code is finished. So did i get that right, that there is no possbiliy to this offline/without any extern service? I thought its just like a new rule which can be easy implemented…

Or is there maybe a workaround to select a cpu with >= clockrate than the needed one? So if i write the facts in the right descending order it should select the right one, doesnt it?

I don’t see why you can’t use either means offline.

Constraints is just a library you add via use_module/1, s(CASP) is so new I don’t know where to start other than looking at the example code (see below).

Since SWISH is based on Pengines, (remember I don’t use SWISH or Pengines so this is a guess) if SWISH does it then Pengines should be able to do it.

Examples:

Constraints on SWISH

N-Queens (code)

s(CASP) on SWISH

Intro (code)


Since Prolog is a logic language the order of the facts and predicates should not matter, or so goes the idea. Rearanging facts to get a desired outcome is one of the last choices I would make to get the code to work. Instead understand how the logic works and use that to your benefit. As I noted your project is more like a second semester term project and you are in the first few weeks of the first semester, keep learning.

To better understand constraints see:

The Power of Prolog

Normally I would link right to the needed part but you need to read the entire site.

Here is a StackOverflow answer I wrote about the N-Queens problem.

Thank you very much. I will read those ressources and try to do it :slight_smile:

Roughly, there are two options. Constraint systems have been mentioned and are typically a good solution for solving configuration problems. The classic Prolog way is to produce multiple configurations on backtracking, e.g. all that have a clock >= 3.9Ghz. Next you give a rating to each generated configuration and take the best. The classic Prolog way is to use findall/3 to first generate a list of possible configurations and select the best from their. aggregate_all/4 provides an alternative.

s(CASP) has no optimization options. It is mostly a subsystem that provides stable model semantics for reasoning about possible worlds when negations play an important role. It is positioned by its inventors as a solution for common sense reasoning in worlds with negation and incomplete knowledge (i.e., what we encounter daily in real life).

1 Like

thank you, is it possible that you can give me an example? Ive tried it now and cant get it to work. I think i dont get how to implement those given solutions but i will need this multiple times in future.

I know you probably intended the reply for Jan W.

I can help you locate example code but for me the obvious question is, which option?

  1. Constraint systems
  2. Classic Prolog way
    a. findall/3
    b. aggregate_all/4

Thanks, actually i dont know which solution is the best i would just want to do that one, that is the most easy to implement. Its not about writing the best prolog code but writing something that works for the beginning.

I will take that to mean the one that requires the least amount of learning.

Since s(CASP) is so new and still has warts and those using it are finding bugs and discrepancies lets cross s(CASP) off the list.
Since constraint systems require a good understanding of Prolog before one can start to use constraints effectively and AFAIK there is no way to debug constraints as expected with something like gtrace/0 lets cross constraint systems off the list.
Since aggregate_all/4 is a generalisation of the bagof/3, setof/3 and findall/3 built-in predicates one would have to have a basic knowledge of findall/3, lets cross aggregate_all/4 off the list.

The only option left is findall/3.

That is one of the guiding principles I use, get it working first, then go after optimizations.


So you are asking for example code for a recommendation system based on findall/3.

While the Prolog repositories for SWI-Prolog on GitHub are loaded with the use of findall/3, (list) AFAIK none of them are used to implement a recommendation system.

IIRC one of the classic books creates a recommendation system as one of the ending chapters so will have to take a look to verify.

Give me some time while I look.


EDIT

The Art of Prolog - advanced programming techniques by Leon S Sterling, Ehud Y Shapior and David H D Warren (WorldCat )

Chapter 22 - A Credit Evaluation Expert System

The code has one findall/3, is very simple and has an entire chapter to help understand the code.

A free PDF copy can be downloaded under the Open Access section. (ref)
Noah Evans has posted the code on GitHub (code)

3 Likes

So i read the pdf and i dont think that this would fit my needs, maybe im wrong.
I also tried to use findall but i cant get it to work. Its kinda frustrating because its very hard for me to understand prolog documentation and functions. Im thinking of just skipping this problem and using a workaround like just rounding everything to the next bigger integer like 3,9 to 4 to get everytime a solution not a beatiful solution but im trying this some days now and cant move forward.

Remember the warning. (ref)

This document is a reference manual . That means that it documents the system, but it does not explain the basics of the Prolog language and it leaves many details of the syntax, semantics and built-in primitives undefined where SWI-Prolog follows the standards. This manual is intended for people that are familiar with Prolog.

I suspect that you are trying to jump to far ahead. Try taking predicates that you don’t understand such as findall/3 and write test cases (ref) until you clearly understand it.

It took me several months before I was comfortable using such predicates but now they roll off my fingertips like playing music on a piano. :slightly_smiling_face: I still favor setof/3 over findall/3 when starting new code but once the problem starts to congeal and the existentials (^) can be removed, findall/3 is then used.