Error "rule graph is not stratifiable" in Grakn - reasoning

I'm trying to insert this rule (data is masked):
when {
$d isa person;
$a isa animal;
$r (role-1: $d, role-2: $a) isa relation-1, has attr $ds;
not {$r1 (role-3: $d, role-4: $a) isa relation-2; };
$ds > 0.5;
}, then {
(role-3: $a, role-4: $d, role-5: $ds) isa relation-2;
};
However I keep getting this structural validation error after I do commit. Please help
INVALID_ARGUMENT: InvalidKBException-A structural validation error has occurred. Please correct the [`1`] errors found.
The rule graph is not stratifiable - it contains following cycles with negation: [[[Base Type [RELATION_TYPE] - Id [V65648] - Label [relation-2] ]]]
. Please check server logs for the stack trace.
All uncommitted data is cleared

Rules that cause loops - for example, where the conclusion is negated in the when clause - are not allowed in Grakn.
Here's an example to demonstrate why.
define
person sub entity, plays employee;
employment sub relation, relates employee;
there-are-no-unemployed sub rule,
when {
$p isa person;
not {
(employee: $p) isa employment;
};
}, then {
(employee: $p) isa employment;
}
If we have a person who is not in an employment relation, then they are in an employment relation. But now, we've contradicted the initial premise of the rule - that they were not in an employment relation. Thus, we have a logical contradiction.

Related

How to extract a value of an attribute in Grakn?

