Showing posts with label Artificial Intelligence. Show all posts
Showing posts with label Artificial Intelligence. Show all posts

Friday, July 21, 2017

Expression evaluation over time - Was?


A closer look at the Was query to determine if something has been, builds heavily on the previous articles in this series.

Other articles in the AI Knowledge Based Reasoning series on this site:
Knowledge based reasoning in .net c#
Reasoning in Open or Closed models
Logic Expression evaluation with open-world assumption
Expression evaluation on object based models
Expression evaluation over time
Expression evaluation over time - Was?

Definition of Was

So lets start with defining what we mean when we say Was.
Was Mikaela angry?
Is there a previous frame where the logical expression Feeling(Angry) results in true?
There is also a meaning of this to not be the case at some point after it was true.

Lets look at this in a table form to get our bearings straight.
FrameNameOccupationEye-colorHair-color
1MikaelaStudentBlueBrown
2MikaelaPearlescent
3MikaelaPink
4MikaelaJunior Software DeveloperBlue
5MikaelaSoftware DeveloperBlonde
6MikaelaSenior Software DeveloperPearlescent
7MikaelaSoftware ArchitectBrown

At this point was could ask,

WAS Occupation(Student)
Would be true, as there is a frame where Mikaela was a student. and after that something else.

WAS Name(Mikaela)
Would not be true, as she is Mikaela and has never had any other name

WAS Occupation(Software Architect)
Would not be true, as she currently is and there is no previous frame where she was

WAS HairColor(Brown)
Would be true, she still is in the current frame, but there was other hair colors for at least one frame and all the way back there was Brown again.

Unit tests

Lets look at this in unit test form

[TestClass]
public class RelativeWasTest
{
    [TestMethod]
    public void RelativeWasTest_True()
    {
        Context target;
        var obj = CreateTarget(out target);
            
        var expr2 = new ExpressionIs(new KnowledgeRelation { Subject = "Student", Relation = "Occupation of", Target = obj.ToString() });
        var relative = new RelativeWas(expr2);
        var actual = target.Evaluate(relative);
        Assert.AreEqual(EvaluationResult.True, actual);
    }
    [TestMethod]
    public void RelativeWasTest_False()
    {
        Context target;
        var obj = CreateTarget(out target);

        var expr2 = new ExpressionIs(new KnowledgeRelation { Subject = "Lawyer", Relation = "Occupation of", Target = obj.ToString() });
        var relative = new RelativeWas(expr2);
        var actual = target.Evaluate(relative);
        Assert.AreEqual(EvaluationResult.False, actual);
    }
    [TestMethod]
    public void RelativeWasTest_True_PeriodOfWasNot()
    {
        Context target;
        var obj = CreateTarget(out target);

        var expr2 = new ExpressionIs(new KnowledgeRelation { Subject = "Black", Relation = "HairColor of", Target = obj.ToString() });
        var relative = new RelativeWas(expr2);
        var actual = target.Evaluate(relative);
        Assert.AreEqual(EvaluationResult.True, actual);
    }
    [TestMethod]
    public void RelativeWasTest_NotSure()
    {
        Context target;
        var obj = CreateTarget(out target);

        var expr2 = new ExpressionIs(new KnowledgeRelation { Subject = "Student", Relation = "Lunch of", Target = obj.ToString() });
        var relative = new RelativeWas(expr2);
        var actual = target.Evaluate(relative);
        Assert.AreEqual(EvaluationResult.NotSure, actual);
    }

    private static Person CreateTarget(out Context target)
    {
        var obj = new Person("Alice")
        {
            Occupation = "Student",
            HairColor = "Black"
        };
        target = new Context(obj.ToString());
        target.AddFrame(FrameFactory.Create(obj));

        obj.Occupation = string.Empty;
        obj.HairColor = "Pearlescent";
        target.AddFrame(FrameFactory.Create(obj));

        obj.Occupation = string.Empty;
        obj.HairColor = "Pink";
        target.AddFrame(FrameFactory.Create(obj));

        obj.Occupation = "Lawyer";
        obj.HairColor = "Black";
        target.AddFrame(FrameFactory.Create(obj));
        return obj;
    }
}

And just to make things interesting its not the exact example as in this post. Just noticed it now, but anyway. The idea is the same.

How to implement this based on the IRelative interface and Context class from the previous post.

public class RelativeWas : IRelative
{
 private readonly AExpression _expression;

 public RelativeWas(AExpression expression)
 {
  _expression = expression;
 }

 public EvaluationResult Evaluate(Context context)
 {
  var wasNot = false;
  for (int frameIndex = context.Frames.Count - 1; frameIndex >= 0; frameIndex--)
  {
   var result = context.Evaluate(_expression, frameIndex);

   if (result == EvaluationResult.NotSure)
    return EvaluationResult.NotSure;
   if (wasNot)
   {
    if (result == EvaluationResult.True)
     return EvaluationResult.True;
   }
   else
   {
    if (result == EvaluationResult.False)
     wasNot = true;
   }
  }
  return EvaluationResult.False;
 }
}


Thank you for reading! Here comes a video of our cat Prime trying fresh catnip for the first time!
All code provided as-is. This is copied from my own code-base, May need some additional programming to work.

Monday, July 3, 2017

Expression evaluation over time

We have looked at different aspects of knowledge representation during this series and this time its time to look at time itself. How to model logical expressions that incorporate time? I.e. how to store knowledge and query it with time based queries?

Other articles in the AI Knowledge Based Reasoning series on this site:
Knowledge based reasoning in .net c#
Reasoning in Open or Closed models
Logic Expression evaluation with open-world assumption
Expression evaluation on object based models
Expression evaluation over time
Expression evaluation over time - Was?

Introduction

To be able to model logic expressions that incorporate time we first have to ask ourselves, what do we mean by time? Is it abstract ideas like before, after, now and then? Or is it exact number of ticks since we began to measure? Or is it a combination of both?

This part will be quite heavy on ideas rather then code..
Turns out that I provided code for the examples as well. Enjoy : )

Discrete Time

Lets first look at some definitions of discrete time.
Discrete time views values of variables as occurring at distinct, separate "points in time", or equivalently as being unchanged throughout each non-zero region of time ("time period")—that is, time is viewed as a discrete variable -wikipedia
So basically what we say is that even though time is continuous, we will look at it in a discrete way just to simplify our models.

Events

