Distributing the EYE reasoner for browser and node using WebAssembly.
The simplest way to use this package is to use the n3reasoner
to execute a query over a dataset and get the results. The input data
should include the data and any inference rules that you wish to apply to the dataset; the optional query
should match the pattern of data you wish the engine to return; if left undefined, all new inferred facts will be returned. For example:
import { n3reasoner } from 'eyereasoner';
export const queryString = `
@prefix : <http://example.org/socrates#>.
{:Socrates a ?WHAT} => {:Socrates a ?WHAT}.
`;
export const dataString = `
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix : <http://example.org/socrates#>.
:Socrates a :Human.
:Human rdfs:subClassOf :Mortal.
{?A rdfs:subClassOf ?B. ?S a ?A} => {?S a ?B}.
`;
// The result of the query (as a string)
const resultString = await n3reasoner(dataString, queryString);
// All inferred data
const resultString = await n3reasoner(dataString);
Note: One can also supply an array of dataString
s rather than a single dataString
if one has multiple input data files.
The n3reasoner
accepts both string
s (formatted in Notation3 syntax) and quad
s as input. The output will be of the same type as the input data
. This means that we can use n3reasoner
with RDF/JS quads as follows:
import { Parser } from 'n3';
const parser = new Parser({ format: 'text/n3' });
export const queryQuads = parser.parse(queryString);
export const dataQuads = parser.parse(dataString);
// The result of the query (as an array of quads)
const resultQuads = await n3reasoner(dataQuads, queryQuads);
The n3reasoner
function allows one to optionally pass along a set of options
import { n3reasoner } from 'eyereasoner';
const data = `
@prefix : <urn:example.org:> .
:Alice a :Person .
{ ?S a :Person } => { ?S a :Human } .
`;
const result = await n3reasoner(data, undefined, {
output: 'derivations',
outputType: 'string'
});
The options
parameter can be used to configure the reasoning process. The following options are available:
output
: What to output with implicit queries.derivations
: output only new derived triples, a.k.a--pass-only-new
(default)deductive_closure
: output deductive closure, a.k.a--pass
deductive_closure_plus_rules
: output deductive closure plus rules, a.k.a--pass-all
grounded_deductive_closure_plus_rules
: ground the rules and output deductive closure plus rules, a.k.a--pass-all-ground
none
: provides no-pass-*
arguments to eye, often used when doing RDF Surface reasoning
outputType
: The type of output (if different from the input)string
: output as stringquads
: output as array of RDF/JS Quads
To have more granular control one can also use this module as follows
import { SwiplEye, queryOnce } from 'eyereasoner';
const query = `
@prefix : <http://example.org/socrates#>.
{:Socrates a ?WHAT} => {:Socrates a ?WHAT}.
`
const data = `
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix : <http://example.org/socrates#>.
:Socrates a :Human.
:Human rdfs:subClassOf :Mortal.
{?A rdfs:subClassOf ?B. ?S a ?A} => {?S a ?B}.
`
async function main() {
// Instantiate a new SWIPL module and log any results it produces to the console
const Module = await SwiplEye({ print: (str: string) => { console.log(str) }, arguments: ['-q'] });
// Load the the strings data and query as files data.n3 and query.n3 into the module
Module.FS.writeFile('data.n3', data);
Module.FS.writeFile('query.n3', query);
// Execute main(['--nope', '--quiet', './data.n3', '--query', './query.n3']).
queryOnce(Module, 'main', ['--nope', '--quiet', './data.n3', '--query', './query.n3']);
}
main();
The SWIPL
module exported from this library is a build that inlines WebAssembly and data strings in order to be
isomorphic across browser and node without requiring any bundlers. Some users may wish to have more fine-grained control
over their SWIPL module; for instance in order to load the .wasm
file separately for performance. In these cases
see the SWIPL
modules exported by npm swipl wasm.
An example usage of the node-specific swipl-wasm build is as follows:
import { loadEyeImage, queryOnce } from 'eyereasoner';
import SWIPL from 'swipl-wasm/dist/swipl-node';
async function main() {
const SwiplEye = loadEyeImage(SWIPL);
// Instantiate a new SWIPL module and log any results it produces to the console
const Module = await SwiplEye({ print: (str: string) => { console.log(str) }, arguments: ['-q'] });
// Load the the strings data and query as files data.n3 and query.n3 into the module
Module.FS.writeFile('data.n3', data);
Module.FS.writeFile('query.n3', query);
// Execute main(['--nope', '--quiet', './data.n3', '--query', './query.n3']).
queryOnce(Module, 'main', ['--nope', '--quiet', './data.n3', '--query', './query.n3']);
}
main();
This package also exposes a CLI interface for using the reasoner. It can be used via npx
# Run the command using the latest version of eyereasoner on npm
npx eyereasoner --nope --quiet ./socrates.n3 --query ./socrates-query.n3
or by globally installing eyereasoner
# Gloablly install eyereasoner
npm i -g eyereasoner
# Run a command with eyereasoner
eyereasoner --nope --quiet ./socrates.n3 --query ./socrates-query.n3
For convenience we provide deploy bundled versions of the eyereasoner on github pages which can be directly used in an HTML document as shown in this example which is also deployed on github pages.
There is a bundled version for each release - which can be found at the url:
https://eyereasoner.github.io/eye-js/vMajor/vMinor/vPatch/index.js
for instance v2.3.14 has the url https://eyereasoner.github.io/eye-js/2/3/14/index.js. We also have shortcuts for:
- the latest version https://eyereasoner.github.io/eye-js/latest/index.js,
- the latest of each major version https://eyereasoner.github.io/eye-js/vMajor/latest/index.js, and
- the latest of each minor version https://eyereasoner.github.io/eye-js/vMajor/vMinor/latest/index.js
Available versions can be browsed at https://github.com/eyereasoner/eye-js/tree/pages.
Github also serves these files with a gzip
content encoding which compresses the script to ~1.4MB when being served.
We also distribute bundles that can be dynamically imported on github pages; for example
const { eyereasoner } = await import('https://eyereasoner.github.io/eye-js/2/latest/dynamic-import.js');
// Instantiate a new SWIPL module and log any results it produces to the console
const Module = await eyereasoner.SwiplEye({ print: (str) => { console.log(str) }, arguments: ['-q'] });
// Load the the strings data and query as files data.n3 and query.n3 into the module
Module.FS.writeFile('data.n3', data);
Module.FS.writeFile('query.n3', query);
// Execute main(['--nope', '--quiet', './data.n3', '--query', './query.n3']).
eyereasoner.queryOnce(Module, 'main', ['--nope', '--quiet', './data.n3', '--query', './query.n3']);
We provide some examples of using eyereasoner
:
- Using as an npm package and bundling using webpack (
./examples/rollup
). - Using a prebuilt version of
eyereasoner
(./examples/prebuilt
) - this example is deployed on github pages.
We use benchmark.js to collect the performance results of some basic operations. Those results are published here.
We have experimental support for RDF Lingua using the linguareasoner
; similarly to n3reasoner
it can be used with both string and quad input/output. For instance:
import { linguareasoner } from 'eyereasoner';
const result = await linguareasoner(`
# ------------------
# Socrates Inference
# ------------------
#
# Infer that Socrates is mortal.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
@prefix var: <http://www.w3.org/2000/10/swap/var#>.
@prefix : <http://example.org/socrates#>.
# facts
:Socrates a :Human.
:Human rdfs:subClassOf :Mortal.
# rdfs subclass
_:ng1 log:implies _:ng2.
_:ng1 {
var:A rdfs:subClassOf var:B.
var:S a var:A.
}
_:ng2 {
var:S a var:B.
}
# query
_:ng3 log:query _:ng3.
_:ng3 {
var:S a :Mortal.
}`)
If you are using or extending eye-js as part of a scientific publication, we would appreciate a citation of our zenodo artefact.
©2022–present Jesse Wright, Jos De Roo, MIT License.