LOGQ 2.1.0

dotnet add package LOGQ --version 2.1.0                
NuGet\Install-Package LOGQ -Version 2.1.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LOGQ" Version="2.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add LOGQ --version 2.1.0                
#r "nuget: LOGQ, 2.1.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install LOGQ as a Cake Addin
#addin nuget:?package=LOGQ&version=2.1.0

// Install LOGQ as a Cake Tool
#tool nuget:?package=LOGQ&version=2.1.0                

LOGQ

LOGQ stands for LOGical Query - it's logical programming tool that works similar to Prolog program. It's goal to simplify and extend Prolog features and provide easy integration with mapping tool.

Documentation
NuGet package

Usage

Logical query

Main feature is creating logical queries. They're built as trees with nodes represented by logical actions. Logical actions can be added using With method, some predefined logical actions can be added using Cut, Fail, Succed, WithScoped methods.

LogicalQuery query = new LogicalQuery()
  .With(() => true) 
  .Cut()
  .Fail()
  .OrWith(() => Console.WriteLine("Action!"))
  .Succed();

Logical action

Logical actions are abstractions used for query nodes, they define some sort of condition and created by specifying a backtrack iterator that provides them with predicates to check.

LogicalQuery query = new LogicalQuery()
  .With(() => 3 > 1);
  
// In this case predicate will be converted to list with one predicate
// Then it will be converted to backtrack iterator which will iterate through that list

Logical actions can be created by passing bactrack iterator, action, predicate or collection of predicates to the logical query using With. If some of the given predicates is successful - logical action returns true, if each predicate fails - action returns false.

Backtrack iterator

Backtrack iterator is used to replace Prolog's predicate types with single abstraction. It consists of generator function and reset action:

  • Generator generates predicates for logical actions until it meets some terminal condition after which it returns null that means it's out of predicates.
  • Reset action returns generator back to it's initial state.
// Backtrack iterator constructor for previous example

internal BacktrackIterator(ICollection<Predicate<List<IBound>>> initializer)
{
    bool enumeratorIsUpToDate = false;
    var enumerator = initializer.GetEnumerator();

    _generator = () =>
    {
        if (!enumeratorIsUpToDate)
        {
            enumerator = initializer.GetEnumerator();
            enumeratorIsUpToDate = true;
        }

        if (!enumerator.MoveNext())
        {
            return null;
        }

        Predicate<List<IBound>> predicate = enumerator.Current;
        return predicate;
    };

    _reset = () => enumeratorIsUpToDate = false;
}

Knowledge base

Knowledge bases are storing facts and rules and can provide backtrack iterators that would do fact-checking or rule-checking on base contents.

// Let's say we have some records about school students
KnowledgeBase students = new KnowledgeBase();

// There is a record about student named Andrew in 7th grade
students.DeclareFact(new FactStudent("Andrew", 7))

// Also we know that if we have a record about student in higher grade we also have records about that student in lesser grades
students.DeclareRule(new RuleWithBody<BoundRuleStudent>(
    new RuleStudent(new AnyValue<string>(), new AnyValue<int>()),
    bound => new LogicalQuery()
        .With(new BoundFactStudent(bound.Name, bound.Grade), students)
        .OrWith(context => bound.Grade.Value <= 12)
        .With(new BoundRuleStudent(bound.Name, bound.Grade.Value + 1), students)
    ));

Facts

Facts are plain data stored in knowledge base.

LogicalQuery query = new LogicalQuery()
  .With(new BoundFactStudent("Andrew", 1), students)
  .With(new BoundFactStudent("Alex", new UnboundVariable<int>()), students)

To make a fact-check bound facts are created. Bound facts are facts using bound variables, that stands for variables which mutation is controlled by backtracking (their values are restored to preaction state on the way back).

Rules

Rules are data with associated logical query which returns true only if that data exists. They made with two parts:

  • Rule head that consists of patterns to check if this rule applies
  • Rule body that consists of query
LogicalQuery query = new LogicalQuery()
  .With(new BoundRuleStudent("Alex", 3), students);

To make a rule-check bound rules are created. Like bound facts that's rule heads made of bound variables.

Objects mapping

Objects are mapped by marking them with Fact attribute. Marked objects are processed by source generator that creates their Fact, BoundFact, Rule and BoundRule analogues and adds static method to convert objects to their representations

// Marking student class used in previous examples
// That will generate FactStudent, BoundFactStudent, RuleStudent and BoundRuleStudentClasses 

[LOGQ.Fact("Student")]
public class Student
{
    public string Name { get; set; }
    public int Grade { get; set; }

    public Student(string name, int grade)
    {
        Name = name;
        Grade = grade;
    }
}

Credits

Andrew Lock's source generator series

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.1.0 413 10/25/2022
2.0.0 400 9/23/2022
1.1.0 409 9/8/2022
1.0.0 394 8/31/2022

- Retract method to delete facts and rules from knowledge base
- Generic RuleWithBody that no more requires downcasting bound rule
- Fast rule-checks
- Collections of supported delegates supported too
- Records and structs support
- Generic types mapping
- Explicitly adding fact/rule storages