I want to use GRAKN to model knowledge about an autonomous car. In one example, I want to derive which velocity I have to propose to the autonomous car. I know the maximum speed of the car, I know the speed limit of the road and if the speed limit on the road is not exceeding the maximum speed of the car, I want to propose the car to drive the allowed speed limit. maximum-speed, speed-limit and proposed-speed are attributes of cars or roads. In my example I want to assign the value of 'speed-limit' as the value of 'proposed-speed'. Is this possible in GRAKN?
The following is what I tried. I know it is incorrect, but I expect the solution to look something like this, but than assigning values instead of the whole attribute.
define
max-speed sub attribute, datatype double;
proposed-speed sub attribute, datatype double;
speed-limit sub attribute, datatype double;
drives-on sub relation,
relates vehicle-role,
relates type-of-road;
vehicle sub entity,
has max-speed,
has proposed-speed,
plays vehicle-role;
car sub vehicle;
road-type sub entity,
has speed-limit,
plays type-of-road;
highway sub road-type;
proposed-speed-by-road-type sub rule,
when {
$x isa vehicle, has max-speed $s;
$y isa road-type, has speed-limit $z;
($x,$y) isa drives-on;
$z <= $s;
}, then {
$x has proposed-speed $z;
};
proposed-speed-by-car-max sub rule,
when {
$x isa vehicle, has max-speed $s;
$y isa road-type, has speed-limit $z;
($x,$y) isa drives-on;
$z > $s;
}, then {
$x has proposed-speed $s;
};
insert
$owncar isa car, has max-speed 190;
$highway isa highway, has speed-limit 130;
(vehicle-role: $owncar, type-of-road: $highway) isa drives-on;`
Now, if I query the following: match $x id V82016, has proposed-speed $z; get;
I get:
grakn.core.server.exception.TransactionException-The type [car] is not allowed to have an attribute of type [speed-limit]. Please check server logs for the stack trace.
I get this, because this is not correct. So what I would like is to extract the value of 'speed-limit' and assign it to proposed-speed. Is this possible?
This is possible. Your example is correct. The only condition at the moment is that the respective attribute data types are the same and the types are allowed to have them. Under the hood a new attribute is created with the value copied. We are planning to expand the use case to cover compatible pairs of data types.
It works as expected on current master branch. In general it should also work with 1.5.7, however 1.5.7 has a problem with computing rule equalities which may lead to incorrect result. The problem should be absent in the 1.5.8 release.
Hope that helps!

Xquery. How to check current incremental backup status?

I have written an Xquery to that gets executed at the time of when incremental backup is in progress. I know the backup status returns three possible values -
completed, in-progress and failed. Not sure the exact value of last one but anyways this is my xquery -
xquery version "1.0-ml";
declare function local:escape-for-regex
( $arg as xs:string? ) as xs:string {
replace($arg,
'(\.|\[|\]|\\|\||\-|\^|\$|\?|\*|\+|\{|\}|\(|\))','\\$1')
} ;
declare function local:substring-before-last
( $arg as xs:string? ,
$delim as xs:string ) as xs:string {
if (matches($arg, local:escape-for-regex($delim)))
then replace($arg,
concat('^(.*)', local:escape-for-regex($delim),'.*'),
'$1')
else ''
} ;
let $server-info := doc("/config/server-info.xml")
let $content-database :="xyzzy"
let $backup-directory:=$server-info/configuration/server-info/backup-directory/text()
let $backup-latest-dateTime := xdmp:filesystem-directory(fn:concat( $backup-directory,'/',$content-database))/dir:entry[1]/dir:filename/text()
let $backup-latest-date := fn:substring-before($backup-latest-dateTime,"-")
let $backup-info := cts:search(/,cts:element-value-query(xs:QName("directory-name"),$backup-latest-date))
let $new-backup := if($backup-info)
then fn:false()
else fn:true()
let $db-bkp-status := if($new-backup)
then (xdmp:database-backup-status(())[./*:forest/*:backup-path[fn:contains(., $backup-latest-dateTime)]][./*:forest/*:incremental-backup eq "false"]/*:status)
else (xdmp:database-backup-status(())[./*:forest/*:backup-path[fn:contains(., $backup-latest-dateTime)]][./*:forest/*:incremental-backup eq "true"][./*:forest/*:incremental-backup-path[fn:contains(., fn:replace(local:substring-before-last(xs:string(fn:current-date()), "-"), "-", ""))]]/*:status)
return $db-bkp-status
We maintain a configuration file that stores backup status. If there is a new full backup day then $backup-info will return nothing. If it is daily incremental backup day then it will return the config. I'm using it just to check if todays backup is new full or incremental. For incremental day $backup-info is false and so it goes to the last line i.e. else condition. this doesn't return anything for incremental backups. Neither completed nor in-progress. I wonder how markLogic picks up the timestamp. Please assist on this.
Feel free to provide your own xquery from scratch. I can update mine.
I even took out the Job id and search in the output of the function xdmp:database-backup-status(()) but that job id too doesn't exist in the result set.
MarkLogic provides the Admin modules to provide much of the information you are attempting to get via other methods. The Admin UI modules (typically found in /opt/MarkLogic/Modules/MarkLogic/Admin/Lib) contains a lot of helpful code that can be adapted to get these sorts of details. In this case I would refer to database-status-form.xqy
define function db-mount-state(
$fstats as node()*,
$fcounts as node()*,
$dbid as xs:unsignedLong)
{
let $times := $fstats/fs:last-state-change,
$ls := max($times),
$since :=
if (not(empty($ls)))
then concat(" since ", longDate($ls), " ", longTimeSecs($ls))
else ""
return concat(database-status($dbid,$fstats,$fcounts),$since)
}
define function backup-recov-state($fstats as node()*)
{
if(empty($fstats/fs:backups/fs:backup)
and
empty($fstats/fs:restore))
then
"No backup or restore in progress"
else
if(empty($fstats/fs:backups/fs:backup))
then
"Restore in progress (see below for details)"
else
"Backup in progress (see below for details)"
}
... Call the functions against your database, then pull the details from the elements you want:
let $last-full-backup := max($fstats/fs:last-backup)
let $last-incremental-backup : = max($fstats/fs:last-incr-backup
return ($last-full-backup, $last-incremental-backup)
This is just some sample code snippets, not executable, but it should get you moving in the right direction.

Idiomatic way to access properties of union type

What is the idiomatic way to access properties of union type that may be missing in one of the types merged in the union?
type DataColumn = {
value: number;
};
type CalculatedColumn = {
calculation: string;
};
type Column = DataColumn | CalculatedColumn;
function getValue(c: Column) {
return c.value || c.calculation;
}
Flow typecheck results in the following error:
13: return c.value || c.calculation;
^ property `calculation`. Property not found in
13: return c.value || c.calculation;
^ object type
#dfkaye pointed out on twitter that if there is an error thrown for the "default" case, it works:
function e() {
throw new Error('foo');
}
function getValue(c: Column) {
return c.value || c.calculation || e();
}
Can somebody explain:
Why it works? Is it intentional, or a side effect?
Why is it necessary? Column type has always either value or calculation, so error case should never happen.
Is there a better, more idiomatic way?
Is this a safe approach, or is it likely to break in future?
PS: Seems like in TypeScript it can be done using type assertions.
The idiomatic way is to use disjoint unions. This passes with no errors:
type DataColumn = {
kind: 'data';
value: number;
};
type CalculatedColumn = {
kind: 'calculated';
calculation: string;
};
type Column = DataColumn | CalculatedColumn;
function e() {
throw new Error('foo');
}
function getValue(c: Column) {
return c.kind === 'data' ? c.value : c.calculation;
}
getValue({kind: 'data', value: 123});
getValue({kind: 'calculated', calculation: 'foo'});
I'm not actually sure why the case you described doesn't work. I can't think of any reason it would be unsound. But disjoint unions definitely work.
Why it works? Is it intentional, or a side effect?
It's most likely a bug, Flow simple ignores all branches but last:
function getValue(c: Column) {
return c.value || c.calculation || undefined;
}
Why is it necessary? Column type has always either value or calculation, so error case should never happen
This is where you are wrong. If value has a type { value: number } it means that it can have any other property of any type, including calculation of type string or may be of some other type.
Is there a better, more idiomatic way?
Yes, see Nat Mote's answer
Is this a safe approach, or is it likely to break in future?
It's not safe in principle, so it's very likely to break in the future
Seems like in TypeScript it can be done using type assertions.
You can do the same thing in Flow, but it's unsafe:
function getValue(c: Column) {
return ((c: any): DataColumn).value || ((c: any): CalculatedColumn).calculation;
}
Also you should not forget that numbers and string can be falsey.

How to use forAll method of Doctrine ArrayCollection?

Can anybody show example of using forAll method of Doctrine\Common\Collections\ArrayCollection?
It's pretty straightforward. The class you linked to implements the forAll method in a following manner:
foreach ($this->_elements as $key => $element) {
if ( ! $p($key, $element)) {
return false;
}
}
So, based on that you should invoke the forAll like:
$collection = ... #some data
$collection->forAll(function($key, $item){
// Your logic here, based on $key and $item
});
Hope this help....
EDIT (the example):
You have an object of entity Student, which has a OneToMany to student's marks.
You want to check if student has passed all the subjects he/she elected
$student = ....
$allPassed = $student->getMarks()->forAll(function($key, $mark){
return $mark->getValue() != 'F';
});
The $allPassed will hold TRUE if all marks were either 'A', 'B', 'C' or 'D'. Even if one of them were F if will be FALSE.
I would like to highlight that forAll method exits as soon as the inner function returns a false.
Following the example of Perovic, take for instance that the $student has 10 marks, where only one is an 'F'.
If the 'F' mark is the 10th element of the array, the function
$mark->getValue()
will be invoked 10 times.
On the other hand, if the 'F' mark is the first element of the array, $mark->getValue() will be invoked only once, since the function immediately returns false, and forAll method stops evaluating.

MarkLogic xquery errors

Both following queries run fine on eXist-db but produce the following errors on MarkLogic server. Any help appreciated.
Query:
for $cust in //Customer[#id=1011]
for $ord in //Order[#Acct = $cust//Accounts//Account/#id/fn:string(.)]
return $ord/OrdQty/#Cash
return max($orderprice)
Error:
[1.0-ml] XDMP-UNEXPECTED: (err:XPST0003) Unexpected token syntax error, unexpected Return_, expecting $end or SemiColon_
Stack Trace
At line 10 column 0:
In xdmp:eval("xquery version "1.0-ml";
declare namespace html = ...", (), 13899855847338100900different-tr...)
8.
9. return $ord/OrdQty/#Cash
10. return max($orderprice)
Query:
for $cust in //Customer
return <Customer>
{$cust/#id}
{$cust/Name}
<Customer_Securities>
{for $account in $cust/Accounts/Account
return <Account BALANCE="{$account/Balance/OnlineActualBal}"
ACCOUNT_ID="{$account/#id}">
<Securities>
{$account/Holdings/Position/Name}
</Securities>
</Account> }
</Customer_Securities>
</Customer>
Error:
[1.0-ml] XDMP-EXPNTREECACHEFULL: for $cust in fn:collection()/descendant::Customer return { $cust/#id }{ $cust/Name }{ for $account in $cust/Accounts/Account return { $account/Holdings/Position/Name } } -- Expanded tree cache full on host gkomninos-pc.studentcom.co.uk
Stack Trace
At line 3 column 0:
In xdmp:eval("xquery version "1.0-ml";
declare namespace html = ...", (), 13899855847338100900different-tr...)
1. xquery version "1.0-ml";
2. declare namespace html = "http://www.w3.org/1999/xhtml";
3. for $cust in //Customer
4.
5. return
For the first error, that may be related to some additional syntax leeway provided by eXist; however, the for shouldn't have two returns (see XQuery spec on FLWORs) (also $orderprice is not defined):
for $cust in //Customer[#id=1011]
for $ord in //Order[#Acct = $cust//Accounts//Account/#id/fn:string(.)
return ($ord/OrdQty/#Cash, max($orderprice))
The second query is throwing an exception because it selects too much data to fit into the expanded tree cache. This will be dependent on the number of customers in your database. Is it possible to select fewer customers (i.e.: maybe this report only needs to select those with overdue balances, etc.)? Alternatively, you can generate your report in batches to avoid filling the cache.

Resources