Lets say that we receive knowledge in the form of events, all data recorded in the event will be added to our Context as one frame. For example:
Time Frame Name Occupation Eye-color Hair-color
1 Kate Student Blue Brown
2 Kate Pearlescent
3 Kate Pink
4 Kate Student Blue
5 Kate Intern Blonde
6 Kate
Pearlescent
7 Kate Lawyer Brown
Time frame can be incremental number if we don't care about actual time passed or a time stamp of when the even occurred.
So lets store all our data in this form.

Full frame from incomplete frames

How to query something like the above example?
One idea is to see each event as its own frame of context. I.e. all expressions written in previous posts would now be transferred to refer only to one frame at a time. But that would be kind of incomplete as all events do not record data on all possible parameters. One way to work around this would be to always start from the latest frame and search backwards in the frame-stack until that parameter gets hit. For example in the example above, a full 'latest' frame of information would be the blue highlighted information as seen in the following table:
Time Frame Name Occupation Eye-color Hair-color
4 Kate Student Blue
5 Kate Intern Blonde
6 Kate
Pearlescent
7 Kate Lawyer Brown

Occupation(Lawyer) AND Eye-color(Blue) AND Hair-color(Brown)
Would return True

Occupation(Intern) AND Eye-color(Blue) AND Hair-color(Brown)
Would evaluate to False, as it is not the last full aggregate frame. See Occupation column has newer entries then Intern.

Occupation(Lawyer) AND Eye-color(Blue) AND Drives(Volvo XC90)
Would evaluate to Not Sure as there is no event recording any knowledge about what car Kate drives.

Lets look at some C# code to do just that. Lets convert our Evaluate method in the Context class to the following instead:
public EvaluationResult Evaluate(AExpression expression, int frameStart = -1)
{
    if (frameStart == -1)
        frameStart = _frames.Count - 1;
    var facts = new Dictionary<ExpressionLeaf, EvaluationResult>();
    var leafNodes = expression.GetLeafNodes();
    foreach (var node in leafNodes)
    {
        var leaf = node.Leaf;
        var attr = leaf as KnowledgeAttribute;
        var rel = leaf as KnowledgeRelation;
        if (!(attr != null | rel != null))
            continue;
        for (int i = frameStart; i >= 0; i--)
        {
            var frame = _frames[i];
            var result = attr != null ? frame.Evaluate(attr) : frame.Evaluate(rel);

            if (result == EvaluationResult.NotSure)
                continue;
            facts.Add(node, result);
            break;
        }
    }
    if (!facts.Any())
        return EvaluationResult.NotSure;
    if (facts.Values.Any(x => x == EvaluationResult.NotSure))
        return EvaluationResult.NotSure;
    return expression.TransformEvaluation(facts);
}
And the frame/event store looks something like this (still in the Context class):
private readonly List<KnowledgeStore> _frames;
public IReadOnlyCollection<KnowledgeStore> Frames => new ReadOnlyCollection<KnowledgeStore>(_frames);
public KnowledgeStore CurrentFrame => _frames.Last();
public void AddFrame(KnowledgeStore frame)
{
    _frames.Add(frame);
}

Relative queries

So now we have covered how to determine the current state from this event based knowledge store. Next step is to start determining how knowledge relates to each other based on relative time queries.

For this we will need to add an Evaluate method in the Context class for just relative queries:
public EvaluationResult Evaluate(IRelative expression)
{
    return expression.Evaluate(this);
}

All keyword

Time Frame Name Occupation Eye-color Hair-color
1 Kate Student Blue Brown
2 Kate Pearlescent
3 Kate Pink
4 Kate Student Blue
5 Kate Intern Blonde
6 Kate
Pearlescent
7 Kate Lawyer Brown
This one is pretty simple, it just states that All knowledge frames in the store should evaluate the expression to true.
I.e. ALL Name(Kate) AND Eye-color(Blue)
would be True.
But ALL Occupation(Lawyer) would evaluate to False as there exists frames where this statement is false.
And as before, including a fact from a column that has no recorded data in the query would result in Not Sure.

public class RelativeAll : IRelative
{
    private readonly AExpression _expression;

    public RelativeAll(AExpression expression)
    {
        _expression = expression;
    }

    public EvaluationResult Evaluate(Context context)
    {
        var result = EvaluationResult.NotSure;
        for (int frameIndex = context.Frames.Count - 1; frameIndex >= 0; frameIndex--)
        {
            result = context.Evaluate(_expression, frameIndex);
            if(result == EvaluationResult.False)
                return EvaluationResult.False;
        }
        return result;
    }
}

Some unit tests to see how it behaves:
[TestMethod]
public void RelativeAllTest_AddFrame_CurrentUpdated()
{
    Context target;
    var obj = CreateTarget(out target);

    var expr = new ExpressionIs(new KnowledgeRelation { Subject = "Lawyer", Relation = "Occupation of", Target = obj.ToString() });
    var actual = target.Evaluate(expr);
    Assert.AreEqual(EvaluationResult.True, actual);
}

[TestMethod]
public void RelativeAllTest_All_True()
{
    Context target;
    var obj = CreateTarget(out target);

    var expr = new ExpressionIs(new KnowledgeRelation
    {
        Subject = "Alice",
        Relation = "Name of",
        Target = obj.ToString()
    });
    var rel = new RelativeAll(expr);
    var actual = target.Evaluate(rel);
    Assert.AreEqual(EvaluationResult.True, actual);
}

[TestMethod]
public void RelativeAllTest_All_False()
{
    Context target;
    var obj = CreateTarget(out target);

    var expr = new ExpressionIs(new KnowledgeRelation
    {
        Subject = "Lawyer",
        Relation = "Occupation of",
        Target = obj.ToString()
    });
    var rel = new RelativeAll(expr);
    var actual = target.Evaluate(rel);
    Assert.AreEqual(EvaluationResult.False, actual);
}

[TestMethod]
public void RelativeAllTest_All_NotSure()
{
    Context target;
    var obj = CreateTarget(out target);

    var expr = new ExpressionIs(new KnowledgeRelation
    {
        Subject = "Undercut",
        Relation = "Hair style of",
        Target = obj.ToString()
    });
    var rel = new RelativeAll(expr);
    var actual = target.Evaluate(rel);
    Assert.AreEqual(EvaluationResult.NotSure, actual);
}

private static Person CreateTarget(out Context target)
{
    var obj = new Person("Alice");
    obj.Occupation = "Student";
    target = new Context(obj.ToString());
    target.AddFrame(FrameFactory.Create(obj));
    obj.Occupation = "Lawyer";
    target.AddFrame(FrameFactory.Create(obj));
    return obj;
}

