Hi Bob,
You probably didn't mean to send this to the whole mailing list (!)
but I'll bet you intrigued a lot of people! Since you got the ball
rolling I'll answer in public as well.
I'm glad to see you've been making progress even though I haven't been
as helpful as I wanted to be. I think I have the missing piece of the
puzzle for you, though.
I've been thinking for a long time that it would be useful to change
the way the silly monolithic parser works. Right now, following CLIPS,
there's a parser that handles constructs like defrule, deffunction,
etc. Anything that doesn't appear to be one of these is assumed to be
a function. But the parser doesn't have to work this way. Indeed,
there's no reason at all why "defrule" can't just be a function like
any other (as these things tend to work in LISP.) Then you could
defadvice it, and therefore have that chance to figure out which
rules have fuzzy LHSs, etc. You could take all the time you needed at
this point without worrying about efficiency.
Does this sound like it would solve many of the difficulties?
I've made more comments below, so look carefully!
I think Bob Orchard wrote:
>
> Hello Ernest,
>
> I'm making good progress toward a FuzzyJess ... the Fuzzy part is ready it's
> just the Jess part that needs to be integrated.
>
> Here is my problem ... please feel free to ask for clarifications,
> make comments, make suggestions, be critical in any way ...
>
> Criteria (conflicting of course):
>
> 1. make the fuzzy extensions simple to use
> 2. minimize the code changes to Jess (none if possible)
> 3. keep the fuzzy inferencing from becoming inefficient
>
>
> I have struggled to find a simple way to get the integration of the Fuzzy
> classes to be usable with Jess without changing any Jess code but
> am yet to find a final solution ... everything still points to
> the need to do some hacking. I believe that the fuzzy classes represent
> a BIG improvement over the builtin extensions of FuzzyCLIPS.
> They can be used to do a lot of fuzzy manipulation outside of
> Jess and in many cases can be self sufficient, although integration
> with Jess will provide a natural simplification for doing
> fuzzy inferencing.
>
> Consider the following FuzzyCLIPS program (I ignore the Certainty Factor
> issue for now -- I don't think it is a big deal since it can easily
> be accomodated in the fuzzyModify function described below, by
> checking for a slot with a particular name (CF) and modifying it):
>
> (deftemplate Temperature -30.0 100.0 "degrees C"
> ((cold (z 5.0 15.0))
> (warm (pi 15.0 5.0))
> (hot (s 15.0 25.0))
> )
> )
>
> (deftemplate fanspeed 0 1000 RPM
> ((slow (z 60.0 200.0))
> (medium (pi 500.0 320.0))
> (fast (z 750.0 900.0))
> )
> )
>
> (defrule matchVeryCold
>
> ?f <- (temperature very cold)
> =>
> (assert (fanspeed very slow))
> (retract ?f)
> )
>
> (assert (temperature cold))
>
>
> There will be a partial match between "temperature very cold" (the pattern) and
> "temperature cold" (the fact). In effect this means that there is an overlap
> between the fact and the pattern that is significant (as determined by
> a threshold value ... normally 0.0). This will cause the rule to fire and
> the fact "fanSpeed very slow" will be asserted BUT the shape of the
> asserted fuzzy value will be a combination of the shape defined by "very slow"
> and the degree of matching of any fuzzy patterns on the LHS. In FuzzyCLIPS
> I 'look back' at the patterns and facts that matched them when the rule is
> fired and determine the impact that the fuzzy matching will have on
> any asserted fuzzy facts. Because of the tight integration with FuzzyCLIPS I
> am able to 'mark' a rule as a fuzzy rule at compile time and use this info
> in the handling of the RHS actions such as asserts of fuzzy facts. I even
> mark facts as fuzzy Facts if they have a fuzzy slot. There is more to do
> as well since even after the proper shape for the fuzzy value is determined
> it may be that there is already a fact with the same non-fuzzy slots ... if
> so then the 2 facts must be combined (union of the fuzzy values).
>
> Now the equivalent FuzzyJess program (as currently designed) ...
>
> (defglobal ?*tempFvar* = (new nrc.fuzzy.FuzzyVariable "Temperature" -30.0 100.0
>"degrees C"))
> (defglobal ?*fanspeedFvar* = (new nrc.fuzzy.FuzzyVariable "FanSpeed" 0.0 1000.0
>"RPM"))
>
I've just added an "import" command, llike the import statement in
Java, that will let you omit the package prefix in Jess code. That
would make this somewhat less daunting in appearance I think!
> (defrule init
> (declare (salience -100))
> =>
> (?*tempFvar* addTerm "cold" (new nrc.fuzzy.ZFuzzySet 5.0 15.0))
> (?*tempFvar* addTerm "warm" (new nrc.fuzzy.PIFuzzySet 15.0 5.0))
> (?*tempFvar* addTerm "hot" (new nrc.fuzzy.SFuzzySet 15.0 25.0))
> (assert (tempFact (new nrc.fuzzy.FuzzyValue ?*tempFvar* "cold")))
> (?*fanspeedFvar* addTerm "slow" (new nrc.fuzzy.ZFuzzySet 60.0 200.0))
> (?*fanspeedFvar* addTerm "medium" (new nrc.fuzzy.PIFuzzySet 500.0 320.0))
> (?*fanspeedFvar* addTerm "fast" (new nrc.fuzzy.SFuzzySet 750.0 900.0))
> )
>
> (defrule matchVeryCold
>
> ?f <- (tempFact ?t&:(?t fuzzyMatch "very cold"))
> =>
> (fuzzyModify
> (assert (fanspeedFact (new nrc.fuzzy.FuzzyValue ?*fanspeedFvar* "very slow")))
> )
> (retract ?f)
> )
>
>
> The matching of fuzzy slots can be easily replaced by a fuzzyMatch method
> that returns true if the fuzzy value in the fact and the specified fuzzy pattern
> overlap enough (as determined by a threshold value). However, this is
> now a bit more flexible than FuzzyCLIPS since the argument to fuzzyMatch can be
> a string or it may be a variable which holds a FuzzyValue (or a string).
> In FuzzyCLIPS the pattern was always a fixed string and determined at compile time.
> This I believe is a good bit of added flexibility for the user ... but
> as we'll see it adds to the difficulty in FuzzyJess.
>
> Now I cannot determine apriori if the rule has a fuzzy LHS since I
> do not want to get involved in compiling of the rules (without some restrictions
> as in FuzzyCLIPS it wouldn't likely be possible anyway). Therefore I need to find a
> way to find the fuzzy values and the patterns that were matched on the
> LHS (if any) to allow the appropriate shapes to be determined for any
> asserted facts that have fuzzy values in them.
Note that starting with Jess 5.0a5, the newest release, the
jess.Context object that is passed to every Unserfunction.call() method
has two methods, getToken() and getFact(), which give you access to
the two Rete inputs in the join nodes. I suppose it would be useful to
make a few mods such that thee will supply proper values in pattern
nodes as well! Anyhow, this will give you access to the partial match at
each stage.
First let me explain the rational
> for adding a fuzzyModify call around the assert call. It might be possible to
> use the defadvice for 'assert' but this would be most inefficient in a general
> program since many of the rules may not have a need to do the 'fuzzyModify'
> on a fact. It would also give the user some flexibility (if needed) to not
> have the standard fuzzy modifications done to particular facts. Whether I use
> defadvice or the function the assert still poses a problem ... assert returns
> only the last fact asserted rather than a list of all facts that have been asserted
> so either the user must wrap ONLY asserts that create single facts or the assert
> would have to be modified to return a either single fact or a list of facts
> (when more than 1 was asserted). This actually makes some sense to me since it
> might be a useful change to assert. The other problem comes with definstance
> since unlike assert it returns true or false rather than the fact that was
> asserted. So assuming these problems can be easily addressed fuzzyModify has
> some interesting things to do. It must find the fuzzy values (patterns)
> that matched with fuzzy values in facts on the LHS and use these to determine
> the actual shape for the fuzzy values in these asserted facts. This should
> only be done once per rule (for efficiency when the user uses several
> fuzzyModify calls) so it would be useful (I think necessary) to store these fuzzy
> value pairs after they have been found. Finding the fuzzy value pairs may not be
> too difficult since we can scan the facts that matched and then find the patterns
> that referenced fuzzyMatch and calculate the fuzzy values. However, this will in
> general not work since the argument to the fuzzyMatch method might have been a
> variable and by the time the fuzzyModify is called that variable may have changed!
> So it seems that the pairs of fuzzy values need to be recorded when the matching
> is done on the LHS and be accessible to an activation when the rule fires.
>
> (As I write this it is beginning to appear that the fuzzyMatch method of the
> class FuzzyValue would then be tied too closely to Jess and instead there
> should probably be a Jess function called fuzzyMatch that uses
> the fuzzyMatch method and handles the business of recording any Jess
> needed information)
>
> The problem gets a bit more complex since the fuzzyMatch (method or function)
> might be in a 'not' pattern in which case the fuzzy value in the fact and the
> pattern have no impact on facts asserted on the RHS.
>
> So basically I seem to need a way to store fuzzy value pairs as matches are
> made on the LHS and have those available when the RHS fires. Also I need
> to be able to determine if a function is being fired at the root level or
> in a rule firing so that fuzzyModify knows when it has to do calcs based
> on the LHS ... if at root level it just does the global contribution
> part.
>
I'll see about adding a facility like this to the Context class as well.
>
> There is still the issue of doing global contribution. This is the
> effect that takes place after the correct shape for the fuzzy values in
> a fact are determined above. The system needs to then check to see if there are
> any more facts that are identical to this one (like checking for duplicate
> facts, except that the facts are identical when they have the same non-fuzzy
> parts). If there are these facts get combined to show the contribution of
> many rules to the solution. This should not be difficult to do.
>
>
> So, my conclusions from all of this:
>
> 1. I do need to record the fuzzy value pairs that are successful with a
> fuzzyMatch used on the LHS of a rule (must be available for use on the
> RHS when a rule is activated); this is the only really troublesome
> thing to be done ... perhaps a general way to store extra info with
> a fact that matches a pattern and gets propogated down the net.
> Any insight on the best way to do this or an alternative idea?
Well, we could probably add a get/SetDatum method to the Token class,
which could carry an arbitrary object along. Tokens are shared in
funny ways in Jess, however, so we'd have to think about
this. Alternatively, you could do itbackward and fuzzyMatch could
store the data in its own internal hashtable, with tokens as the
keys. Actually, this is not bad; it's easy for the RHS to find the
matches, then, as well, as long as the context points to the token
(which it doesn't now, but could) on a rule LHS.
>
> 2. fuzzyMatch should be a Jess added user function that does this storing
> rather than a FuzzyValue method (separates the methods of the fuzzy
> values, which are used indepently from Jess as well, from the Jess
> inferencing requirements); there will still be a FuzzyValue method that
> can do the fuzzyMatch'ing. This will change the syntax of the above
> example a bit - the rule becomes
>
> (defrule matchVeryCold
>
> ?f <- (tempFact ?t&:(fuzzyMatch ?t "very cold")) ;;; minor change here
> =>
> (fuzzyModify
> (assert (fanspeedFact (new nrc.fuzzy.FuzzyValue ?*fanspeedFvar* "very
>slow")))
> )
> (retract ?f)
> )
>
>
>
> 3. could use a defadvice for fuzzyModify if I can make it efficient enough
> (for assertion of fact with no fuzzy values in it, it should quickly
> determine this); could also use the fuzzyModify function; in either
> case there must be a way to determine ALL of the facts that were
> asserted by the assert statement or the definstance -- perhaps a
> defadvice before and after could be used for assert or definstance;
> the before would get and store the next fact number to be used
> and the after would get the next fact number and iterate over all
> facts asserted between the before and after.
>
Perhaps assrt could be modified to return a multifield containing
the list of fact-ids asserted, rather than just the id of the last one.
>
> Sorry if this is unclear and rambling but sometimes I just need to bounce some
> ideas around someone else's head ... often the results are fruitful.
>
> Thanks, Bob.
>
>
> P.S. I've enclosed a zip file with the generated docs for the fuzzy classes to give
>you
> a flovor for what's been done.
---------------------------------------------------------
Ernest Friedman-Hill
Distributed Systems Research Phone: (925) 294-2154
Sandia National Labs FAX: (925) 294-2234
Org. 8920, MS 9214 [EMAIL PROTECTED]
PO Box 969 http://herzberg.ca.sandia.gov
Livermore, CA 94550
---------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [EMAIL PROTECTED]'
in the BODY of a message to [EMAIL PROTECTED], NOT to the
list. List problems? Notify [EMAIL PROTECTED]
---------------------------------------------------------------------