The application I'm working on is a "configurator" of sorts. It's written in C# and I even wrote a rules engine to go with it. The idea is that there are a bunch of propositional logic statements, and the user can make selections. Based on what they've selected, some other items become required or completely unavailable.
The propositional logic statements generally take the following forms:
A => ~X
ABC => ~(X+Y)
A+B => Q
A(~(B+C)) => ~Q A <=> B
The symbols:
=> -- Implication
<=> -- Material Equivalence
~ -- Not
+ -- Or
Two letters side-by-side -- And
I'm very new to Prolog, but it seems like it might be able to handle all of the "rules processing" for me, allowing me to get out of my current rules engine (it works, but it's not as fast or easy to maintain as I would like).
In addition, all of the available options fall in a hierarchy. For instance:
Outside
Color
Red
Blue
Green
Material
Wood
Metal
If an item at the second level (feature, such as Color) is implied, then an item at the third level (option, such as Red) must be selected. Similarly if we know that a feature is false, then all of the options under it are also false.
The catch is that ev开发者_如何学运维ery product has it's own set of rules. Is it a reasonable approach to set up a knowledge base containing these operators as predicates, then at runtime start buliding all of the rules for the product?
The way I imagine it might work would be to set up the idea of components, features, and options. Then set up the relationships between then (for instance, if the feature is false, then all of its options are false). At runtime, add the product's specific rules. Then pass all of the user's selections to a function, retrieving as output which items are true and which items are false.
I don't know all the implications of what I'm asking about, as I'm just getting into Prolog, but I'm trying to avoid going down a bad path and wasting lots of time in the process.
Some questions that might help target what I'm trying to find out:
- Does this sound do-able?
- Am I barking up the wrong tree?
- Are there any drawbacks or concerns to trying to create all of these rules at runtime?
- Is there a better system for this kind of thing out there that I might be able to squeeze into a C# app (Silverlight, to be exact)?
- Are there other competing systems that I should examine?
- Do you have any general advice about this sort of thing?
Thanks in advance for your advice!
- Sure, but Prolog has a learning curve.
- Rule-based inference is Prolog's game, though you may have to rewrite many rules into Horn clauses.
A+B => Q
is doable (it becomesq :- a. q :- b.
orq :- (a;b).
) but your other examples must be rewritten, includingA => ~X
. - Depends on your Prolog compiler, specifically whether it supports indexing for dynamic predicates.
- Search around for terms like "forward checking", "inference engine" and "business rules". Various communities keep inventing different terminologies for this problem.
- Constraint Handling Rules (CHR) is a logic programming language, implemented as a Prolog extension, that is much closer to rule-based inference/forward chaining/business rules engines. If you want to use it, you'll still have to learn basic Prolog, though.
- Keep in mind that Prolog is a programming language, not a silver bullet for logical inference. It cuts some corners of first-order logic to keep things efficiently computable. This is why it only handles Horn clauses: they can be mapped one-to-one with procedures/subroutines.
You can also throw in DCGs to generate bill of materials. The idea is roughly that terminals can be used to indicate subproducts, and non-terminals to define more and more complex combinations of a subproducts until you arrive at your final configurable products.
Take for example the two attribute value pairs Color in {red, blue, green} and Material in {wood, metal}. These could specify a door knob, whereby not all combinations are possible:
knob(red,wood) --> ['100101'].
knob(red,metal) --> ['100102'].
knob(blue,metal) --> ['100202'].
You could then define a door as:
door ... --> knob ..., panel ...
Interestingly you will not see any logic formula in such a product specification, only facts and rules, and a lot of parameters passed around. You can use the parameters in a knowledge acquisition component. By just running uninstantiated goals you can derive possible values for the attribute value pairs. The predicate setof/3 will sort and removen duplicates for you:
?- setof(Color,Material^Bill^knob(Color,Material,Bill,[]),Values).
Value = [blue, red]
?- setof(Material,Color^Bill^knob(Color,Material,Bill,[]),Values).
Material = [metal, wood]
Now you know the range of the attributes and you can let the end-user successively pick an attribute and a value. Assume he takes the attribute Color and its value blue. The range of the attribute Material then shrinks accordingly:
?- setof(Material,Bill^knob(blue,Material,Bill,[]),Values).
Material = [metal]
In the end when all attributes have been specified you can read off the article numbers of the subproducts. You can use this for price calculation, by adding some facts that give you additional information on the article numbers, or to generate ordering lists etc..:
?- knob(blue,metal,Bill,[]).
Bill = ['100202']
Best Regards
P.S.: Oh it seems that the bill of materials idea used in the product configurator goes back to Clocksin & Mellish. At least I find a corresponding comment here: http://www.amzi.com/manuals/amzi/pro/ref_dcg.htm#DCGBillMaterials
精彩评论