Before keyword

Time Frame Name Occupation Eye-color Hair-color
4 Kate Student Blue
5 Kate Intern Blonde
6 Kate
Pearlescent
7 Kate Lawyer Brown

Syntax: Expression1 Before Expression2
A little harder, trying to determine if Expression1 evaluates true in a full frame before Expression2 evaluates true.
For example:
(Name(Kate) AND Occupation(Intern) AND Hair-color(Blonde)) Before (Name(Kate) AND Occupation(Intern) AND Hair-color(Pearlescent))
Would evaluate to True.

(Name(Kate) AND Occupation(Intern) AND Hair-color(Pearlescent)) Before (Name(Kate) AND Occupation(Intern) AND Hair-color(Blonde))
Would evaluate to False.

And as before, including a fact from a column that has no recorded data in the query would result in Not Sure.

Tricky one is if only one of the expressions evaluate but the other comes back Not Sure, I think for sake of consistency we should evaluate that as Not Sure also.
public class RelativeBefore : IRelative
{
    private readonly AExpression _left;
    private readonly AExpression _right;

    public RelativeBefore(AExpression left, AExpression right)
    {
        _left = left;
        _right = right;
    }

    public EvaluationResult Evaluate(Context context)
    {
        int rightFrameIndex;
        var rightResult = EvaluateExpression(context, _right, out rightFrameIndex);
        int leftFrameIndex;
        var leftResult = EvaluateExpression(context, _left, out leftFrameIndex);

        if (leftResult == EvaluationResult.NotSure || rightResult == EvaluationResult.NotSure)
            return EvaluationResult.NotSure;

        if (leftResult == EvaluationResult.True && rightResult == EvaluationResult.True)
        {
            return leftFrameIndex < rightFrameIndex ? EvaluationResult.True : EvaluationResult.False;
        }
        return EvaluationResult.False;
    }

    private EvaluationResult EvaluateExpression(Context context, AExpression expression, out int frameIndex)
    {
        var result = EvaluationResult.NotSure;
        for (frameIndex = context.Frames.Count - 1; frameIndex >= 0; frameIndex--)
        {
            result = context.Evaluate(expression, frameIndex);
            if (result == EvaluationResult.True)
            {
                return EvaluationResult.True;
            }
        }
        return result;
    }
}

Some tests to clarify things:
[TestMethod]
public void RelativeBeforeTest_True()
{
    Context target;
    var obj = CreateTarget(out target);

    var expr1 = new ExpressionIs(new KnowledgeRelation { Subject = "Student", Relation = "Occupation of", Target = obj.ToString() });
    var expr2 = new ExpressionIs(new KnowledgeRelation { Subject = "Lawyer", Relation = "Occupation of", Target = obj.ToString() });
    var relative = new RelativeBefore(expr1, expr2);
    var actual = target.Evaluate(relative);
    Assert.AreEqual(EvaluationResult.True, actual);
}
[TestMethod]
public void RelativeBeforeTest_False()
{
    Context target;
    var obj = CreateTarget(out target);

    var expr1 = new ExpressionIs(new KnowledgeRelation { Subject = "Student", Relation = "Occupation of", Target = obj.ToString() });
    var expr2 = new ExpressionIs(new KnowledgeRelation { Subject = "Lawyer", Relation = "Occupation of", Target = obj.ToString() });
    var relative = new RelativeBefore(expr2, expr1);
    var actual = target.Evaluate(relative);
    Assert.AreEqual(EvaluationResult.False, actual);
}
[TestMethod]
public void RelativeBeforeTest_LeftNotSure_NotSure()
{
    Context target;
    var obj = CreateTarget(out target);

    var expr1 = new ExpressionIs(new KnowledgeRelation { Subject = "Undercut", Relation = "Hair style of", Target = obj.ToString() });
    var expr2 = new ExpressionIs(new KnowledgeRelation { Subject = "Lawyer", Relation = "Occupation of", Target = obj.ToString() });
    var relative = new RelativeBefore(expr1, expr2);
    var actual = target.Evaluate(relative);
    Assert.AreEqual(EvaluationResult.NotSure, actual);
}
[TestMethod]
public void RelativeBeforeTest_RightNotSure_NotSure()
{
    Context target;
    var obj = CreateTarget(out target);

    var expr1 = new ExpressionIs(new KnowledgeRelation { Subject = "Undercut", Relation = "Hair style of", Target = obj.ToString() });
    var expr2 = new ExpressionIs(new KnowledgeRelation { Subject = "Lawyer", Relation = "Occupation of", Target = obj.ToString() });
    var relative = new RelativeBefore(expr2, expr1);
    var actual = target.Evaluate(relative);
    Assert.AreEqual(EvaluationResult.NotSure, actual);
}
private static Person CreateTarget(out Context target)
{
    var obj = new Person("Alice");
    obj.Occupation = "Student";
    target = new Context(obj.ToString());
    target.AddFrame(FrameFactory.Create(obj));
    obj.Occupation = "Lawyer";
    target.AddFrame(FrameFactory.Create(obj));
    return obj;
}


Conclusions and future work

The method to determine a 'full' frame by aggregating each column backwards gives room for uncertainty as we don't really consider the time between two events that are aggregated together into one frame, if we only have a few records of knowledge and the time between those events is years, then maybe we should be a little bit more uncertain.. a little bit more fuzzy in our determination. Or perhaps return a probability value together with the result. I.e.
True: 0.95
False: 0.1
NotSure: 0.4
And that way be able to build a little more smooth evaluations. But for now this suites my needs.
Another improvement could be to add variance per knowledge column. I.e. if the name is always Kate, then variance should be 0, but for the hair color in the example above it should be way higher as it changes for each event..
Addition of more types of relative expressions could be useful. Exists, Followed by, X years ago etc. But here I think the requirements for each type of project needs to guide the way.

For example source code, head over to my github repository and play around for yourself:


All code provided as-is. This is copied from my own code-base, May need some additional programming to work.

Saturday, May 13, 2017

Expression evaluation on object based models


Let's look at how to mix object based models with logical expression evaluation.

Other articles in the AI Knowledge Based Reasoning series on this site:
Knowledge based reasoning in .net c#
Reasoning in Open or Closed models
Logic Expression evaluation with open-world assumption
Expression evaluation on object based models
Expression evaluation over time
Expression evaluation over time - Was?

