15,033,877 members
Articles / Artificial Intelligence
Article
Posted 30 Jul 2013

36.6K views
10 bookmarked

# LINQ to Family Tree (Prolog Style)

Rate me:
Querying a family tree in LINQ fashion.

## Introduction

This time I'll use Prolog style to achieve my goal, to make it easier and more understandable.

## Background

A family tree is chart representation of family relationships in a tree structure. Family trees are often presented with the oldest generations at the top and the newer generations at the bottom.

The figure represents a sample of family trees (The Simpsons). I know it's funny , but it will make our idea simple and clear. Of course the rest of the article will be interesting because many of us know the Simpsons. The figure illustrates how the family tree will look like, how we can organize the family members, and so forth.

The figure consists of three generations, the first generation at the top of the tree and the third generation at the bottom.

Such a tree describes the relationships of each node, e.g., Bart is son of Homer who is spouse of Marge. So we can know every relationship in the family including fathers, mothers, brothers, sisters, sons, daughters, grand parents .. etc.

This is a true sample for a tree structure which is already taught in Data Structures books.

In the following sentences I want to introduce Prolog briefly, which is a general purpose logical programming language that's used widely in artificial intelligence (AI). Prolog is one of the many functional programming languages. What does that mean? It means everything in this language is functional!! May be that sounds strange , don't worry I'll try to explore an example with a little details.

Prolog programs describe relations, defined by means of clauses. Clauses can be facts or rules.

```male(homer).

father(homer, bart).```

The facts in Prolog are nothing but functions with some arguments ending with a comma. If we take a look at the above box we'll notice that Male, Female, and Father are facts. To make it clear we can say Homer is a Male and Homer is Father of Bart. In a nutshell it seems to be an "Is A" relationship.

`brother(X,Y):- male(X), father(Z,X), father(Z,Y).`

A rule in Prolog is a kind of function that has a body which defines the actual function. In the above box we have a Brother rule which says X is Brother of Y will be true if X is Male and if we find Z as Father of X as well as Father of Y.

I think it's easy. Now you can start to define your own facts and rules in Prolog, which are the essential things in that language. The remaining thing is evaluation which is a kind of query engine for Prolog, because all the facts and rules have been stored in the knowledge database. The user can ask the Prolog query engine as much as he/she wants. Then engine starts to evaluate and answer these questions. Here are a couple of queries.

```?- male(homer).
Yes

?- father(bart, homer).
No

?- father(X, bart).
X=homer```

The first query asks if Homer is a Male. Prolog will check this fact and return the result which in this case is Yes; same thing in the second one. If we take a deep look at the last query we'll notice that we have X which is a variable, all the names starting with a capital letter are considered as variables, so this time Prolog will search for someone who is a Father of Bart, and Prolog will respond with X=Homer.

I think this is a quick tour of Prolog .. let us enter the mission ..

## Using the code

We have seen Prolog and how it uses the knowledge database and query engine for reasoning.

```'GEN 1:   Abraham        Mona       Clancy               Jackie
'            |             |           |                   |
'            +---o-----o---+           +---o-----o-----o---+
'                |     |                   |     |     |
'GEN 2:        Herb  Homer               Marge Patty  Selma
'                      |                   |            |
'                      +---o-----o-----o---+            o
'                          |     |     |                |
'GEN 3:                  Bart   Lisa Maggie            Ling```

The above diagram explores the Simpsons family tree. It shows every member of the family in each generation. It is good to draw it right here because the rest of the demos will use the tree, and it will be easier to discover the relationships and follow the rules that we will construct later on.

Now I want to build my LINQ to Family Tree provider with Prolog flavor. And the interesting part for me is the query engine which I'm trying to explore in this article because it's the core part for reasoning and evaluating results.

Again as per my latest tip/trick in which I introduced LINQ to CSV I realize that a combination of LINQ and Dynamic Programming makes LINQ so sweet and more powerful to LINQfy dynamic objects. The same way I was thinking of constructing a LINQ to Family Tree.

### Fact class

VB
```Class Fact
Inherits DynamicObject

Public Property Name As String
Public Property Arguments As New List(Of String)

Public Overrides Function TryInvokeMember(binder As InvokeMemberBinder, _
args() As Object, ByRef result As Object) As Boolean
Select Case args.Length
Case 1
mFacts.Add(New Fact() With {.Name = binder.Name.ToProper(), _
.Arguments = New List(Of String) From {args(0)}})
Case 2
mFacts.Add(New Fact() With {.Name = binder.Name.ToProper(), _
.Arguments = New List(Of String) From {args(0), args(1)}})
End Select
Return True
End Function
End Class```

