Do I still need to make the issue or is Edson already on it?
With kind regards,
Geoffrey De Smet
Mark Proctor wrote:
can you pop this into a jira for me. After 2-3 days I lose track of
emails in the lists, as I only tend to skim read.
Mark
Geoffrey De Smet wrote:
> As promised :) (be carefull what you wish for)
>
> - "<init code>: this is a semantic block of code in the selected
> dialect that will be executed once for each tuple, before iterating
> over the source objects."
>
> What is a "tuple"?
> Do you mean "once for each rule" or "once for each pattern
match"?
> (I presume the first, after reading further.)
>
> - "Source objects" are facts that follow the source pattern I presume?
> Or is there a difference?
>
> - The method javadocs in the AverageAccumulateFunction example are a
> bit too besides the point IMHO. I'd leave them out.
>
>
> Summary: nothing seriously wrong with that documentation, looks good :)
>
> With kind regards,
> Geoffrey De Smet
>
>
> Edson Tirelli wrote:
>>
>> Geoffrey,
>>
>> The "sum" function that is shipped with drools always uses double
>> internally, but all numeric accumulate functions must have return
>> type Number to avoid class cast exceptions... I must write that in
>> the docs... so, recommendation is to do:
>>
>> Number( $total : intValue ) from accumulate(
>> Hop($distance : distance ), // distance is an int
>> sum($distance)
>> );
>>
>> Now, having said that, the decision to use double is because we
>> needed a one size fits all to ship with drools. On the other hand I
>> tried to make as simple as possible to plug new or replace built-in
>> functions. So, if you want a sum function that uses only integers,
>> you can easily develop and plug it your own. Since I just wrote the
>> docs on how to do it, may I ask you please to read them and provide a
>> feedback if they are good, need more info, shall I write them in
>> another way, etc?
>> BTW, when I say it is really simple to create another sum
>> function, I mean, you can do it in about 20 minutes. Really!
>>
>> Find attached the HTML doc page I'm talking about.
>>
>> []s
>> Edson
>>
>>
>> 2007/7/22, Geoffrey De Smet < ge0ffrey.spam(a)gmail.com
>> <mailto:ge0ffrey.spam@gmail.com>>:
>>
>> Hi guys,
>>
>> I finally got around to experimenting with the accumulate support in
>> LocalSearchSolver. Thanks for implementing it :)
>>
>> I use nothing but int's in my calculations,
>> but I get a ClassCastExceptions, as sum() always returns a Double
>> and
>> setSoftConstraintsBroken(int) failes.
>>
>> In a previous benchmarks I 've proven that summing integers in
>> double's
>> instead of int's hurts performance for 10% or more (which is rather
>> big).
>>
>> Is there a sumInteger() available (or do I need to write it)? Or
>> can it
>> be overloaded over sum() in a much cleaner way?
>>
>>
>>
>> rule "ScoreCalculator"
>> when
>> $scoreFact : ScoreFact(); // singleton
>> $total : Integer() from accumulate(
>> Hop($distance : distance ), // distance is an int
>> sum($distance)
>> );
>> then
>> $scoreFact.setSoftConstraintsBroken($total);
>> end
>>
>>
>> svn is still here, till it's ready for drools:
>>
https://taseree.svn.sourceforge.net/svnroot/taseree/trunk
>>
>> --
>> With kind regards,
>> Geoffrey De Smet
>>
>> _______________________________________________
>> rules-dev mailing list
>> rules-dev(a)lists.jboss.org <mailto:rules-dev@lists.jboss.org>
>>
https://lists.jboss.org/mailman/listinfo/rules-dev
>>
>>
>>
>>
>> --
>> Edson Tirelli
>> Software Engineer - JBoss Rules Core Developer
>> Office: +55 11 3529-6000
>> Mobile: +55 11 9287-5646
>> JBoss, a division of Red Hat @
www.jboss.com <
http://www.jboss.com>
>> ------------------------------------------------------------------------
>>
>> 3.6. Advanced Conditional Elements
>> Prev <ch03s05.html> Chapter 3. The Rule Language Next
>> <ch03s07.html>
>>
>> ------------------------------------------------------------------------
>>
>>
>> 3.6. Advanced Conditional Elements
>>
>>
>> Note
>>
>> /|(updated to Drools 4.0)|/
>>
>> Drools 4.0 introduces a whole new set of conditional elements in
>> order to support full First Order Logic expressiveness, as well as
>> some facilities for handling collections of facts. This section will
>> detail the following new Conditional Elements:
>>
>> *
>>
>> from
>>
>> *
>>
>> collect
>>
>> *
>>
>> accumulate
>>
>> *
>>
>> forall
>>
>>
>> 3.6.1. From
>>
>> The *from* Conditional Element allows users to specify a source for
>> patterns to reason over. This allows the engine to reason over data
>> not in the Working Memory. This could be a sub-field on a bound
>> variable or the results of a method call. It is a powerful
>> construction that allows out of the box integration with other
>> application components and frameworks. One common example is the
>> integration with data retrieved on-demand from databases using
>> hibernate named queries.
>>
>> The expression used to define the object source is any expression
>> that follows regular MVEL syntax. I.e., it allows you to easily use
>> object property navigation, execute method calls and access maps and
>> collections elements.
>>
>> Here is a simple example of reasoning and binding on another pattern
>> sub-field:
>>
>> rule "validate zipcode"
>> when
>> Person( $personAddress : address ) Address( zipcode ==
>> "23920W") from $personAddress then
>> # zip code is ok
>> end
>>
>> With all the flexibility from the new expressiveness in the Drools
>> engine you can slice and dice this problem many ways. This is the
>> same but shows how you can use a graph notation with the 'from':
>>
>> rule "validate zipcode"
>> when
>> $p : Person( ) $a : Address( zipcode == "23920W") from
>> $p.address then
>> # zip code is ok
>> end
>>
>> Previous examples were reasoning over a single pattern. The *from* CE
>> also support object sources that return a collection of objects. In
>> that case, *from* will iterate over all objects in the collection and
>> try to match each of them individually. For instance, if we want a
>> rule that applies 10% discount to each item in an order, we could do:
>>
>> rule "apply 10% discount to all items over US$ 100,00 in an order"
>> when
>> $order : Order()
>> $item : OrderItem( value > 100 ) from $order.items
>> then
>> # apply discount to $item
>> end
>>
>> The above example will cause the rule to fire once for each item
>> whose value is greater than 100 for each given order.
>>
>> The next example shows how we can reason over the results of a
>> hibernate query. The Restaurant pattern will reason over and bind
>> with each result in turn:
>>
>>
>> 3.6.2. Collect
>>
>> The *collect* Conditional Element allows rules to reason over
>> collection of objects collected from the given source or from the
>> working memory. A simple example:
>>
>> import java.util.ArrayList
>>
>> rule "Raise priority if system has more than 3 pending alarms"
>> when
>> $system : System()
>> $alarms : ArrayList( size >= 3 )
>> from collect( Alarm( system == $system, status ==
>> 'pending' ) )
>> then
>> # Raise priority, because system $system has
>> # 3 or more alarms pending. The pending alarms
>> # are $alarms.
>> end
>>
>> In the above example, the rule will look for all pending alarms in
>> the working memory for each given system and group them in
>> ArrayLists. If 3 or more alarms are found for a given system, the
>> rule will fire.
>>
>> The *collect* CE result pattern can be any concrete class that
>> implements tha java.util.Collection interface and provides a default
>> no-arg public constructor. I.e., you can use default java collections
>> like ArrayList, LinkedList, HashSet, etc, or your own class, as long
>> as it implements the java.util.Collection interface and provide a
>> default no-arg public constructor.
>>
>> Both source and result patterns can be constrained as any other pattern.
>>
>> Variables bound before the *collect* CE are in the scope of both
>> source and result patterns and as so, you can use them to constrain
>> both your source and result patterns. Although, the /collect( ... )/
>> is a scope delimiter for bindings, meaning that any binding made
>> inside of it, is not available for use outside of it.
>>
>> Collect accepts nested *from* elements, so the following example is a
>> valid use of *collect*:
>>
>> import java.util.LinkedList;
>>
>> rule "Send a message to all mothers"
>> when
>> $town : Town( name == 'Paris' )
>> $mothers : LinkedList() from collect( Person(
>> gender == 'F', children > 0 ) from
>> $town.getPeople() )
>> then
>> # send a message to all mothers
>> end
>>
>>
>> 3.6.3. Accumulate
>>
>> The *accumulate* Conditional Element is a more flexible and powerful
>> form of *collect* Conditional Element, in the sense that it can be
>> used to do what *collect* CE does and also do things that *collect*
>> CE is not capable to do. Basically what it does is it allows a rule
>> to iterate over a collection of objects, executing custom actions for
>> each of the elements, and at the end return a result object.
>>
>> The general syntax of the *accumulate* CE is:
>>
>> /|<result pattern>|/ from accumulate( /|<source pattern>|/,
>> init( /|<init code>|/ ),
>> action( /|<action code>|/ ),
>> reverse( /|<reverse code>|/ ),
>> result( /|<result expression>|/ ) )
>>
>> The meaning of each of the elements is the following:
>>
>> *
>>
>> *<source pattern>*: the source pattern is a regular pattern that
>> the engine will try to match against each of the source objects.
>>
>> *
>>
>> *<init code>*: this is a semantic block of code in the selected
>> dialect that will be executed once for each tuple, before
>> iterating over the source objects.
>>
>> *
>>
>> *<action code>*: this is a semantic block of code in the selected
>> dialect that will be executed for each of the source objects.
>>
>> *
>>
>> *<reverse code>*: this is an optional semantic block of code in
>> the selected dialect that if present will be executed for each
>> source object that no longer matches the source pattern. The
>> objective of this code block is to "undo" any calculation done
in
>> the <action code> block, so that the engine can do decremental
>> calculation when a source object is modified or retracted, hugely
>> improving performance of these operations.
>>
>> *
>>
>> *<result expression>*: this is a semantic expression in the
>> selected dialect that is executed after all source objects are
>> iterated.
>>
>> *
>>
>> *<result pattern>*: this is a regular pattern that the engine
>> tries to match against the object returned from the <result
>> expression>. If it matches, the *accumulate* conditional element
>> evaluates to *true* and the engine proceeds with the evaluation of
>> the next CE in the rule. If it does not matches, the *accumulate*
>> CE evaluates to *false* and the engine stops evaluating CEs for
>> that rule.
>>
>> It is easier to understand if we look at an example:
>>
>> rule "Apply 10% discount to orders over US$ 100,00"
>> when
>> $order : Order()
>> $total : Number( doubleValue > 100 ) from
>> accumulate( OrderItem( order == $order, $value : value ),
>> init( double total = 0; ),
>> action( total += $value; ),
>> reverse( total -= $value; ),
>> result( total ) )
>> then
>> # apply discount to $order
>> end
>>
>> In the above example, for each Order() in the working memory, the
>> engine will execute the *init code* initializing the total variable
>> to zero. Then it will iterate over all OrderItem() objects for that
>> order, executing the *action* for each one (in the example, it will
>> sum the value of all items into the total variable). After iterating
>> over all OrderItem, it will return the value corresponding to the
>> *result expression* (in the above example, the value of the total
>> variable). Finally, the engine will try to match the result with the
>> Number() pattern and if the double value is greater than 100, the
>> rule will fire.
>>
>> The example used java as the semantic dialect, and as such, note that
>> the usage of ';' is mandatory in the init, action and reverse code
>> blocks. The result is an expression and as such, it does not admit
>> ';'. If the user uses any other dialect, he must comply to that
>> dialect specific syntax.
>>
>> As mentioned before, the *reverse code* is optional, but it is
>> strongly recommended that the user writes it in order to benefit from
>> the /improved performance on update and retracts/.
>>
>> The *accumulate* CE can be used to execute any action on source
>> objects. The following example instantiates and populates a custom
>> object:
>>
>> rule "Accumulate using custom objects"
>> when
>> $person : Person( $likes : likes )
>> $cheesery : Cheesery( totalAmount > 100 )
>> from accumulate( $cheese : Cheese( type == $likes ),
>> init( Cheesery cheesery = new
>> Cheesery(); ),
>> action( cheesery.addCheese( $cheese
>> ); ),
>> reverse( cheesery.removeCheese(
>> $cheese ); ),
>> result( cheesery ) );
>> then
>> // do something
>> end
>>
>>
>> 3.6.3.1. Accumulate Functions
>>
>> The accumulate CE is a very powerful CE, but it gets real declarative
>> and easy to use when using predefined functions that are known as
>> Accumulate Functions. They work exactly like accumulate, but instead
>> of explicitly writing custom code in every accumulate CE, the user
>> can use predefined code for common operations.
>>
>> For instance, the rule to apply discount on orders written in the
>> previous section, could be written in the following way, using
>> Accumulate Functions:
>>
>> rule "Apply 10% discount to orders over US$ 100,00"
>> when
>> $order : Order()
>> $total : Number( doubleValue > 100 ) from
>> accumulate( OrderItem( order == $order, $value : value ),
>> sum( $value ) )
>> then
>> # apply discount to $order
>> end
>>
>> In the above example, sum is an AccumulateFunction and will sum the
>> $value of all OrderItems and return the result.
>>
>> Drools 4.0 ships with the following built in accumulate functions:
>>
>> *
>>
>> average
>>
>> *
>>
>> min
>>
>> *
>>
>> max
>>
>> *
>>
>> count
>>
>> *
>>
>> sum
>>
>> These common functions accept any expression as input. For instance,
>> if someone wants to calculate the average profit on all items of an
>> order, a rule could be written using the average function:
>>
>> rule "Average profit"
>> when
>> $order : Order()
>> $profit : Number() from accumulate( OrderItem(
>> order == $order, $cost : cost, $price : price )
>> average( 1 - $cost / $price ) )
>> then
>> # average profit for $order is $profit
>> end
>>
>> Accumulate Functions are all pluggable. That means that if needed,
>> custom, domain specific functions can easily be added to the engine
>> and rules can start to use them without any restrictions. To
>> implement a new Accumulate Functions all one needs to do is to create
>> a java class that implements the
>> org.drools.base.acumulators.AccumulateFunction interface and add a
>> line to the configuration file or set a system property to let the
>> engine know about the new function. As an example of an Accumulate
>> Function implementation, the following is the implementation of the
>> "average" function:
>>
>> /*
>> * Copyright 2007 JBoss Inc
>> * * Licensed under the Apache License, Version 2.0 (the "License");
>> * you may not use this file except in compliance with the License.
>> * You may obtain a copy of the License at
>> * *
http://www.apache.org/licenses/LICENSE-2.0
>> * * Unless required by applicable law or agreed to in writing,
>> software
>> * distributed under the License is distributed on an "AS IS" BASIS,
>> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
>> implied.
>> * See the License for the specific language governing permissions and
>> * limitations under the License.
>> *
>> * Created on Jun 21, 2007
>> */
>> package org.drools.base.accumulators;
>>
>>
>> /**
>> * An implementation of an accumulator capable of calculating average
>> values
>> * * @author etirelli
>> *
>> */
>> public class AverageAccumulateFunction implements AccumulateFunction {
>>
>> protected static class AverageData {
>> public int count = 0;
>> public double total = 0;
>> }
>>
>> /* (non-Javadoc)
>> * @see
>> org.drools.base.accumulators.AccumulateFunction#createContext()
>> */
>> public Object createContext() {
>> return new AverageData();
>> }
>>
>> /* (non-Javadoc)
>> * @see
>> org.drools.base.accumulators.AccumulateFunction#init(java.lang.Object)
>> */
>> public void init(Object context) throws Exception {
>> AverageData data = (AverageData) context;
>> data.count = 0;
>> data.total = 0;
>> }
>>
>> /* (non-Javadoc)
>> * @see
>> org.drools.base.accumulators.AccumulateFunction#accumulate(java.lang.Object,
>> java.lang.Object)
>> */
>> public void accumulate(Object context,
>> Object value) {
>> AverageData data = (AverageData) context;
>> data.count++;
>> data.total += ((Number) value).doubleValue();
>> }
>>
>> /* (non-Javadoc)
>> * @see
>> org.drools.base.accumulators.AccumulateFunction#reverse(java.lang.Object,
>> java.lang.Object)
>> */
>> public void reverse(Object context,
>> Object value) throws Exception {
>> AverageData data = (AverageData) context;
>> data.count--;
>> data.total -= ((Number) value).doubleValue();
>> }
>>
>> /* (non-Javadoc)
>> * @see
>> org.drools.base.accumulators.AccumulateFunction#getResult(java.lang.Object)
>>
>> */
>> public Object getResult(Object context) throws Exception {
>> AverageData data = (AverageData) context;
>> return new Double( data.count == 0 ? 0 : data.total /
>> data.count );
>> }
>>
>> /* (non-Javadoc)
>> * @see
>> org.drools.base.accumulators.AccumulateFunction#supportsReverse()
>> */
>> public boolean supportsReverse() {
>> return true;
>> }
>>
>> }
>>
>> The code for the function is very simple, as we could expect, as all
>> the "dirty" integration work is done by the engine. Finally, to plug
>> the function into the engine, we added it to the configuration file:
>>
>> drools.accumulate.function.average =
>> org.drools.base.accumulators.AverageAccumulateFunction
>>
>> Where "drools.accumulate.function." is a prefix that must always be
>> used, "average" is how the function will be used in the rule file,
>> and "org.drools.base.accumulators.AverageAccumulateFunction" is the
>> fully qualified name of the class that implements the function behavior.
>>
>>
>> 3.6.4. Forall
>>
>> *Forall* is the Conditional Element that completes the First Order
>> Logic support in Drools. The syntax is very simple:
>>
>> forall( /|<select pattern>|/ /|<constraint patterns>|/ )
>>
>> The *forall* Conditional Element will evaluate to true when all facts
>> that match the /|<select pattern>|/ match all the /|<constraint
>> patterns>|/. Example:
>>
>> rule "All english buses are red"
>> when
>> forall( $bus : Bus( type == 'english') Bus(
>> this == $bus, color = 'red' ) )
>> then
>> # all english buses are red
>> end
>>
>> In the above rule, we "select" all Bus object whose type is
>> "english". Then, for each fact that matchs this pattern we evaluate
>> the following patterns and if they match, the forall CE will evaluate
>> to true. Another example:
>>
>> rule "all employees have health and dental care programs"
>> when
>> forall( $emp : Employee()
>> HealthCare( employee == $emp )
>> DentalCare( employee == $emp )
>> )
>> then
>> # all employees have health and dental care
>> end
>>
>> Forall can be nested inside other CEs for complete expressiveness.
>> For instance, *forall* can be used inside a *not* CE:
>>
>> rule "not all employees have health and dental care"
>> when not forall( $emp : Employee()
>> HealthCare( employee == $emp )
>> DentalCare( employee == $emp )
>> )
>> then
>> # not all employees have health and dental care
>> end
>>
>> As a side note, forall Conditional Element is equivalent to writing:
>>
>> not( /|<select pattern>|/ and not ( and /|<constraint patterns>|/ )
)
>>
>> Also, it is important to note that *forall is a scope delimiter*, so
>> it can use any previously bound variable, but no variable bound
>> inside it will be available to use outside of it.
>>
>> ------------------------------------------------------------------------
>> Prev <ch03s05.html> Up <ch03.html> Next <ch03s07.html>
>> 3.5. Rule Home <title.html> | ToC <bk01-toc.html> 3.7. Query
>>
>>
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> rules-dev mailing list
>> rules-dev(a)lists.jboss.org
>>
https://lists.jboss.org/mailman/listinfo/rules-dev
>
> _______________________________________________
> rules-dev mailing list
> rules-dev(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/rules-dev
>
_______________________________________________
rules-dev mailing list
rules-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-dev