Many systems work on an object model of some kind, to be able to integrate logical expression evaluation to an existing system you need some way to translate from that object model to a knowledge model. This is one way to do it, there are probably better ways out there. But this works for me : )

To be able to evaluate logical expressions on an object model, you first have to translate the object model into a Knowledge model. The idea here is to scope the amount of knowledge to a certain object (or objects), lets call that scope a Context, in the case of objects lets call it an ObjectContext.
public class Context
{
 public Guid Id { get; }
 public string Name { get; }
   
 public KnowledgeStore KnowledgeStore { get; }

 public Context(string name)
 {
  Id = Guid.NewGuid();
  Name = name;
  KnowledgeStore = new KnowledgeStore(this);
 }

 public EvaluationResult Evaluate(AExpression expression)
 {
  var facts = new Dictionary<ExpressionLeaf, EvaluationResult>();
  var leafNodes = expression.GetLeafNodes();
  foreach (var node in leafNodes)
  {
   var leaf = node.Leaf;
   if(leaf is KnowledgeNon)
    continue;
   var attr = leaf as KnowledgeAttribute;
   if (attr != null)
   {
    facts.Add(node, KnowledgeStore.Evaluate(attr));
   }
   var rel = leaf as KnowledgeRelation;
   if (rel != null)
   {
    facts.Add(node, KnowledgeStore.Evaluate(rel));
   }
  }
  if (facts.Values.Any(x => x == EvaluationResult.NotSure))
   return EvaluationResult.NotSure;
  return expression.TransformEvaluation(facts);
 }
}
So, the base Context object lets us Evaluate an Expression, as we assume an open world we also allow for the response NotSure.

And for the ObjectContext, we will use reflection to create the Knowledge from the objects that we throw at it.In my case, my model inherits from a BaseObject class, but it could be any object.
public class ObjectContext : Context
{
 public BaseObject Root { get; set; }
 public ObjectContext(BaseObject root) : base(root.ToString())
 {
  Root = root;
  KnowledgeStore.AddAttribute(new KnowledgeAttribute
  {
   Attribute = root.GetType().Name,
   Subject = Name
  }, Name);
  var fields = GetAllProperties(root);
  foreach (var field in fields)
  {
   KnowledgeStore.AddRelation(new KnowledgeRelation
   {
    Subject = field.Value,
    Relation = $"{field.Key}Of",
    Target = Name
   }, Name);
  }
 }

 private Dictionary<string, string> GetAllProperties(object obj)
 {
  var d = new Dictionary<string, string>();
  var properties = obj.GetType().GetProperties();
  foreach (var prop in properties)
  {
   var val = prop.GetValue(obj);
   if (val == null)
    val = string.Empty;
   d.Add(prop.Name, val.ToString());
  }
  return d;
 }
}

So basically we will take a snapshot of the model and allow for expression evaluation on that snapshot. If the underlying model changes, the context object would need to be recreated.
As you can see we add a suffix to each attribute name, so if the object has a field called Name, the knowledge attribute would be NameOf.