The `Fact` class is one of the essential classes that participate in the core class `FamilyTree`. It defines a simple fact which contains two properties `Name` which holds the name of the fact such as Male, Female, Father, Brother .. etc., `Arguments` which is a list of strings that holds all the arguments that are related to the fact. E.g., `Female(Amy)`, `Parent(Neal,Ian)`. The arguments contain "Amy" as parameter for the `Female` fact, and two parameters "Neal" and "Ian" for the `Parent` fact.

We will notice that the `Fact` class inherits from `DynamicObject` which makes this class capable to contain run-time functions which are pretty neat, because it allows us to add facts as much as we want at run-time without complaining.

The `Fact` class must be dynamic because if we take a look at a  Prolog sample we will notice that we can write any name and make it a fact, which is something strange in the non dynamic world!! The question is how to make this class flexible and contain run-time functions?!! `DynamicObject` comes to the rescue.

VB
```<Extension()>
Public Function ToProper(str As String) As String
Return StrConv(str, VbStrConv.ProperCase)
End Function```

`ToProper` is an extension method which convert any string to a proper case which is something useful, perhaps the user writes a fact `Female("Amy")` and a query for `Female("amy")`, the result will absolutely be false because the name is case sensitive in comparing strings. To avoid this I introduced this helper function.

The last thing in the `Fact` class is the fact creation which is simply done by overriding the `TryInvokeMember` method, which gives us an opportunity to write some code while invoking any function inside this class. The code is straightforward which pushes a new instance of the `Fact` class into the `mFacts` property which is declared in the `FamilyTree` class. It simply holds all the facts in the family tree. I just want to point out that `binder.Name` returns the actual name after ".". For example fact.Father = ...

### Rule class

VB
```Class Rule
Inherits DynamicObject

Public Property Name As String
Public Property Definition As Func(Of String, String, Boolean)

Public Overrides Function TrySetMember(binder As SetMemberBinder, value As Object) As Boolean
mRules.Add(New Rule() With {.Name = binder.Name, .Definition = value})
Return True
End Function
End Class```

The Rule class defines a simple rule which takes the same way of Fact into participation in the `FamilyTree` class. It has two properties: `Name` which holds the rule name and `Definition` which holds the actual body of the function. As we can see it's a Func delegate which points to a function that accepts two strings and returns a boolean, because all the rules accept two arguments as input and it has some logic to check whether the rule is satisfied or not.

This time we override `TrySetMember`. Actually we want to create a run-time property that holds a function, so it's setting a member rather than invoking a member. The same thing happens when the code pushes a new instance of the `Rule` class into the `mRules` property which is defined in the `FamilyTree` class to hold all the rules in the tree.

I want to point out that the value is the actual value set by programming which supposedly comes after the "=", for example, r.Brother = ... which is the function that defines the `Brother` rule in this case.

### FamilyTree class

The `FamilyTree` class is the core class in LINQ to FamilyTree which acts as query engine for Prolog, It's a little long so I will try to divide it into chunks to make it readable and more understandable.

VB
```Public Class FamilyTree
Inherits DynamicObject

Private Shared Property mFacts As New List(Of Fact)
Private Shared Property mRules As New List(Of Rule)```

Again and again this class is a dynamic object to allow us to create run-time functions for querying as much as we need. Basically it contains two important properties `mFacts`, `mRules` which we had already seen before in the previous classes, so they 're `Private Shared` to make them accessible with the `FamilyTree` class and all inner classes inside it - which in our case are `Fact` and `Rule`

VB
```Public Sub New()
mRules.Add(New Rule() With {.Name = "Parent", _
.Definition = New Func(Of String, String, Boolean)(Function(x, y)
Return mFacts.Where(Function(f) f.Name = "Parent" AndAlso _
f.Arguments.First() = x AndAlso f.Arguments.Last() = y).Any()
End Function)})
mRules.Add(New Rule() With {.Name = "Married", _
.Definition = New Func(Of String, String, Boolean)(Function(x, y)
Return mFacts.Where(Function(f) f.Name = "Married" AndAlso _
f.Arguments.First() = x AndAlso f.Arguments.Last() = y).Any()
End Function)})
mRules.Add(New Rule() With {.Name = "Male", _
.Definition = New Func(Of String, String, Boolean)(Function(x, y)
Return mFacts.Where(Function(f) f.Name = "Male" AndAlso f.Arguments.First() = x).Any()
End Function)})
mRules.Add(New Rule() With {.Name = "Female", _
.Definition = New Func(Of String, String, Boolean)(Function(x, y)
Return mFacts.Where(Function(f) f.Name = "Female" AndAlso f.Arguments.First() = x).Any()
End Function)})
End Sub```

