Verified Commit eada3295 authored by Marcin Moskal's avatar Marcin Moskal
Browse files

Remove variable length implementation

Showing with 1 addition and 339 deletions
+1 -339
package pl.edu.agh.kis.eis.ndl;
import java.util.Iterator;
public class CartesianIterator implements Iterator
{
private final Iterable[] iterables;
private final Iterator[] iterators;
private Object[] values;
private int size;
private boolean empty;
/**
* Constructor
* @param iterables array of Iterables being the source for the Cartesian product.
*/
public CartesianIterator(Iterable[] iterables) {
this.size = iterables.length;
this.iterables = iterables;
this.iterators = new Iterator[size];
// Initialize iterators
for (int i = 0; i < size; i++) {
iterators[i] = iterables[i].iterator();
// If one of the iterators is empty then the whole Cartesian product is empty
if (!iterators[i].hasNext()) {
empty = true;
break;
}
}
// Initialize the tuple of the iteration values except the last one
if (!empty) {
values = new Object[size];
for (int i = 0; i < size-1; i++) setNextValue(i);
}
}
@Override
public boolean hasNext() {
if (empty) return false;
for (int i = 0; i < size; i++)
if (iterators[i].hasNext())
return true;
return false;
}
@Override
public Object[] next() {
// Find first in reverse order iterator the has a next element
int cursor;
for (cursor = size-1; cursor >= 0; cursor--)
if (iterators[cursor].hasNext())
break;
// Initialize iterators next from the current one
for (int i = cursor+1; i < size; i++)
iterators[i] = iterables[i].iterator();
// Get the next value from the current iterator and all the next ones
for (int i = cursor; i < size && i >= 0; i++)
setNextValue(i);
return values.clone();
}
/**
* Gets the next value provided there is one from the iterator at the given index.
* @param index
*/
private void setNextValue(int index) {
Iterator it = iterators[index];
if (it.hasNext())
values[index] = it.next();
}
@Override
public void remove() { throw new UnsupportedOperationException(); }
}
\ No newline at end of file
package pl.edu.agh.kis.eis.ndl.multi
package pl.edu.agh.kis.eis.ndl
import scala.util.{Success, Try}
......
package pl.edu.agh.kis.eis.ndl
import pl.edu.agh.kis.eis.ndl.multi.MonoFact
case class Placeholder[A](s: VarOrAtom[A]*) {
def isBound: Boolean = s.forall({
case v: Variable[A] => v.binding.isDefined
......
package pl.edu.agh.kis.eis.ndl.multi
import pl.edu.agh.kis.eis.ndl.{Placeholder, Variable}
class KnowledgeBase[A](val facts: Seq[MonoFact[A]]) {
def queryFirst(f: (Variable[A] => Seq[Placeholder[A]])): Option[A] = {
val variable = Variable[A](name = Some("x"))
queryDeterministic(f(variable)).headOption.flatMap(_.headOption).flatMap(_.binding)
}
def queryDeterministic(placeholder: Placeholder[A], knownBindings: Seq[Set[Variable[A]]] = Seq.empty):
Seq[Set[Variable[A]]] = {
val variables = placeholder.variables
val candidates = withArity(placeholder.arity).withMatchingConstants(placeholder.constants.toMap)
candidates.facts.map { fact =>
val unified = placeholder.unify(fact)
if(unified.nonEmpty) {
variables.map(x => Variable(x.binding, x.name)) // clones
} else {
Set.empty[Variable[A]]
}
}.filter(_.nonEmpty)
}
def queryDeterministic(placeholders: Seq[Placeholder[A]]): Seq[Set[Variable[A]]] =
placeholders.foldLeft(Seq.empty[Set[Variable[A]]]) { case (bindings, placeholder) =>
queryDeterministic(placeholder, bindings).flatMap(Variable.augmentBindings(bindings, _))
}
def queryNondeterministic(f: (Variable[A] => Seq[Placeholder[A]])): Set[A] = ???
def withArity(arity: Int): KnowledgeBase[A] =
new KnowledgeBase[A](facts.filter(_.arity == arity))
def withMatchingConstants(mappings: Map[Int, A]): KnowledgeBase[A] =
new KnowledgeBase(facts.filter(_.matchesConstants(mappings)))
}
package pl.edu.agh.kis.eis.ndl.multi
import org.scalatest.{FlatSpec, Matchers}
import pl.edu.agh.kis.eis.ndl.{Const, Placeholder, Variable, multi}
class KnowledgeBaseSpec extends FlatSpec with Matchers {
"First-match variable binding" should "be returned in" in {
val facts = Seq(
MonoFact(2),
MonoFact(1),
MonoFact(1, 2),
MonoFact(2, 1)
)
val kb = new KnowledgeBase(facts)
kb.queryFirst { x => Seq(Placeholder(x), Placeholder(Const(1), x)) } should equal(Some(2))
kb.queryFirst { x => Seq(Placeholder(x)) } should equal(Some(2))
kb.queryFirst { x => Seq(Placeholder(x, Const(2))) } should equal(Some(1))
kb.queryFirst { x => Seq(Placeholder(Const(1), x)) } should equal(Some(2))
}
"First-match variable binding on empty knowledge base" should "not be returned" in {
val kb = new KnowledgeBase(Seq.empty[MonoFact[Int]])
kb.queryFirst { x => Seq(Placeholder(x)) } should equal(None)
}
"Non-deterministic query" should "return valid variable binding" ignore {
val kb = new KnowledgeBase(Seq(
MonoFact(1, 1),
MonoFact(3, 3)
))
kb.queryNondeterministic { x: Variable[Int] => Seq(Placeholder(x, x)) } should contain allOf (1, 3)
}
"Facts with specified arity" should "be returned" in {
val knowledgeBase: KnowledgeBase[Int] = new KnowledgeBase(Seq(
MonoFact(0),
MonoFact(1, 20),
MonoFact(1),
MonoFact(20, 1),
MonoFact(0, 0),
MonoFact(1, 0)
))
all (knowledgeBase.withArity(1).facts.map(_.arity)) shouldEqual 1
all (knowledgeBase.withArity(2).facts.map(_.arity)) shouldEqual 2
}
"Single multi-variable deterministic query" should "return valid variable bindings" in {
val x: Variable[Int] = Variable()
val y: Variable[Int] = Variable()
val kb: KnowledgeBase[Int] = new KnowledgeBase(Seq(
MonoFact(2),
MonoFact(1, 1),
MonoFact(2, 2),
MonoFact(1),
MonoFact(2, 1),
MonoFact(1, 2)
))
kb.queryDeterministic(Placeholder(x, x)) should equal(List(
Set(Variable(1)), Set(Variable(2))
))
kb.queryDeterministic(Placeholder(x, y)) should equal(List(
Set(Variable(1), Variable(1)),
Set(Variable(2), Variable(2)),
Set(Variable(2), Variable(1)),
Set(Variable(1), Variable(2))
))
kb.queryDeterministic(Placeholder(x)) should equal(List(
Set(Variable(2)),
Set(Variable(1))
))
}
"Compound, multi-variable deterministic query" should "return valid variable bindings" in {
val x = Variable[Int](name = Some("x"))
val y = Variable[Int](name = Some("y"))
val z = Variable[Int](name = Some("z"))
val kb = new KnowledgeBase[Int](Seq(
MonoFact(1, 2),
MonoFact(1, 3),
MonoFact(2, 1),
MonoFact(1)
))
kb.queryDeterministic(Seq(Placeholder(x), Placeholder(y, z))) should equal(Seq(
Set(Variable("x", 1), Variable("y", 1), Variable("z", 2)),
Set(Variable("x", 1), Variable("y", 1), Variable("z", 3)),
Set(Variable("x", 1), Variable("y", 2), Variable("z", 1))
))
kb.queryDeterministic(Seq(Placeholder(x), Placeholder(x, z))) should equal(Seq(
Set(Variable("x", 1), Variable("z", 2)),
Set(Variable("x", 1), Variable("z", 3))
))
}
}
package pl.edu.agh.kis.eis.ndl.multi
import org.scalatest.{FlatSpec, Matchers}
class MonoFactSpec extends FlatSpec with Matchers {
"Constant variable match" should "success" in {
val fact = MonoFact(1, 2)
fact matchesConstants Map(0 -> 1) should be(true)
fact matchesConstants Map(1 -> 2) should be(true)
fact matchesConstants Map(0 -> 1, 1 -> 2) should be(true)
}
"Constant variable match" should "fail" in {
val fact = MonoFact(5, 7)
fact matchesConstants Map(2 -> 10) should be(false) // index off-by-one
// reversed values
fact matchesConstants Map(0 -> 7) should be(false)
fact matchesConstants Map(1 -> 5) should be(false)
}
}
package pl.edu.agh.kis.eis.ndl.multi
import org.scalatest.{FlatSpec, Matchers}
import pl.edu.agh.kis.eis.ndl._
class PlaceholderSpec extends FlatSpec with Matchers {
def genVariables[A](n: Int): Seq[VarOrAtom[A]] = Seq.tabulate(n)(_ => Variable())
"Placeholder" should "bind single variable" in {
val x = Variable[Int]("x")//Seq(Variable[Int]())
val placeholder = Placeholder(x, x)
placeholder.unify(MonoFact(1, 1)) should contain only 1
}
it should "fail to bind single variable" in {
val placeholder = Placeholder(Variable(), Const(1))
placeholder.unify(MonoFact(20, 2)) should be(empty)
placeholder.unify(MonoFact(20, 1)) should contain only 20
}
it should "bind two distinct variables" in {
val placeholder = Placeholder[Int](Variable(), Variable())
placeholder.unify(MonoFact(8, 60)) should contain inOrderOnly(8, 60)
}
it should "bind variables in term with constants" in {
val placeholder = Placeholder(Const(20), Variable(), Const(2), Variable())
placeholder.unify(MonoFact(20, 8, 2, 60)) should contain inOrderOnly(8, 60)
}
it should "bind non-shared variables in term with fixed constants" in {
val sharedVariable = Variable[Int]()
val placeholder: Placeholder[Int] = Placeholder(Const(1), sharedVariable, sharedVariable, Const(2), Variable())
placeholder.unify(MonoFact(1, 20, 20, 2, 18)) should contain inOrderOnly(20, 18)
placeholder.unify(MonoFact(1, 20, 30, 2, 18)) should be(empty)
}
"Placeholder constants" should "be returned" in {
Placeholder().constants should be(empty)
Placeholder(Variable(), Const(1), Const(2), Variable(), Const(20)).constants should contain inOrderOnly(
(1, 1), (2, 2), (4, 20))
Placeholder(Const(18), Variable(), Variable(), Variable(), Const(1)).constants should contain inOrderOnly(
(0, 18), (4, 1)
)
}
"Placeholder variables" should "be returned" in {
Placeholder(Const(1), Const(1), Variable("x"), Variable("y"), Const(2)).variables should contain only(
Variable("x"),
Variable("y")
)
}
"Provided variables" should "be compatible with Placeholder" in {
Placeholder(Variable("x", 5)).isBindingCompatible(Set(Variable("x", 5))) should equal(true)
}
"Provided variables" should "not be compatible with Placeholder" in {
Placeholder(Variable("x", 5)).isBindingCompatible(Set(Variable("x", 10))) should equal(false)
}
"Unrelated variable" should "be compatible with any Placeholder" in {
Placeholder(Variable("y", 20)).isBindingCompatible(Set(Variable("x", 20))) should equal(true)
Placeholder(Const(1), Const(2)).isBindingCompatible(Set(Variable("x", 40))) should equal(true)
}
}
package pl.edu.agh.kis.eis.ndl.multi
import org.scalatest.{FlatSpec, Matchers}
import pl.edu.agh.kis.eis.ndl.Variable
class VarOrConstSpec extends FlatSpec with Matchers {
val knownBindings: Seq[Set[Variable[Int]]] = Seq(
Set(Variable("x", 1), Variable("y", 2)),
Set(Variable("x", 2), Variable("y", 1))
)
"Adding compatible binding" should "return known input bindings back" in {
Variable.augmentBindings(knownBindings, Set(Variable[Int]("x", 1))) should equal(Seq(knownBindings.head))
Variable.augmentBindings(knownBindings, Set(Variable[Int]("y", 1))) should equal(Seq(knownBindings(1)))
}
"Adding non-existent variable" should "augment existing bindings with new element" in {
Variable.augmentBindings(knownBindings, Set(Variable[Int]("z", 3))) should equal(Seq[Set[Variable[Int]]](
Set(Variable("x", 1), Variable("y", 2), Variable[Int]("z", 3)),
Set(Variable("x", 2), Variable("y", 1), Variable[Int]("z", 3))
))
}
"Adding conflicting binding should" should "discard whole binding" in {
Variable.augmentBindings(knownBindings, Set(Variable[Int]("x", 10))) should be(empty)
Variable.augmentBindings(knownBindings, Set(Variable[Int]("y", 20))) should be(empty)
}
"Bindings" should "be augmented when there are no known bindings" in {
val candidateBindings: Set[Variable[Int]] = Set(Variable("x", 1), Variable("y", 2))
Variable.augmentBindings(Seq.empty, candidateBindings) should equal(Seq(candidateBindings))
}
}
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