Lets look at some unit tests to see how this works.
[TestClass]
public class ObjectContextTest
{
 [TestMethod]
 public void ContextTest_Evaluate_Not_False()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionNot(new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() });
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.False, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_Not_True()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionNot(new KnowledgeRelation { Relation = "NameOf", Subject = "T", Target = obj.ToString() });
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.True, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_And_BothTrue()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionAnd(
   new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() },
   new KnowledgeRelation { Relation = "NameOf", Subject = "Charlize", Target = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.True, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_And_RightFalse()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionAnd(
   new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() },
   new KnowledgeRelation { Relation = "NameOf", Subject = "T", Target = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.False, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_And_LeftFalse()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionAnd(
   new KnowledgeRelation { Relation = "NameOf", Subject = "T", Target = obj.ToString() },
   new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.False, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_And_BothFalse()
 {
  var obj = new Person("Charlize") { Gender = Person.GenderType.Female };
  var target = new ObjectContext(obj);
  var expr = new ExpressionAnd(
   new KnowledgeRelation { Relation = "NameOf", Subject = "T", Target = obj.ToString() },
   new KnowledgeRelation { Relation = "GenderOf", Subject = "male", Target = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.False, actual);
 }
 [TestMethod]
 public void ContextTest_Evaluate_Or_BothTrue()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionOr(
   new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() },
   new KnowledgeRelation { Relation = "NameOf", Subject = "Kate", Target = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.True, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_Or_RightFalse()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionOr(
   new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() },
   new KnowledgeRelation { Relation = "NameOf", Subject = "Kate", Target = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.True, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_Or_LeftFalse()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionOr(
   new KnowledgeRelation { Relation = "NameOf", Subject = "Kate", Target = obj.ToString() },
   new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.True, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_Or_BothFalse()
 {
  var obj = new Person("Charlize") { Gender = Person.GenderType.Female };
  var target = new ObjectContext(obj);
  var expr = new ExpressionOr(
   new KnowledgeRelation { Relation = "NameOf", Subject = "Kate", Target = obj.ToString() },
   new KnowledgeRelation { Relation = "GenderOf", Subject = "Male", Target = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.False, actual);
 }


 [TestMethod]
 public void ContextTest_Evaluate_Xor_BothTrue()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionXor(
   new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() },
   new KnowledgeRelation { Relation = "NameOf", Subject = "Charlize", Target = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.False, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_Xor_RightFalse()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionXor(
   new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() },
   new KnowledgeRelation { Relation = "NameOf", Subject = "Kate", Target = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.True, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_Xor_LeftFalse()
 {
  var obj = new Person("Charlize");
  var target = new ObjectContext(obj);
  var expr = new ExpressionXor(
   new KnowledgeRelation { Relation = "NameOf", Subject = "Kate", Target = obj.ToString() },
   new KnowledgeAttribute { Attribute = "Person", Subject = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.True, actual);
 }

 [TestMethod]
 public void ContextTest_Evaluate_Xor_BothFalse()
 {
  var obj = new Person("Charlize") { Gender = Person.GenderType.Female };
  var target = new ObjectContext(obj);
  var expr = new ExpressionXor(
   new KnowledgeRelation { Relation = "NameOf", Subject = "T", Target = obj.ToString() },
   new KnowledgeRelation { Relation = "GenderOf", Subject = "female", Target = obj.ToString() }
   );
  var actual = target.Evaluate(expr);
  Assert.AreEqual(EvaluationResult.False, actual);
 }
}

So, just some thoughts on how to do this. This is far from completed and is still a work in progress used by one of my home projects. Any comments are appreciated.
If you wonder why this is not on my github repository, I feel that it doesn't really have that kind of quality yet. But with time it will get there.

All code provided as-is. This is copied from my own code-base, May need some additional programming to work.



Friday, December 30, 2016

Dealing with events in the real world ...


Working on my AI project I've come to the point where I need to be able to deal with events from the real world. Say a signal from a motion detector, cat door opened or someone popping the Champagne on New Years Eve, or Cider if you are not into Champagne... I don't judge :)

So lets first define what we mean by a World Event.
  • it can be described
  • it happened Somewhere
  • it happened at a specific Time

public class WorldEvent
{
    public Guid Id { get; set; }
    public string Description { get; set; }
    public DateTime When { get; set; }
    public AveCoordinate Where { get; set; }

    public WorldEvent()
    {
        Id = Guid.NewGuid();
        Description = string.Empty;
    }

    public override string ToString()
    {
        return $"WorldEvent[{When:O}, lng:{Where.Longitude:##.000},lat:{Where.Latitude:##.000}]";
    }
}

If you wonder about the AveCoordinate used above, it is defined as follows:
public class AveCoordinate
{
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public double Altitude { get; set; }
    public AveCoordinate()
    {
        // for deserialization
    }
    public AveCoordinate(double lat, double lng)
    {
        Latitude = lat;
        Longitude = lng;
    }
    public AveCoordinate(double lat, double lng, double altitude)
    {
        Latitude = lat;
        Longitude = lng;
        Altitude = altitude;
    }

    public double GetDistanceTo(AveCoordinate coordinates)
    {
        return GetDistanceTo(coordinates.ToGeoCoordinate());
    }
    public double GetDistanceTo(GeoCoordinate coordinates)
    {
        return ToGeoCoordinate().GetDistanceTo(coordinates);
    }

    public GeoCoordinate ToGeoCoordinate()
    {
        return new GeoCoordinate(Latitude, Longitude, Altitude);
    }
}

You might wonder why I chose to not use the GeoCoordinate class directly, but it kind of didn't like to be serialized with fastJSON that is my go to utility for serializing/deserializing stuff. So I had to create my own coordinate class, but as you can see the calculations are done with help of the GeoCoordinate class.
At the moment the GeoCoordinate GetDistanceTo method does not take the Altitude into account so I might have to write my own at some point. But for now it does the trick.

Ok, so now we have a base class that can be used to describe things that happen in the real world.
So what now?

Event Relations

I would like to know if events could be related to each other in some way.
In the real world we work with 4 dimensions, space being the first 3 and time being the last.
So how do we figure out how related 2 events are?

Naive formulation
  • They happened at the same place or close by
  • They happened at the same time or close to
Lets add a naive Distance calculation to the WorldEvent class

public double Distance(WorldEvent other)
{
    var metres = Where.GetDistanceTo(other.Where) + 1d;
    var seconds = (When - other.When).TotalSeconds + 1d;
    var distance = Math.Sqrt(Math.Pow(metres, 2d)*Math.Pow(seconds, 2d));
    return distance;
}

Does this work?

I really try to avoid the advanced stuff with clustering algorithms etc. until I really can't solve the problem in any other way. So lets put down some tests to see if this actually works for our purposes.

[TestMethod]
public void WorldEventTest_IrrelevantDirection()
{
    var first = new WorldEvent
    {
        When = new DateTime(2016, 03, 22, 07, 0, 0),
        Where = new AveCoordinate(58.58073, 14.00119)
    };
    var second = new WorldEvent
    {
        When = new DateTime(2016, 03, 22, 07, 0, 0),
        Where = new AveCoordinate(58.58073, 14.00119)
    };
    var actualFirst = first.Distance(second);
    var actualSecond = second.Distance(first);
    Assert.AreEqual(actualFirst, actualSecond);
}
The first test just makes sure that we didn't screw things up. The distance calculation should be the same in both directions.

[TestMethod]
public void WorldEventTest_SameLocation_YearsBetweenVsMinutesBetween()
{
    var first = new WorldEvent
    {
        When = new DateTime(1934, 03, 22, 07, 0, 0),
        Where = new AveCoordinate(58.58073, 14.00119)
    };
    var second = new WorldEvent
    {
        When = new DateTime(2016, 03, 22, 07, 0, 0),
        Where = new AveCoordinate(58.58073, 14.00119)
    };
    var third = new WorldEvent
    {
        When = new DateTime(2016, 03, 22, 07, 3, 0),
        Where = new AveCoordinate(58.58073, 14.00119)
    };
    var actualFirst = first.Distance(second);
    var actualSecond = second.Distance(third);
    Assert.IsTrue(actualFirst > actualSecond);
}
Here we ensure that things that happen close-by in time at the same place will get a lesser distance then the events that happen a very long time apart.

[TestMethod]
public void WorldEventTest_SameTime_FarAwayVersusClose()
{
    // Stelvio 46.623215,10.7990846
    var first = new WorldEvent
    {
        When = new DateTime(2016, 03, 22, 07, 0, 0),
        Where = new AveCoordinate(46.623215, 10.7990846)
    };
    var second = new WorldEvent
    {
        When = new DateTime(2016, 03, 22, 07, 0, 0),
        Where = new AveCoordinate(58.58073, 14.00119)
    };
    var third = new WorldEvent
    {
        When = new DateTime(2016, 03, 22, 07, 0, 0),
        Where = new AveCoordinate(58.559686, 13.959535)
    };
    var actualFirst = first.Distance(second);
    var actualSecond = second.Distance(third);
    Assert.IsTrue(actualFirst > actualSecond);
}
And here the other way around. Events that happen at the same time, but on different parts of the globe should have a longer distance then events that happen in the same area.

Conclusion

Ok, so not the most advanced stuff but it does the trick for my project at the moment. We can always add more advanced calculations at a later stage, maybe just keep this as a preprocessing stage to filter out really non related stuff.
So far just keeping it simple. :)

All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Hope this helps someone out there :)



Thursday, November 24, 2016

Basic word prediction in c#


In this little post I will go through a small and very basic prediction engine written in C# for one of my projects.
Basically what it does is the following:
  • It will collect data in the form of lists of strings
  • Given an input, it will give back a list of predictions of the next item. In falling probability order.
So no rocket science, but a good and basic prediction engine that can be build upon depending on what scenarios you want to solve.


First, some unit tests:


[TestMethod]
public void PredictorTest_NoMatch()
{
    var target = new Predictor();
    var actual = target.Predict("The rabbit-hole went straight on like a tunnel for some way");
    Assert.AreEqual(0, actual.Count);
}
[TestMethod]
public void PredictorTest_SingleMatch()
{
    var target = new Predictor();
    target.Predict("Alice opened the door and found that it led into a small passage");
    var actual = target.Predict("Alice opened the door");
    Assert.AreEqual(1, actual.Count);
    Assert.AreEqual("and", actual.First());
}
[TestMethod]
public void PredictorTest_SingleMatch_OtherNoise()
{
    var target = new Predictor();
    target.Predict("Alice opened the door and found that it led into a small passage");
    target.Predict("Alice took up the fan and gloves");
    var actual = target.Predict("Alice opened the door");
    Assert.AreEqual(1, actual.Count);
    Assert.AreEqual("and", actual.First());
}
[TestMethod]
public void PredictorTest_SingleMatch_TwoResultsInOrder()
{
    var target = new Predictor();
    target.Predict("Alice thought she might as well wait");
    target.Predict("Alice thought this a very curious thing");
    target.Predict("Alice thought she had never seen such a curious");
    var actual = target.Predict("Alice thought");
    Assert.AreEqual(2, actual.Count);
    Assert.AreEqual("she", actual.First());
    Assert.AreEqual("this", actual.Last());
}

So nothing too fancy. You provide it with input and as expected it returns a list of possible next values. Examples are from Alice's Adventures in Wonderland by Lewis Carroll, the Project Gutenberg edition.


Predictor class

public class Predictor
{
    private readonly Dictionary<string, Dictionary<string, int>> _items = new Dictionary<string, Dictionary<string, int>>();
    private readonly char[] _tokenDelimeter = {' '};
    public List<string> Predict(string input)
    {
        var tokens = input.Split(_tokenDelimeter, StringSplitOptions.RemoveEmptyEntries);
        var previousBuilder = new StringBuilder();
        Dictionary<string, int> nextFullList;
        foreach (var token in tokens)
        {
            nextFullList = GetOrCreate(_items, previousBuilder.ToString());
            if (nextFullList.ContainsKey(token))
                nextFullList[token] += 1;
            else
                nextFullList.Add(token, 1);

            if (previousBuilder.Length > 0)
                previousBuilder.Append(" ");
            previousBuilder.Append(token);
        }
        nextFullList = GetOrCreate(_items, previousBuilder.ToString());
        var prediction = (from x in nextFullList
            orderby x.Value descending
            select x.Key).ToList();

        return prediction;
    }
    private static T GetOrCreate<T>(Dictionary<string, T> d, string key)
    {
        if (d.ContainsKey(key))
        {
            return d[key];
        }
        var t = Activator.CreateInstance<T>();
        d.Add(key, t);
        return t;
    }
}

It's not smart, and it requires having seen quite a lot of samples to work well.
An additional improvement could be to add storage of previous/next token combinations so that if the full search doesn't yield any result, a guess could be made based on only the previous word. But I guess that is up to you.

All code provided as-is. This is copied from my own code-base, May need some additional programming to work.



Wednesday, November 23, 2016

Defining Intelligence

Lately I've been thinking a lot about intelligence, knowledge, thinking and how to define the goal of my Artificial Intelligence project. What is it that I want to achieve?
This post is basically a lot of in progress thoughts and references to popular culture.

So where to begin?

The inner voice(s)

Early humans may have thought that the voice in their head was the voice of God, but when did we become aware of a self?
Is one voice enough? Or should one strive to include at least two? Maybe with different approaches in a dialog with itself?
Maybe a loop of self triggered input that iterates core values and thus would form the system over time. Even if a lot of input is given from various sources, the repeating of core values would make those beliefs strong in different parts of the system. Like a backstory. Guess more ideas on this will come with more episodes of Westworld.

Neural networks, the brain


I have a rudimentary knowledge of how the human brain works at its lowest level, mainly by building huge networks of interconnected cells, neurons, that can propagate triggers in between them. When a neuron it triggered, it will in turn trigger its output that can be connected to multiple other neurons. A single neuron can in turn receive triggers from multiple neurons. This gets kind of out of hand quite fast.
There are a lot of research into modelling artificial neural networks, and honestly my own work with neural networks have been to solve very specific tasks. Maybe the system should be able to train its own networks to solve different kind of tasks? Maybe put it in the backlog for future pondering. To start with I think this is a too low level to look at intelligence.


Active Symbols


Something I picked up from the book 'Gödel, Escher, Bach: An Eternal Golden Braid' by Douglas R. Hofstadter. The idea to look at the brain on a higher level than the neural. A symbol could be anything, for example a word or a concept. Each symbol it is built by neurons activating in certain patterns. Neurons could be re-used between different symbols and symbols could activate other symbols in a network in itself.
Does the artificial intelligence need the neural layer? Or could we build just symbols and just activate them in different ways?
Need to be able to merge multiple symbols into new ones.
In the end this could give some sort of associative power to the entity, by activating symbols based on input and seeing what other symbols also activate from past knowledge.

Feeling of joy


When do humans feel joy? When we discover new things, when things go according to plan.

Should my project 'feel'?
The following dialog between two characters, played by Dustin Hoffman and Samuel L. Jackson, is from the movie Sphere.
Norman:
I would be happy if Jerry had no emotions whatsoever. Because the thing of it is once you go down that road... here's Jerry, an emotional being cooped up for 300 years with no one to talk to... none of the socialization, the emotional growth that comes from contact with other emotional beings...
Harry:
So...?
Norman:
What happens if Jerry gets mad?
To the point, is it OK to build something that can feel? Could it be a bad thing? But if you build something intelligent that can't feel, are you creating a sociopath?
What about boredom? Doing routine tasks makes me bored, that feeling makes me look at problems in other ways, maybe automate them. Should the agent try to minimize boredom and maximize joy? Or is there different kinds of joy. A too greedy algorithm would maybe not be able to do long term planning, go through times of focus to achieve something great.
Should the fitness function be floating, like it is for me. Sometimes I feel happy just watching TV, other times only a 10 K gets me there. Maybe a healthy balance is what we should strive for here as well.

Breathing

At least for me, a lot of my thinking is based around the basic need to breath. An artificial entity would not have that need, but maybe there should be some kind if core layer pulse that keeps things going. Something that triggers and activates itself, maybe the inner voice should be linked to this.
Is attention span linked to breathing as well? How many breaths can you keep a thought in active play before something else pops up instead?

Compartmentalizing

Working with a lot of information and knowledge will lead to conflicting ideas. Some sort of way to compartmentalize, separate and isolate, should be a good thing to have.

Prediction

The ability to predict future events based on past experiences. A simple way would be to just store sequences of words and increase counters when seen. And when a sequence is seen, different optional predictions would trigger what could be acted on. Maybe one part global and another part connected to a place or person. Being able to predict how someone could react seems core when trying to decide what to do next. This would require some sort of linking of past knowledge to a source.

Lastly

Should we strive to create something artificial with all the restrictions that humans have or should we strive for something without restrictions other than the computer hardware in itself. Maybe a lot of the self that we know comes from the constant struggle with the faulty hardware that we are running on. Or is the movie Transcendence with Johnny Depp and Rebecca Hall into something, the idea of unlimited resources.

This was a lot longer than I thought it would be. In the end a lot of questions and few answers but I guess that was expected. I hope this sparked some ideas, thoughts or feelings. :)

Sunday, November 6, 2016

Logic Expression evaluation with open-world assumption


Now it is time to look at how to evaluate expressions against that stored knowledge.

Knowledge based reasoning in .net c#
Reasoning in Open or Closed models
Logic Expression evaluation with open-world assumption
Expression evaluation on object based models
Expression evaluation over time
Expression evaluation over time - Was?

Logic operators


Logical AND

The AND operator evaluates true, if both the right and the left side expression evaluate as true.
Leading to the following truth table:
AND
TRUE FALSE
TRUE TRUE FALSE
FALSE FALSE FALSE

In code:
public override EvaluationResult TransformEvaluation(Dictionary<ExpressionLeaf, EvaluationResult> facts)
{
 var leftResult = Left.TransformEvaluation(facts);
 if (leftResult != EvaluationResult.True)
  return EvaluationResult.False;

 var rightResult = Right.TransformEvaluation(facts);
 if(rightResult != EvaluationResult.True)
  return EvaluationResult.False;

 return EvaluationResult.True;
}

Logical OR

The OR operator evaluates true, if any of the left or right side expressions evaluate as true.
This gives the following truth table:
OR
TRUE FALSE
TRUE TRUE TRUE
FALSE TRUE FALSE

In code:
public override EvaluationResult TransformEvaluation(Dictionary<ExpressionLeaf, EvaluationResult> facts)
{
 var leftResult = Left.TransformEvaluation(facts);
 if (leftResult == EvaluationResult.True)
  return EvaluationResult.True;

 var rightResult = Right.TransformEvaluation(facts);
 if (rightResult == EvaluationResult.True)
  return EvaluationResult.True;

 return EvaluationResult.False;
}

Logical XOR

The XOR, i.e. the exclusive OR operator evaluates true, if either the left or the right hand side is true. But false if both are equal.
Truth table:
XOR
TRUE FALSE
TRUE FALSE TRUE
FALSE TRUE FALSE

In code:
public override EvaluationResult TransformEvaluation(Dictionary<ExpressionLeaf, EvaluationResult> facts)
{
 var leftResult = Left.TransformEvaluation(facts);
 var rightResult = Right.TransformEvaluation(facts);

 if ((leftResult == EvaluationResult.True && rightResult == EvaluationResult.False)
  || (leftResult == EvaluationResult.False && rightResult == EvaluationResult.True))
  return EvaluationResult.True;
 
 return EvaluationResult.False;
}

Logical NOT

The NOT operator only has a right side value and evaluates true if it is false.
Truth table
NOT
TRUE FALSE
- FALSE TRUE
- - -

In code:
public override EvaluationResult TransformEvaluation(Dictionary<ExpressionLeaf, EvaluationResult> facts)
{
 var result = Right.TransformEvaluation(facts);
 switch (result)
 {
  case EvaluationResult.False:
   return EvaluationResult.True;
  case EvaluationResult.True:
   return EvaluationResult.False;
  case EvaluationResult.NotSure:
   return EvaluationResult.NotSure;
  default:
   throw new ArgumentOutOfRangeException();
 }
}


Expression evaluation

Now that we have the basic logical operators to use to form our expressions. Lets look at how to evaluate:

In my code base I have a number of expression types, that include AND, OR, XOR, NOT and LEAF.
The leaf is a special case that contains one single KnowledgeItem and can be evaluated against the expression.
The leaf node evaluation is as follows:

public override EvaluationResult TransformEvaluation(Dictionary<ExpressionLeaf, EvaluationResult> facts)
{
 return facts[this];
}

So. The expression tree contains AND, OR, XOR and NOT operations but only the leaf nodes contains actual information that can be evaluated.
Also, you may have noted that the most of these operators above just Transform an result, and they only take into account True and False values, whereas in the open-world assumption we should also have the Unknown/NotSure value.
In my implementation I decided to evaluate each and every Leaf node at the start of the evaluation method. If any NotSure values were found, the result was not transformed. Meaning the logical operators were not hit. The evaluation method just returned NotSure directly.

public EvaluationResult Evaluate(AExpression expression)
{
 var facts = new Dictionary<ExpressionLeaf, EvaluationResult>();
 var leafNodes = expression.GetLeafNodes();
 foreach (var node in leafNodes)
 {
  var attr = node.Leaf as KnowledgeAttribute;
  if (attr != null)
  {
   facts.Add(node, KnowledgeStore.Evaluate(attr));
  }
  var rel = leaf as KnowledgeRelation;
  if (rel != null)
  {
   facts.Add(node, KnowledgeStore.Evaluate(rel));
  }
 }
 if (facts.Values.Any(x => x == EvaluationResult.NotSure))
  return EvaluationResult.NotSure;
 return expression.TransformEvaluation(facts);
}


All code provided as-is. This is copied from my own code-base, May need some additional programming to work.
Good luck :)

Saturday, October 8, 2016

Reasoning in Open or Closed models


I've been thinking a lot on how to model knowledge and how to let a system work with it in a programmatic way.


Other articles in the AI Knowledge Based Reasoning series on this site:
Knowledge based reasoning in .net c#
Reasoning in Open or Closed models
Logic Expression evaluation with open-world assumption
Expression evaluation on object based models
Expression evaluation over time
Expression evaluation over time - Was?

Closed-world model

This is where I am at the moment in my thinking and in the coding of my current project. Mostly because it is quite stand forward to implement in code.

public bool Evaluate(expression);

In the closed-world model, everything that you do not find an answer for in your model is assumed to be false.
At first, this seems like a OK thing to do. Assuming that your model covers everything. For example in games, where the AI-engine has access to all information this is the way to go. But in an situation where the model does not cover everything I find it lacking. My current project tries to interface with the real world and when its reasoning returns False on everything that it does not know the end results are quite off the board.

Open-world assumption

So instead of just the boolean result of true or false. In the open-world assumption we introduce a third option, the NotSure result of an evaluation.
public EvaluationResult Evaluate(expression);
public enum EvaluationResult
{
 True,
 False,
 NotSure
}
So far quite easy, just convert your Evaluation method to return NotSure when its not sure.
But the question is, what to do when the system is not sure about something?
Options are:

  • Nothing, just wait until it is sure. Could be OK for systems that receive a lot of information. Just assume that the information missing will arrive at a later date.
  • Formulate a question regarding the missing piece of information. Break the evaluated expression into pieces and find out what was missing and ask a user or two to provide that input.
  • Figure out how much of an expression is unsure. Is it OK to still act on a result with 75% knowledge and 25% gaps? Maybe the AI should figure out the accepted level of certainty by trial and error. 

Conclusions

As I wrote in the beginning. I'm not sure how to implement this kind of reasoning myself. First step in converting the closed-world system that I have now to an open world one is to go by the Nothing approach. Basically just returning NotSure and then not acting on it for starters. Could not be worse than assuming a false falsehood that the system does now.

Sources

https://en.wikipedia.org/wiki/Closed-world_assumption
https://en.wikipedia.org/wiki/Open-world_assumption

Thursday, September 15, 2016

Knowledge based reasoning in .net c#


I've lately been working on a side project in AI. One of the key parts of it is to figure out how to include a knowledge base and let the program reason about things itself. So how to model knowledge?


Other articles in the AI Knowledge Based Reasoning series on this site:
Knowledge based reasoning in .net c#
Reasoning in Open or Closed models
Logic Expression evaluation with open-world assumption
Expression evaluation on object based models
Expression evaluation over time
Expression evaluation over time - Was?

Prolog

Somewhere in the back of my head I have a class that I took back in university that scratched the surface of the Prolog language.
In a very simplified way the Prolog language uses facts and rules.

Facts in Prolog are in the form:

cat(pixel)

In other words, it is a known fact that pixel is a cat.
You can then go ahead and as for all the cats and get back pixel.
The fun things start when you define the rule that cat is an animal

animal(X) :- cat(X)

and start asking about animals and get back pixel.
A special case of rule you add a tuple and thus basically gain a relation

brotherOf(prime, pixel)
brotherOf(tiger, pixel)

meaning that prime and tiger and brothers to pixel.

As said, this is a very vague memory from the back of my head. If you are looking for a Prolog tutorial, then this is not the post for you.

Modelling knowledge

So, my approach to model knowledge is influenced by Prolog but that's about it. As I want the application to create the knowledge by itself there is no need to write a complicated textual representation, just a model that can be added to a queried. The textual representation used in this article are just there to make it easier to write about it
The model will be

attribute(variable)
relation(variable1, variable2)
variable1 => variable2

In this first version it is also assumed that all variables are strings. The attribute, relation and implication names are also treated as strings.

Some code for the knowledge model:

public class KnowledgeAttribute
{
 public string Attribute { get; set; }
 public string Subject { get; set; }
 public override string ToString()
 {
  return $"'{Attribute}'('{Subject}')";
 }
}
public class KnowledgeImplication
{
 public string Implicator { get; set; }
 public string Implied { get; set; }
 public override string ToString()
 {
  return $"'{Implicator}' => '{Implied}'";
 }
}
public class KnowledgeRelation
{
 public string Relation { get; set; }
 public string Subject { get; set; }
 public string Target { get; set; }
 public override string ToString()
 {
  return $"'{Relation}'('{Subject}', '{Target}')";
 }
}

So nothing too complicated there. Lets for simplicity store them in a holding object
public class KnowledgeModel
{
 public Dictionary<string, KnowledgeAttribute> Attributes { get; set; }
 public Dictionary<string, KnowledgeRelation> Relations { get; set; }
 public Dictionary<string, KnowledgeImplication> Implications { get; set; }

 public KnowledgeModel()
 {
  Attributes = new Dictionary<string, KnowledgeAttribute>();
  Relations = new Dictionary<string, KnowledgeRelation>();
  Implications = new Dictionary<string, KnowledgeImplication>();
 }
}

Querying

Now we can start querying the model. To get all variables with the same attribute:
public HashSet<string> ListAllWith(string attribute)
{
 return new HashSet<string>(from x in _model.Attributes.Values
  where
   x.Attribute.Equals(attribute, StringComparison.OrdinalIgnoreCase)
  select x.Subject
  );
}
Get variables matching a list of attributes
public HashSet<string> ListAllWith(IEnumerable attributes)
{
 HashSet<string> result = null;
 foreach (var attribute in attributes)
 {
  var found = ListAllWith(attribute);
  if (found.Count == 0)
   break; // nothing matches all attributes

  if (result == null)
   result = found;
  else
   result.IntersectWith(found);

  if (result.Count == 0)
   break; // nothing matches all attributes
 }
 return result;
}
Get all implications
private HashSet<string> GetAllImplications(string implied)
{
 var result = new HashSet<string>();
 result.UnionWith(from x in _model.Implications.Values
  where x.Implied.Equals(implied, StringComparison.OrdinalIgnoreCase)
  select x.Implicator);
 var chained = new HashSet<string>();
 foreach (var item in result)
 {
  chained.UnionWith(GetAllImplications(item));
 }
 result.UnionWith(chained);
 result.Add(implied);
 return result;
}
Or all related
public HashSet<string> ListAllRelated(string relationType, string variable)
{
 var relationTypes = GetAllImplications(relationType);
 return new HashSet<string>(from x in _model.Relations.Values
  where
  relationTypes.Contains(x.Relation)
  && x.Target.Equals(variable, StringComparison.OrdinalIgnoreCase)
  select x.Subject
  );
}

So. now just fill it with data and start querying.
Hope this helps someone out there

All code provided as-is. This is copied from my own code-base, May need some additional programming to work.

For example source code, head over to my github repository and play around for yourself:

Good luck :)

This is part of a series of posts regarding Knowledge modelling and expression evaluation.
The next part is
Logic Expression evaluation with open-world assumption