We add the four essential rules that we need in the constructor: `Parent`, `Married`, `Male`, and `Female`. Let me describe two of them.

• `Parent`: which has name "Parent" and the definition is a simple function that accepts x, y as arguments and checks if there's a fact that has name "Parent" and x as first argument and y as last argument; if there is it will return True otherwise False.
• `Male`: which has name "Male" and the definition is a simple function that accepts x, y as arguments and check if there's a fact that has name "Male" and x as first argument; if there is, it will return True otherwise False. If you notice we are no longer interested in the last argument because this fact has a single argument.
VB
```Public Sub Facts(action As Action(Of Object))
action(New Fact())
End Sub

Public Sub Rules(action As Action(Of Object))
action(New Rule())
End Sub```

As we have seen I introduced new procedures to add facts and rules, respectively, but I used `Action(Of T)` instead of pushing the instances directly into the facts or rules lists! Don't worry I did that to add the facts or rules at one shoot, in other words as a bulk of instances rather than adding them one by one. Also to make it look like a function that we have seen in Prolog before.

VB
```Public Overrides Function TryInvokeMember(binder As InvokeMemberBinder, _
args() As Object, ByRef result As Object) As Boolean
Dim mRule = mRules.Where(Function(r) r.Name = binder.Name).SingleOrDefault()
If mRule IsNot Nothing Then
Dim lst As New List(Of String)
Dim lst1 As List(Of String)
Dim lst2 As List(Of String)
If args(0).GetType() Is GetType(String) Then
lst1 = New List(Of String)
Else
lst1 = New List(Of String)(CType(args(0), List(Of String)).Select(Function(s) s.ToProper()))
End If
Select Case args.Length
Case 1
If binder.Name = "Male" OrElse binder.Name = "Female" Then
result = mRules.Where(Function(r) _
r.Name = binder.Name).Single().Definition.Invoke(args(0), Nothing)
Exit Select
End If
For Each item1 In lst1
Function(f) f <> item1 AndAlso mRule.Definition.Invoke(f, item1)))
Next
result = lst
Case 2
If args(1).GetType() Is GetType(String) Then
lst2 = New List(Of String)
Else
lst2 = New List(Of String)(CType(args(1), _
List(Of String)).Select(Function(s) s.ToProper()))
End If
For Each item1 In lst1
For Each item2 In lst2
If mRule.Definition.Invoke(item1, item2) Then
result = True
Exit Select
End If
Next
Next
result = False
End Select
Else
Throw New ArgumentException(String.Format("The rule {0} is not exist", binder.Name))
End If
Return True
End Function ```

Here I override the `TryInvokeMember` method to execute the queries that are associated with the `FamilyTree` object. I know it looks strange a little bit, but hold on I will give you the main idea and explain how it works.

Basically we are looking for a rule with its name after the ".". If we issue `familyTree.Brother` that means we should look for the `Brother` rule in `mRules` list; if it does not exist that means it's not defined yet so I throw an `ArgumentException`, otherwise we have two choices:

1. Boolean Query: If the query contains two arguments that indicate that we want to check if the given rule satisfies or not. May be the query contains one argument and this is a special case for Male and Female rules.
2. List Query: If the query contains one argument that indicates the we are looking for something that satisfies the argument with the given rule.

If we dig into the previous code we will see that I introduced two `List(Of String)` because sometimes one or both arguments may contain more than one value. For example the Sister rule which is defines as follows:

VB
`sister(X,Y):- female(X), sibling(X,Y) `

X may have one or more siblings, I think it will be nice if we use `List(Of String)` rather than `String` to cover all the cases.

Again if we dig into the code you will notice that whenever we are trying to execute a List Query we are looking into all the facts of the tree which in the `mFacts` property. Aafter that we return all the matches that satisfy the given rule.

That's it .. let us see how we can represent Simpsons in a `FamilyTree` object, of course we should create an instance of `FamilyTree` class as follow:

VB
`Dim family As Object = New FamilyTree() `

After that let us define our facts which are shown in the graph at the top.

