Counting Existing Facts in the RHS of Clips Rules - artificial-intelligence

How do you test for fact existence in the RHS of rules in Clips? I'm trying to
design a rule that will "score" the current state by counting how many goal facts exist. It's obvious how to test for facts in the LHS, but I can't find how to do the equivalent in the RHS.
I want to do something like this, albeit this isn't valid Clips code:
(defrule score-state ""
?score <- (score (value ?value))
=>
(modify ?score (value (+ (exists (goal-1)) (exists (goal-2)) (exists (goal-3))))))
So that if none of the goal states exist, then there would exist the fact (score (value 0)). Conversely, if all the goal states existed, then there would exist the fact (score (value 3)).
The reference manual mentions the function fact-existp, but this seems to require it's passed a fact address. I tried using it like (fact-existp (goal-1)), but Clips gives me a syntax error.

(deftemplate score
(slot value))
(deftemplate goal-1)
(deftemplate goal-2)
(deftemplate goal-3)
(deffacts start
(score (value undefined))
(goal-1)
(goal-3))
(deffunction ecount (?g)
(if (any-factp ((?f ?g)) TRUE)
then (return 1)
else (return 0)))
(defrule score-state ""
?score <- (score (value undefined))
=>
(modify ?score (value (+ (ecount goal-1) (ecount goal-2) (ecount goal-3)))))

Related

Why is my code returning all records when I am trying to subset inside for loop - R?

for (i in 1:length(data$name)){
if (!is.na(data$years[i]) >= 34 & !is.na(data$gender[i]) == "male" & !is.na(data$classification[i]) == "mid"){
print(data$name)
}
}
There's a few problems in your code. I am assuming this is a class exercise or similar, so I'll add a bit extra detail to illustrate where you've missed a step.
First of all you loop works fine, but your if condition is not completely correct.
!is.na(data$years[i]) >= 34
All of your conditions look (somewhat) like this. The idea is obvious, you want to "check that data$years[i] is not null, and above 34". But in R (and most languages) you have to check these seperately.
!is.na(data$years[i]) && data$years[i] >= 34
Similar for the rest of your conditions.
Next your print statement is printing out everything, because this is what you're asking it to:
print(data$name)
is "ignorant" of anything else you've done up till now. It seems you want to print the specific record, eg:
print(data$name[i])
And this is the way to go about it.
Now R has a thing called "vectorization", so we could wrap this entire loop up in one go:
data$name[!is.na(data$years) & !is.na(data$gender) & !is.na(data$classification) & data$year > 34 & data$gender == "male" & data$classification == "mid"]
But I am assuming that is not part of your current exercise. Note the slight (but important) difference that for vectorized (eg. more than 1) condition I use single & but for single conditions I use 2 &&. The latter is optimized to be "lazy" for single inputs (thus faster).
Perhaps you can try subset + complete.cases like below
subset(
data,
years >= 34 & gender == "male" & classification == "mid" & complete.cases(data[c("years", "gender", "classification")])
)$name

smaller greater comparisions with Solr functions

Comparing dates is of course easy using Solr, but I need to do find a Solr function, where I can do the following:
int value = date2 - date1;
if (value < 0)
do something...
if (value > 0)
do something else...
I know about for example if(exists(myField) ,100, 0), but instead of exists() I want to say if(((date2-date1) < 0), 100, 0).
Is there a way or a function to do this kind of comparison?

PyDatalog: list of values in answer

In PyDatalog I have defined the following assertions:
#stations
assert_fact('station', 'A' ,'yellow')
assert_fact('station', 'B' ,'yellow')
assert_fact('station', 'C' ,'yellow')
assert_fact('station', 'D' ,'yellow')
#sections
assert_fact('stretch', 'A' ,'B')
assert_fact('stretch', 'B' ,'C')
assert_fact('stretch', 'C', 'D')
And I would like to ask the database if there is a way to get to D from A.
The following code should work, because it answers set([()]) if there is a way, and None if there isn't. But it doesn't give me the result of the different evaluations of Z. I would like to know also the route, for example: A B C D
load("""
route(X,Y) <= stretch(X,Y)
route(X,Y) <= stretch(X,Z) & route(Z,Y)
""")
I have tried with unbound values, but it only gives me the result of the first iteration:
load("""
route(X,Y,P) <= stretch(X,Y) & (P==Y)
route(X,Y,P) <= stretch(X,P) & route(P,Y,Z)
""")
I think that the problem is that it only takes P in the first iteration. Or should I use aggregation functions? I don't understand very well how I could use concat...
Thanks in advance.
You need a predicate with a variable that contains the nodes between the 2 end points. You could use the following definition of route():
load("""
route(X,P, Y) <= stretch(X,Y) & (P==[])
route(X,P, Y) <= stretch(X,Z) & route(Z,P1,Y) & ~(Z in P1) & (P==[Z]+P1)
""")
print(pyDatalog.ask("route('A', P, 'D')"))
# prints set([(('B', 'C'),)])
Lists are supported since pyDatalog 0.13.

A PostgreSQL query with 'ANY' is not working

SELECT "Ticket_id" FROM "Tickets"
WHERE "Status" = 1 AND ("Ticket_id" != ANY(array[1,2,3])) Limit 6
And the result is 1,2,3,4,5,6
You want to use ALL, not ANY. From the fine manual:
9.21.3. ANY/SOME (array)
expression operator ANY (array expression)
[...] The left-hand expression is evaluated and compared to each element of the array using the given operator, which must yield a Boolean result. The result of ANY is "true" if any true result is obtained.
So if we say this:
1 != any(array[1,2])
then we'll get true since (1 != 1) or (1 != 2) is true. ANY is essentially an OR operator. For example:
=> select id from (values (1),(2),(3)) as t(id) where id != any(array[1,2]);
id
----
1
2
3
(3 rows)
If we look at ALL, we see:
9.21.4. ALL (array)
expression operator ALL (array expression)
[...] The left-hand expression is evaluated and compared to each element of the array using the given operator, which must yield a Boolean result. The result of ALL is "true" if all comparisons yield true...
so if we say this:
1 != all(array[1,2])
then we'll get false since (1 != 1) and (1 != 2) is false and we see that ALL is essentially an AND operator. For example:
=> select id from (values (1),(2),(3)) as t(id) where id != all(array[1,2]);
id
----
3
(1 row)
If you want to exclude all values in an array, use ALL:
select "Ticket_id"
from "Tickets"
where "Status" = 1
and "Ticket_id" != all(array[1,2,3])
limit 6
Do you mean:
"Ticked_id" NOT IN (1,2,3)

Pattern match in a text column

I have a text column and the data in the text columns are as below:
Rob goes to school,get punished
Rob goes to school
Rob does not goes to school,get punished
When trying to write a query using case statement like
CASE
WHEN (PATINDEX('%Rob goes to school%',value) > 0) OR
(PATINDEX('%Rob is ill%',value) > 0 ) AND
(PATINDEX(%get punished%',value) > 0) THEN
'DONE'
It should select only the 1st statement but instead it is picking both the 1st and 2nd statement with 'DONE'. Any suggestion how to do a pattern match in this case?
I am using SQL Sever 2005/2008
Operator precedence and not enough parenthesis probably
You have x OR y AND z which is actually x OR (y AND z). Do you want want (x OR y) AND z?
The 2nd statement give true OR (false AND false) which gives true
You want (true OR false) AND false to give false
So the SQL should be
CASE WHEN
(
PATINDEX('%Rob goes to school%', value) > 0
OR
PATINDEX('%Rob is ill%', value) > 0
)
AND
(PATINDEX(%get punished%', value) > 0) THEN 'DONE'
...
PATINDEX does not treat your strings as delimited lists (comma-separated values) -- it searches for a match against the entire string.
Rob goes to school,get punished
Rob goes to school
PATINDEX('%Rob goes to school%',value) > 0 evaluates to true for both of them because the wildcard % matches any string of 0 or more characters. Your second and third patterns never get evaluated.
If you want to test which pattern is returning true, try this:
CASE
WHEN (PATINDEX('%Rob goes to school%',value) > 0) THEN 'Pattern 1'
WHEN (PATINDEX('%Rob is ill%',value) > 0 ) THEN 'Pattern 2'
WHEN (PATINDEX('%get punished%',value) > 0) THEN 'Pattern 3'
ELSE 'No Match Found' END
If you want a pattern to match the first value, but not the second, then look for (PATINDEX('%Rob goes to school,%',value) > 0) with the comma instead.
Otherwise -- if you're wanting to treat the strings like comma-separated values, PATINDEX is not your best tool for that. Other options might include converting your strings to tables via table-value function, or what have you.

Resources