-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First pass of interactive path index and discrimination tree visualis…
…ers in the docs site. Just 'cos.
- Loading branch information
Showing
4 changed files
with
390 additions
and
1 deletion.
There are no files selected for viewing
184 changes: 184 additions & 0 deletions
184
src/SCFirstOrderLogic.Documentation/Razor/Pages/lab/DiscriminationTreeVisualiser.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
@page "/lab/discrimination-tree-visualiser" | ||
|
||
@using SCFirstOrderLogic; | ||
@using SCFirstOrderLogic.ExampleDomains.FromAIaMA.Chapter9.UsingSentenceParser; | ||
@using SCFirstOrderLogic.Inference; | ||
@using SCFirstOrderLogic.Inference.Basic.BackwardChaining; | ||
@using SCFirstOrderLogic.Inference.Basic.ForwardChaining; | ||
@using SCFirstOrderLogic.Inference.Basic.Resolution; | ||
@using SCFirstOrderLogic.SentenceCreation; | ||
@using System.ComponentModel.DataAnnotations; | ||
@using SCFirstOrderLogic.SentenceManipulation | ||
@using SCFirstOrderLogic.TermIndexing | ||
@using static SCFirstOrderLogic.SentenceCreation.SentenceFactory; | ||
@inject IJSRuntime JS | ||
|
||
<h3>Lab - Discrimination Tree Visualiser <a data-bs-toggle="modal" data-bs-target="#exampleModal" href="#"><span class="bi bi-info-circle" aria-hidden="true"></span></a></h3> | ||
|
||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> | ||
<div class="modal-dialog"> | ||
<div class="modal-content"> | ||
<div class="modal-header"> | ||
<h5 class="modal-title" id="exampleModalLabel">Lab Explanation</h5> | ||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||
</div> | ||
<div class="modal-body"> | ||
<p> | ||
This page is an interactive visualiser for the disrimination trees, as implemented by SCFirstOrderLogic. | ||
</p> | ||
<p> | ||
Each path from root to leaf in a discrimination tree consists of a depth-first traversal of the elements of the term that the leaf represents. | ||
Discrimination trees are particularly well-suited to (i.e. performant at) looking up generalisations of a query term. | ||
</p> | ||
<p> | ||
Note that: | ||
</p> | ||
<ul> | ||
<li>This one is admittedly a little rough around the edges with regards to the tree view and input validation. It'll be iterated upon.</li> | ||
<li>You can add terms to the tree by entering them into the Term text box and clicking the 'Add' button.</li> | ||
<li>When parsing the term, identifiers not followed by any parentheses (to indicate a function) will be interpreted as variables if they feature in the "variables" text box. Otherwise they will be interpreted as zero-arity functions (i.e. constants).</li> | ||
<li>Guidance for writing terms as strings can be found on the "getting started" page.</li> | ||
<li>The source code for this page can be found <a href="https://github.com/sdcondon/SCFirstOrderLogic/blob/main/src/SCFirstOrderLogic.Documentation/Razor/Pages/lab/DiscriminationTreeVisualiser.razor">here</a>.</li> | ||
</ul> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<EditForm Model=@formData Context="editContext" style="font-family: monospace"> | ||
<DataAnnotationsValidator /> | ||
<div class="form-group"> | ||
<label for="variablesText">Variables (comma-separated)</label> | ||
<InputText class="form-control" id="variablesText" @bind-Value=formData.Variables /> | ||
<ValidationMessage For="@(() => formData.Variables)" /> | ||
</div> | ||
<div class="form-group"> | ||
<label for="queryText">Term</label> | ||
<InputText class="form-control" id="queryText" @bind-Value=formData.Term /> | ||
<ValidationMessage For="@(() => formData.Term)" /> | ||
</div> | ||
<div class="form-group mt-2"> | ||
<button type="submit" @onclick="@(() => Add(editContext))" class="btn btn-primary">Add</button> | ||
<button type="submit" @onclick="@(() => RemoveAll(editContext))" class="btn btn-primary">Remove All</button> | ||
</div> | ||
</EditForm> | ||
|
||
@{ | ||
void RenderDiscriminationTreeNode(string label, IDiscriminationTreeNode<Term> node) | ||
{ | ||
<li> | ||
@label | ||
<ul> | ||
@if (node.Children.Count > 0) | ||
{ | ||
@foreach (var (childNodeKey, childNode) in node.Children) | ||
{ | ||
var childNodeLabel = childNodeKey switch | ||
{ | ||
DiscriminationTreeConstantNodeKey constantNodeKey => $"FUNCTION: {constantNodeKey.Identifier} (ARITY {constantNodeKey.ChildElementCount})", | ||
DiscriminationTreeFunctionNodeKey functionNodeKey => $"FUNCTION: {functionNodeKey.Identifier} (ARITY {functionNodeKey.ChildElementCount})", | ||
DiscriminationTreeVariableNodeKey variableNodeKey => $"VARIABLE: {variableNodeKey.Ordinal}", | ||
_ => throw new ArgumentException(nameof(node)) | ||
}; | ||
|
||
RenderDiscriminationTreeNode(childNodeLabel, childNode); | ||
} | ||
} | ||
else | ||
{ | ||
Term value; | ||
try | ||
{ | ||
value = node.Value; | ||
<li>VALUE: @value</li> | ||
} | ||
catch | ||
{ | ||
// root node of empty tree is internal node that has no children | ||
} | ||
} | ||
</ul> | ||
</li> | ||
} | ||
} | ||
|
||
<ul class="mt-4"> | ||
@{ | ||
RenderDiscriminationTreeNode("ROOT", discriminationTreeRootNode); | ||
} | ||
</ul> | ||
|
||
@code { | ||
private DiscriminationTreeDictionaryNode<Term> discriminationTreeRootNode; | ||
private DiscriminationTree discriminationTree; | ||
private FormData formData = new FormData("u, v, w, x, y, z", ""); | ||
|
||
public DiscriminationTreeVisualiser() | ||
{ | ||
discriminationTreeRootNode = new DiscriminationTreeDictionaryNode<Term>(); | ||
discriminationTree = new DiscriminationTree(discriminationTreeRootNode); | ||
} | ||
|
||
private void Add(EditContext editContext) | ||
{ | ||
if (editContext.Validate()) | ||
{ | ||
// TODO: probably useful to offer term parsing.. | ||
var sentence = SentenceParser.BasicParser.Parse($"forall {formData.Variables}, P({formData.Term})"); | ||
var visitor = new TermExtractor(); | ||
visitor.Visit(sentence); | ||
discriminationTree.Add(visitor.Term); | ||
StateHasChanged(); | ||
} | ||
} | ||
|
||
private void RemoveAll(EditContext editContext) | ||
{ | ||
discriminationTreeRootNode = new DiscriminationTreeDictionaryNode<Term>(); | ||
discriminationTree = new DiscriminationTree(discriminationTreeRootNode); | ||
StateHasChanged(); | ||
} | ||
|
||
private class FormData : IValidatableObject | ||
{ | ||
public FormData(string variables, string term) | ||
Check warning on line 144 in src/SCFirstOrderLogic.Documentation/Razor/Pages/lab/DiscriminationTreeVisualiser.razor
|
||
{ | ||
this.Variables = variables; | ||
this.Term = term; | ||
} | ||
|
||
public string Variables { get; set; } | ||
|
||
public string Term { get; set; } | ||
|
||
public string SubmitType { get; set; } | ||
|
||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) | ||
{ | ||
// Yes, could cache the parse results to avoid parsing multiple times, but not worth it for now at least. | ||
// TODO-FEATURE: Some "TryParse.." methods might be useful - they'd certainly make this method a bit cleaner. | ||
// TODO-FEATURE: If we had a ParseError exception type, we could perhaps highlight the offending text. | ||
List<ValidationResult> errors = new(); | ||
try | ||
{ | ||
var sentence = SentenceParser.BasicParser.Parse($"forall {Variables}, P({Term})"); | ||
} | ||
catch (Exception e) | ||
{ | ||
errors.Add(new ValidationResult(e.Message, new[] { nameof(Term) })); | ||
} | ||
|
||
return errors; | ||
} | ||
} | ||
|
||
private class TermExtractor : RecursiveSentenceVisitor | ||
{ | ||
public Term? Term { get; private set; } | ||
|
||
public override void Visit(Predicate predicate) | ||
{ | ||
Term = predicate.Arguments.Single(); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/SCFirstOrderLogic.Documentation/Razor/Pages/lab/Index.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
@page "/lab" | ||
|
||
<h2>Lab - Index</h2> | ||
|
||
<p>This page serves as an index for interactive demos and tools.</p> | ||
|
||
<ul> | ||
<li><a href="lab/inference-demo">Inference Demo</a>: A demonstration of (FoL parsing and) inference with the knowledge bases found in the SCFirstOrderLogic.Inference.Basic package.</li> | ||
<li><a href="lab/path-tree-visualiser">Path Tree Visualiser</a>: An interactive visualiser for path trees as implemented by SCFirstOrderLogic.</li> | ||
<li><a href="lab/discrimination-tree-visualiser">Discrimination Tree Visualiser</a>: An interactive visualiser for discrimination trees as implemented by SCFirstOrderLogic.</li> | ||
</ul> |
2 changes: 1 addition & 1 deletion
2
src/SCFirstOrderLogic.Documentation/Razor/Pages/lab/InferenceDemo.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.