VB
```'Facts
family.Facts(New Action(Of Object)(Sub(f)
f.Male("Abraham")
f.Male("Clancy")
f.Male("Herb")
f.Male("Homer")
f.Male("Bart")
f.Female("Mona")
f.Female("Jackie")
f.Female("Marge")
f.Female("Patty")
f.Female("Selma")
f.Female("Lisa")
f.Female("Maggie")
f.Female("Ling")
f.Married("Abraham", "Mona")
f.Married("Clancy", "Jackie")
f.Married("Homer", "Marge")
f.Parent("Abraham", "Herb")
f.Parent("Mona", "Herb")
f.Parent("Abraham", "Homer")
f.Parent("Mona", "Homer")
f.Parent("Clancy", "Marge")
f.Parent("Jackie", "Marge")
f.Parent("Clancy", "Patty")
f.Parent("Jackie", "Patty")
f.Parent("Clancy", "Selma")
f.Parent("Jackie", "Selma")
f.Parent("Homer", "Bart")
f.Parent("Marge", "Bart")
f.Parent("Homer", "Lisa")
f.Parent("Marge", "Lisa")
f.Parent("Homer", "Maggie")
f.Parent("Marge", "Maggie")
f.Parent("Selma", "Ling")
End Sub)) ```

The code is straightforward, we create a new `Action(Of Object)` and we pass all the facts that we have. It is like a Prolog fact except it passes arguments as a magic string, but it's more readable. And as I mentioned before we have four essentials rules (`Male`, `Female`, `Married`, and `Parent`) which are predefined in my LINQ to Family Tree provider. Isn't that cool? I hope that .. there are a lot of  cooler things to continue ..

After we define our facts it's time for defining the rules or family relationships ..

VB
```'Rules
family.Rules(New Action(Of Object)(Sub(r)
r.Spouse = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Married(x, y) OrElse family.Married(y, x)
End Function)

r.Husbund = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.Spouse(x, y)
End Function)

r.Wife = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.Spouse(x, y)
End Function)

r.Father = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.Parent(x, y)
End Function)

r.Mother = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.Parent(x, y)
End Function)

r.Sibling = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return Equals(family.Father(x), family.Father(y)) AndAlso _
Equals(family.Mother(x), family.Mother(y)) AndAlso x <> y
End Function)

r.Brother = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.Sibling(x, y)
End Function)

r.Sister = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.Sibling(x, y)
End Function)

r.GrandParent = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Parent(x, family.Parent(y))
End Function)

r.GrandFather = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.GrandParent(x, y)
End Function)

r.GrandMother = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.GrandParent(x, y)
End Function)

r.GrandChild = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.GrandParent(y, x)
End Function)

r.GrandSon = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.GrandChild(x, y)
End Function)

r.GrandDaughter = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.GrandChild(x, y)
End Function)

r.Child = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Parent(y, x)
End Function)

r.Son = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.Child(x, y)
End Function)

r.Daughter = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.Child(x, y)
End Function)

r.Uncle = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso (family.Sibling(x, family.Parent(y)) _
OrElse family.Parent(family.Sibling(family.Spouse(x)), y))
End Function)

r.Aunt = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso (family.Sibling(x, family.Parent(y)) _
OrElse family.Parent(family.Sibling(family.Spouse(x)), y))
End Function)

r.Cousin = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Uncle(family.Parent(x), y) OrElse family.Aunt(family.Parent(x), y)
End Function)

r.Nephew = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.Sibling(family.Parent(x), y)
End Function)

r.Niece = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.Sibling(family.Parent(x), y)
End Function)

r.GreatGrandParent = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Parent(x, family.GrandParent(y))
End Function)

r.GreatGrandFather = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.GreatGrandParent(x, y)
End Function)

r.GreatGrandMother = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.GreatGrandParent(x, y)
End Function)

r.GreatGrandChild = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Parent(family.GrandChild(y), x)
End Function)

r.GreatGrandSon = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.GreatGrandChild(x, y)
End Function)

r.GreatGrandDaughter = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.GreatGrandChild(x, y)
End Function)

r.ParentInLaw = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Parent(x, family.Spouse(y))
End Function)

r.FatherInLaw = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.ParentInLaw(x, y)
End Function)

r.MotherInLaw = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.ParentInLaw(x, y)
End Function)

r.SiblingInLaw = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Sibling(x, family.Spouse(y))
End Function)

r.BrotherInLaw = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.SiblingInLaw(x, y)
End Function)

r.SisterInLaw = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.SiblingInLaw(x, y)
End Function)

r.ChildInLaw = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Spouse(x, family.Child(y))
End Function)

r.SonInLaw = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.ChildInLaw(x, y)
End Function)

r.DaughterInLaw = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Female(x) AndAlso family.ChildInLaw(x, y)
End Function)
End Sub))```

As I did in facts, I defined almost the rules passed in a new instance of `Action(Of Object)` that will be passed into the Rules procedure.

Let me now explain three of them:

