Commit f274a6f8 authored by R.W.Majeed's avatar R.W.Majeed

encounter inference factory added

parent 64f0841a
package de.sekmi.histream.inference;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class DependencyExpandingIterator implements Iterator<String> {
private InferenceFactory factory;
private Iterator<String> concepts;
/** Temporary iterator for dependencies */
private Iterator<String> temp;
private String next;
public DependencyExpandingIterator(InferenceFactory factory, Iterator<String> concepts) {
this.concepts = concepts;
this.factory = factory;
}
@Override
public boolean hasNext() {
prefetch();
return null != next;
}
private void prefetch(){
while( next == null ){
if( temp != null && temp.hasNext() ){
// fetch next dependency
next = temp.next();
}else if( concepts.hasNext() ){
next = concepts.next();
// try whether this concept is inferred
InferredConcept ic = factory.getConceptById(next);
if( ic == null ){
// can not infer this concept, leave as is
}else{
// can infer this concept
// remove the concept id and replace with dependency IDs
next = null;
temp = ic.getDependencyIDs();
// continue, fetch first dependency in next iteration
}
}else{
// no more concepts
break;
}
}
}
@Override
public String next() {
prefetch();
if( next != null ){
throw new NoSuchElementException();
}
return next;
}
}
package de.sekmi.histream.inference;
import de.sekmi.histream.ObservationFactory;
public interface EncounterInferenceFactory {
void setObservationFactory(ObservationFactory factory);
/**
* Determine whether this inference factory can infer
* facts with the given concept id.
*
* @param inferredConceptId inferred concept
* @return true if the concept can be inferred, false otherwise.
*/
boolean canInfer(String inferredConceptId);
public abstract class EncounterInferenceFactory extends InferenceFactory {
/**
* Create an inference engine which infers the given concept id.
......@@ -20,5 +8,5 @@ public interface EncounterInferenceFactory {
* @return inference engine or {@code null} if the concept is not
* supported by this factory.
*/
public EncounterInferenceEngine createEngine(String inferredConceptId);
public abstract EncounterInferenceEngine createEngine(String inferredConceptId);
}
package de.sekmi.histream.inference;
import java.util.Iterator;
import de.sekmi.histream.ObservationFactory;
public abstract class InferenceFactory {
protected ObservationFactory factory;
public void setObservationFactory(ObservationFactory factory){
this.factory = factory;
}
/**
* Determine whether this inference factory can infer
* facts with the given concept id.
*
* @param inferredConceptId inferred concept
* @return true if the concept can be inferred, false otherwise.
*/
public abstract boolean canInfer(String inferredConceptId);
public abstract InferredConcept getConceptById(String inferredConceptId);
/**
* Expand a list of concept IDs with dependencies of corresponding
* inferred concepts.
* <p>
* If a concept can be inferred by this inference factory, it is
* replaced with its dependencies. Other concept IDs are not modified.
* </p>
* <p>
* This is mainly useful for generating a list of concept ids for
* a database query.
* </p>
* @param concepts
* @return iterator of concepts which replaces inferred concepts
* with their corresponding dependencies.
*/
public Iterator<String> expandConceptDependencies(Iterator<String> concepts){
return new DependencyExpandingIterator(this, concepts);
}
}
......@@ -4,6 +4,7 @@ import java.util.Iterator;
public interface InferredConcept {
// TODO need producing of multiple concepts?
public String getConceptId();
public Iterator<String> getDependencyIDs();
......
......@@ -5,50 +5,85 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import de.sekmi.histream.ObservationFactory;
import de.sekmi.histream.inference.EncounterInferenceEngine;
import de.sekmi.histream.inference.EncounterInferenceFactory;
import de.sekmi.histream.inference.InferredConcept;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
public class JSEncounterInferenceFactory implements EncounterInferenceFactory{
public class JSEncounterInferenceFactory extends EncounterInferenceFactory{
private ScriptEngineManager sem;
private ObservationFactory os;
private List<Script> scripts;
private Map<String, InferenceEntry> inferenceLookup;
public JSEncounterInferenceFactory() {
sem = new ScriptEngineManager();
this.scripts = new ArrayList<>();
this.inferenceLookup = new HashMap<>();
}
private static class Script{
URL location;
String charset;
String script;
String[] produces;
String[] requires;
public Script(URL location, String charset){
this.location = location;
this.charset = charset;
public Script(String script){
this.script = script;
}
}
private static class InferenceEntry implements InferredConcept{
private Script script;
private int conceptIndex;
public InferenceEntry(Script script, int conceptIndex){
this.script = script;
this.conceptIndex = conceptIndex;
}
@Override
public Iterator<String> getDependencyIDs() {
return Arrays.stream(script.produces).iterator();
}
@Override
public String getConceptId() {
return script.produces[conceptIndex];
}
}
private String readReader(Reader reader) throws IOException{
StringBuilder builder = new StringBuilder();
CharBuffer buffer = CharBuffer.allocate(2048);
while( reader.read(buffer) != -1 ){
buffer.flip();
builder.append(buffer.toString());
buffer.clear();
}
return builder.toString();
}
public void addScript(URL scriptLocation, String charsetName) throws IOException, ScriptException{
ScriptEngine meta = sem.getEngineByName("nashorn");
// TODO use script context for control of error writer and bindings
Bindings bindings = meta.createBindings();
String source;
try(
InputStream in = scriptLocation.openStream();
Reader reader = new InputStreamReader(in, charsetName)
Reader reader = new InputStreamReader(in, charsetName);
){
meta.eval(reader, bindings);
source = readReader(reader);
meta.eval(source, bindings);
}
Script script = new Script(scriptLocation, charsetName);
Script script = new Script(source);
// retrieve metadata
Object p = bindings.get("produces");
if( p == null ){
......@@ -73,24 +108,33 @@ public class JSEncounterInferenceFactory implements EncounterInferenceFactory{
}else{
throw new ScriptException("Unable to read this.requires of type "+p.getClass(), scriptLocation.toString(), -1);
}
scripts.add(script);
addScript(script);
}
@Override
public void setObservationFactory(ObservationFactory factory) {
this.os = factory;
private void addScript(Script script){
// verify that the produced concept ids are unique to this factory
for( String id : script.produces ){
if( inferenceLookup.containsKey(id) ){
throw new IllegalStateException("Produced concept id '"+id+"' not unique to inference engine");
}
}
for( int i=0; i<script.produces.length; i++ ){
inferenceLookup.put(script.produces[i], new InferenceEntry(script,i));
}
scripts.add(script);
}
private Script getScript(String inferredConceptId){
InferenceEntry e = inferenceLookup.get(inferredConceptId);
if( e == null ){
return null;
}else{
return e.script;
}
}
@Override
public boolean canInfer(String inferredConceptId) {
// TODO use hashmap for more efficient lookups
for( Script s : scripts ){
for( String prod : s.produces ){
if( prod.equals(inferredConceptId) ){
return true;
}
}
}
return false;
return inferenceLookup.containsKey(inferredConceptId);
}
@Override
......@@ -99,4 +143,9 @@ public class JSEncounterInferenceFactory implements EncounterInferenceFactory{
return null;
}
@Override
public InferredConcept getConceptById(String inferredConceptId) {
return inferenceLookup.get(inferredConceptId);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment