Using less than (or equal to) in Drools - operators

I am trying to write a Drools file for a java project I am working on, and one of my rules is heavily reliant on less than or equal to. I have read in a couple of places that you shouldn't use < and should in fact use <. Presumably this means that <= would become <=?
Netbeans highlights my < in red as well, which suggests there's something amiss.
This seems completely mad to me - does this mean the code below changes as follows:
($T1.getValue()<$T2getValue)&&($T1.getOtherValue()<=$T2getOtherValue)
becomes
($T1.getValue()<$T2getValue)&&($T1.getOtherValue()<=$T2getOtherValue)
What is the explanation for this?

In *.drl files you can safely use < and >. It doesn't require XML or HTML escaping.
For example, notice the > in this rule from one of the optaplanner examples:
rule "requiredCpuPowerTotal"
when
$computer : CloudComputer($cpuPower : cpuPower)
$requiredCpuPowerTotal : Number(intValue > $cpuPower) from accumulate(
CloudProcess(
computer == $computer,
$requiredCpuPower : requiredCpuPower),
sum($requiredCpuPower)
)
then
scoreHolder.addHardConstraintMatch(kcontext, $cpuPower - $requiredCpuPowerTotal.intValue());
end
I would write your code something like this:
T1($t1Value : value, $t1OtherValue : otherValue)
T2(value < $t1Value, otherValue <= $t1OtherValue)

Related

The relative clause (which) in GF