1. Father

VB
```r.Father = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso family.Parent(x, y)
End Function)```

I define a dynamic member named `Father` that holds a function which accepts two strings and returns a boolean. In other words it holds a rule definition. The function is very simple Father(x, y). x is  Father of y if x is male and x is Parent of y. If these two conditions are satisfied then x should be a father of y.

2. Sibling

VB
```r.Sibling = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return Equals(family.Father(x), family.Father(y)) AndAlso _
Equals(family.Mother(x), family.Mother(y)) AndAlso x <> y
End Function) ```
I define a dynamic member named Sibling that holds a rule. Sibling(x, y). x is Sibling of y if father of x is the same exact Father of y as well as their Mother and x is not y. Here I used a helper function `Equals` because we are issuing a list query and we know that = operator is not appropriate for comparing two lists, so I used the following:
VB
```Public Function Equals(lst1 As List(Of String), lst2 As List(Of String)) As Boolean
Return lst1.Intersect(lst2).Any()
End Function ```

3. Uncle

VB
```r.Uncle = New Func(Of String, String, Boolean)(Function(x, y) As Boolean
Return family.Male(x) AndAlso (family.Sibling(x, family.Parent(y)) _
OrElse family.Parent(family.Sibling(family.Spouse(x)), y))
End Function)```

I define a dynamic member named Uncle that holds a rule. Uncle(x, y). x is Uncle of y if x is male and Parent of y is sibling to x. We pass a function as argument to another function and that's the flavor of functional programming languages such as Prolog.

### Knowledge Database

The knowledge database is a data structure that consists of two parts:

1. Facts

A linear data structure that all the facts in the family tree are organized into. It simply contains all the fact names and their arguments they are associated with.

2. Rules

A linear data structure that all the rules in the family tree are organized into. It simply contains all the rule names and definitions.

### How the query engine works?

The query engine is the part that is responsible for executing queries and evaluating the result from the knowledge database.

1. Boolean Query

In this type of query, the engine works as the follows:

• Initialize the query
• Look into the Facts data structure - which is `mFacts` in our code - to the exact same fact name that has been issued with their arguments
• Return true if we find a match in facts
• Otherwise look into the Rules data structure to the exact rule name that has been issued with the arguments
• If the rule definition contains a declaration of predefined facts, just apply the rule definition with the given arguments and return the list of names that satisfy the rule definition in Facts
• If the rule definition contains another rule, we should dig into that rule and do the same thing as in the previous step

2. List Query

In this type of query, the engine works as follows:

• Initialize the query
• Look into the Rules data structure - which  is `mRules` in our code - to the exact rule name that has been issued with its argument
• Return the definition of the rule if found
• Apply that rule with the given argument with all the names in facts
• Return the list of names that match the previous rule

Last but not least let us issue some queries and see their results:

VB
```'Queries
Console.WriteLine(family.Mother("Selma", "Ling"))

True

Console.WriteLine(family.Sister("Ling", "Lisa"))

False

Dim query = From s In CTypeDynamic(Of List(Of String))(family.Daughter("Homer"))
Select s

For Each item In query
Console.WriteLine(item)
Next For Each item In query

Lisa
Maggie```

The first query returns True because Selma is Female and she is a Parent of Ling, so Selma is Mother of Ling. While the second query returns False because Ling is not a Sibling of Lisa.

The above queries are a sample of Boolean Query, while the last query is a sample of a List query, it uses LINQ to enumerate all of Homer's daughters, which are in our case Lisa and Maggie.

The last thing I want to show you is one of the complex queries using LINQ to Family Tree:

VB
```Dim query = From gc In CTypeDynamic(Of List(Of String))(family.GrandFather("Bart"))
Let Children = family.Child(gc)
Where Children.Count > 1
Select Name = gc, Children

For Each item In query
Console.WriteLine("{0} ({1}) childern", item.Name, item.Children.Count)
For Each subitem In item.Children
Console.WriteLine("  {0}", subitem)
Next
Console.WriteLine()
Next

Abraham (2) children
Herb
Homer

Clancy (3) children
Marge
Patty
Selma```

In the above query, we were looking for the GrandFathers of Bart, Abraham and Clancy, and retrieving their names and their children if they have more than one child. Of course the result will show Abraham, Clancy, and their children.

That's it .. I hope you enjoyed my LINQ to Family Tree provider.

## Points of Interest

LINQ is a great technology for querying with any underlying data source, and to mix with Dynamic Programming to explore its power. In this article I solved some of the tiny issues such as capitalization of arguments, optimizing the search process, and detecting undefined rules.