"Play Toy Story which was published last year"
Sentence = mkUtt( mkImp (mkVP
(mkV2 "play")
(mkNP (mkCN
(mkCN (mkN "Toy Story"))
(mkS pastTense simultaneousAnt(mkCl (mkVP
(mkV2 "publish")
(mkNP (mkCN (mkN "last yser")))
)))
))
));
When creating a relative clause sentence in GF it always the syntax S for sentence will add that between the two of the sentences is there is any way to replace that with which.
First of all, the structure you made isn't a relative clause, but this structure:
mkCN : CN -> S -> CN -- rule that she sleeps
Relative clause has the type RS in the RGL.
How to construct an actual RS
Here I build the RS gradually. Feel free to put these steps back to a single expression, if you wish so, but I find it clearer to to things like this.
oper
last_year_Adv : Adv = ParadigmsEng.mkAdv "last year" ;
published_last_year_VP : VP = mkVP (passiveVP (mkV2 "publish")) last_year_Adv ;
which_is_published_last_year_RCl : RCl = mkRCl which_RP published_last_year_VP ;
which_was_published_last_year_RS : RS = mkRS pastTense which_is_published_last_year_RCl ;
lin
play_TS = mkUtt (mkImp (mkVP
(mkV2 "play")
(mkNP
(mkNP (mkPN "Toy Story"))
which_was_published_last_year_RS)
)
) ;
Now when we test it on the GF shell, we see that despite the name, which_RP is actually "that".
> l play_TS
play Toy Story , that was published last year
How to change "that" into "which"
The first thing to check when you want to create a new lexical item is Paradigms module. Unfortunately, there is no mkRP for English. Things like relative pronouns are usually thought of as closed class: there's only a small, fixed amount of them. Other examples of closed classes are basic numerals (you can't just make up a new integer between 4 and 5!) and determiners. Contrast this to open classes like nouns, verbs and adjectives, those pop up all the time. For open classes, Paradigms modules have many options. But not for closed classes, like relative pronouns.
So if Paradigms doesn't help, the next thing to check is the language-specific Extra module.
Check language-specific Extra modules
If you have the RGL source on your own computer, you can just go to the directory gf-rgl/src/english and grep for which. Or you can use the RGL browser to search for interesting functions.
And there is indeed a relative pronoun in ExtraEng, also called which_RP. (There is also one called who_which_RP.) So now you can do these modifications in your grammar:
concrete MyGrammarEng of MyGrammar =
open SyntaxEng,
ParadigmsEng,
ExtraEng -- Need to open ExtraEng in the concrete!
in ** {
-- … as usual, except for
oper
which_is_published_last_year_RCl : RCl =
mkRCl ExtraEng.which_RP -- Use the ExtraEng.which_RP!
published_last_year_VP ;
And the rest of the code is like before. This produces the result you want.
> l play_TS
play Toy Story , which was published last year
Last-resort hack
So you have looked in all possible modules and found nothing. Consider making it into an issue in the gf-rgl repository, if it's something that's clearly wrong or missing.
But in any case, here's a general, unsafe hack to quickly construct what you want.
First, let's look at the lincat of RP in CatEng, {s : RCase => Str ; a : RAgr}. Then let's look at its implementation in RelativeEng. There you see also the explanation why it's always "that": unlike who and which, "that" works for animate and inanimate NPs.
So I would do this to force the string "which":
oper
myWhich_RP : RP = which_RP ** {s = table {_ => "which"}} ;
The ** syntax means record extension. We use all other fields from the original which_RP, but in the s field, we put a table whose all branches contain the string "which". (You can read more about this technique in my blog.)
Then we use the newly defined myWhich_RP in forming the relative clause:
oper
which_is_published_last_year_RCl : RCl = mkRCl myWhich_RP published_last_year_VP ;
This works too, but it's unsafe, because whenever the RGL changes, any code that touches the raw implementation may break.

optaplanner custom implementation of ScoreHolder

My main question is, if I can use in OptaPlanner custom implementation of ScoreHolder in drools score calculation? And if yes, how I can do it, as the scoreHolder object is injected implicitly to global variable? Below you can find details, why I would like to use custom implementation of ScoreHolder.
I have found one problem during my work on an application that need to optimize value of some production. I have devices and based on forecasts I calculate production for each device.
I use OptaPlanner and I have rule like following:
when
$device : Device($deviceId : id)
$forecast : Forecast(deviceId == $deviceId)
then
int deviceProduction = $device.calculateProduction($forecast);
scoreHolder.addSoftConstraintMatch(kcontext, deviceProduction);
end
So after this, soft score will contain amount of overall production (overallProduction). What I want to have, is to keep VALUE of overall production in the soft score. The problem is, that value of production is not just overallProduction multiplied by price. There is a limit of production and everything over the limit have negative price. So we have given limit and two prices: positive(positive_price) and negative(negative_price). The schema of value calculation looks like following:
if( overallProduction <= limit)
value = positive_price * overallProduction;
else
value = positive_price * limit + negative_price * (overallProduction - limit);
So I think, I can't include calculation of this value inside rule calculated production for single device, because I'm able to calculate this value of overall production, only after collection of production from all devices.
My only idea how I can handle it, is to have custom implementation of scoreHolder extending HardSoftScoreHolder. This custom ScoreHolder would keep internally, in soft sore, overall production. It will be counted by rule given at the beginning. And then, the proper value will be calculated by custom ScoreHolder, just before returning result from extractScore method.
The question is, if I can use my custom ScoreHolder inside drools score calculation? As global scoreHolder object is injected implicitly..
Or if there is other way how I can put value of overall production into score object?
Thanks for your help and best regards,
Instead of hacking the ScoreHolder, I done it like Geoffrey De Smet suggested, thanks!
rule "SingleProduction"
when
$device : Device($deviceId : id)
$forecast : Forecast(deviceId == $deviceId)
then
int deviceProduction = $device.calculateProduction($forecast);
insertLogical(new SingleProduction(deviceProduction));
end
rule "ValueOfTotalProduction"
when
ProductionLimit( $limit : value )
PositivePrice( $positivePrice : value )
NegativePrice( $negativePrice : value )
Number( $totalProduction : intValue() )
from accumulate( SingleProduction( $value : value ),
sum( $value ) )
then
int productionValue;
if($totalProduction <= $limit)
productionValue = $totalProduction * $positivePrice;
else
productionValue = $limit * $positivePrice +
($totalProduction - $limit) * $negativePrice;
scoreHolder.addSoftConstraintMatch(kcontext, productionValue);
end
Hacking the ScoreHolder is not the way to do this (although by creating a custom ScoreDefinition you can do it that way).
Instead, your rule can use an insertLogical() to insert the intermediate results as a new fact, instead of modifying the ScoreHolder directly. Then another rule matches on that intermediate result (probably with a lower salience) and modifies the ScoreHolder accordingly. See the nurse rostering example for an example.
Laune's way would also work.

Mule ESB: How to do Condition checking in Datamapper using Xpath

i'm facing issue in xpath-I need do a check two attribute values, if the condition satisfies need to do hard code my own value. Below is my xml.
I need to check the condition like inside subroot- if ItemType=Table1 and ItemCondition=Chair1 then i have to give a hard coded value 'Proceed'( this hard coded value i will map to target side of datamapper).
<Root>
<SubRoot>
<ItemType>Table1</ItemType>
<ItemCondition>Chair1</ItemCondition>
<ItemValue>
.......
</ItemValue>
</SubRoot>
<SubRoot>
<ItemType>Table2</ItemType>
<ItemCondition>chair2</ItemCondition>
<ItemValue>
.......
</ItemValue>
</SubRoot>
....Will have multiple subroot
</Root>
I have tried to define rules as below, but it is throwing error
Type: String
Context:/Root
Xpath: substring("Proceed", 1 div boolean(/SubRoot[ItemType="Table1" and ItemCondition="Chair1"]))
But it is throwing error like
net.sf.saxon.trans.XPathException: Arithmetic operator is not defined for arguments of types (xs:integer, xs:boolean)
Is there any other shortcut way to perform this.Could you please help me, i have given lot more effort. Not able to resolve it. Thanks in advance.
I am not sure where you are applying this but the XPath expression you are looking for is:
fn:contains(/Root/SubRoot[2]/ItemCondition, "chair") and fn:contains(/Root/SubRoot[2]/ItemType, "Table")
So here is an example returning "Proceed" or "Stop" as appropriate:
if (fn:contains(/Root/SubRoot[1]/ItemCondition, "Chair") and fn:contains(/Root/SubRoot[2]/ItemType, "Table")) then 'Proceed' else 'Stop'
To implement the above condition , i was initially tired to do in xpath, gave me lot of error. I have implemented by simple if else condition in script part of data mapper
if ( (input.ItemType == 'Table') and (input.ItemCondition == 'chair')) {
output.Item = 'Proceed'}
else {
output.Item = 'Stop '};
Make sure about your precedence. Example, Here in the xml structure( or converted POJO) ItemType has to be checked first then followed with ItemCondition.
&& not seems to be working for me, change to 'and' operator
If you were first time trying to implement the logic. It may help you.

phalcon querybuilder total_items always returns 1

I make a query via createBuilder() and when executing it (getQuery()->execute()->toArray())
I got 10946 elements. I want to paginate it, so I pass it to:
$paginator = new \Phalcon\Paginator\Adapter\QueryBuilder(array(
"builder" => $builder,
"limit" => $limit,
"page" => $current_page
));
$limit is 25 and $current_page is 1, but when doing:
$paginator->getPaginate();
$page->total_items;
returns 1.
Is that a bug or am I missing something?
UPD: it seems like when counting items it uses created sql with limit. There is no difference what limit is, limit divided by items per page always equals 1. I might be mistaken.
UPD2: Colleague helped me to figure this out, the bug was in the query phalcon produces: count() of the group by counts grouped elements. So a workaround looks like:
$dataCount = $builder->getQuery()->execute()->count();
$page->next = $page->current + 1;
$page->before = $page->current - 1 > 0 ? $page->current - 1 : 1;
$page->total_items = $dataCount;
$page->total_pages = ceil($dataCount / 100);
$page->last = $page->total_pages;
I know this isn't much of an answer but this is most likely to be a bug. Great guys at Phalcon took on a massive job that is too big to do it properly in their little free time and things like PHQL, Volt and other big but non-core components do not receive as much attention as we'd like. Also given that most time in the past 6 months was spent on v2 there are nearly 500 bugs about stuff like that and it's counting. I came across considerable issues in ORM, Volt, Validation and Session, which in the end made me stick to other not as cool but more proven solutions. When v2 comes out I'm sure all attention will on the bug list and testing, until then we are mostly on our own. Given that it's all C right now, only a few enthusiast get involved, with v2 this will also change.
If this is the only problem you are hitting, the best approach is to update your query to get the information you need yourself without getPaginate().

How to quick match an entry with the beginning of a long string?

I have a table articles (:Rails Model but I think the issue is more SQL related) which have a column name permalink. To instance, some of my permalinks :
title-of-article
great-article
great-article-about-obama
obama-stuff-about-him
I want to match a request like great-article-about-obama-random-stuff to great-article-about-obama. Is it possible to do it, avoiding killing performance ?
Thanks to all,
ps : We use Rails 3 and Postgresql (or Sqlite not decided yet for production)
EDIT
We can do something like this, but the main downside is we have to fetched every single permalinks from the table articles :
permalinks = ['title-of-article','great-article','great-article-about-obama','obama-stuff-about-him']
string_to_match = 'great-article-about-obama-random-stuf'
result = permalinks.inject('') do |matched,permalink|
matched = (string_to_match.include? permalink and permalink.size > matched.size) ? permalink : matched
end
result => 'great-article-about-obama'
I'll love to find a way to do it directly in SQL for obvious performance reason.
Unless using a text-search base technology (w/ postgres : http://www.postgresql.org/docs/8.3/static/textsearch-dictionaries.html + http://tenderlovemaking.com/2009/10/17/full-text-search-on-heroku/ or solr, indexTank) you can do it with :
request = "chien-qui-aboie"
article = nil
while !article do
article = Article.where("permalink like ?", request+"%").select(:id).first
request.gsub!(/-[^-]*$/) unless article
end
This will first look for chien-qui-aboie%, then chien-qui%, then chien%.
This will also match "chien_qui_mange" if there is an article "chien_qui_mange" but no one about "chien qui aboie"
That's not optimal because of the number of requests, but that's not that heavy if it's just a look up, and not the normal way of accessing a record.