adding support for umbounded graphs
authorThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Mon, 30 Dec 2024 12:43:13 +0000 (12:43 +0000)
committerThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Mon, 30 Dec 2024 12:43:13 +0000 (12:43 +0000)
54 files changed:
README.txt
developer/deprecated/Build.javax [new file with mode: 0644]
developer/documentđź–‰/DirectedGraph_cycle_algorithm.txt [new file with mode: 0644]
developer/documentđź–‰/DirectedGraph_definition.txt [new file with mode: 0644]
developer/documentđź–‰/GraphDirectedAcyclic_1.txt [deleted file]
developer/documentđź–‰/dependency_graph.html [deleted file]
developer/documentđź–‰/graph_print.html [new file with mode: 0644]
developer/example/CountingNumber.class [new file with mode: 0644]
developer/example/CountingNumber.java [new file with mode: 0644]
developer/example/Example_Ariadne_SRM [new file with mode: 0755]
developer/example/Example_Ariadne_SRM.class [new file with mode: 0644]
developer/example/Example_Ariadne_SRM.java [new file with mode: 0644]
developer/javacđź–‰/#Ariadne_Node.xjava# [new file with mode: 0644]
developer/javacđź–‰/Ariadne_DirectedGraph.xjava [new file with mode: 0644]
developer/javacđź–‰/Ariadne_File.java [deleted file]
developer/javacđź–‰/Ariadne_Graph.java
developer/javacđź–‰/Ariadne_GraphDirectedAcyclic.java [deleted file]
developer/javacđź–‰/Ariadne_Label.java
developer/javacđź–‰/Ariadne_LabelList.java [deleted file]
developer/javacđź–‰/Ariadne_LabelList.xjava [new file with mode: 0644]
developer/javacđź–‰/Ariadne_Node.java
developer/javacđź–‰/Ariadne_NodeList.java [deleted file]
developer/javacđź–‰/Ariadne_NodeList.xjava [new file with mode: 0644]
developer/javacđź–‰/Ariadne_Production.java [deleted file]
developer/javacđź–‰/Ariadne_ProductionList.java [deleted file]
developer/javacđź–‰/Ariadne_SRM.java [new file with mode: 0644]
developer/javacđź–‰/Ariadne_SRMI.java [new file with mode: 0644]
developer/javacđź–‰/Ariadne_Test.java [new file with mode: 0644]
developer/javacđź–‰/Build.javax [deleted file]
developer/javacđź–‰/DirectedGraph.xjava [new file with mode: 0644]
developer/javacđź–‰/File.java [new file with mode: 0644]
developer/javacđź–‰/GraphAriadne.javax [deleted file]
developer/toolđź–‰/make_example [new file with mode: 0755]
documentđź–‰/Ariadne_tool.txt [new file with mode: 0644]
documentđź–‰/project_participants.txt [new file with mode: 0644]
tester/data/File_0/I_exist [new file with mode: 0644]
tester/data/File_0/file_0 [new file with mode: 0644]
tester/data/File_0/file_1 [new file with mode: 0644]
tester/data/File_0/file_2 [new file with mode: 0644]
tester/data/File_0/file_3 [new file with mode: 0644]
tester/data_File_0/I_exist [deleted file]
tester/data_File_0/file_0 [deleted file]
tester/data_File_0/file_1 [deleted file]
tester/data_File_0/file_2 [deleted file]
tester/data_File_0/file_3 [deleted file]
tester/javacđź–‰/File_0.java
tester/javacđź–‰/Graph_0.java
tester/javacđź–‰/LabelList_0.java
tester/javacđź–‰/Label_0.java
tester/javacđź–‰/NodeList_0.java
tester/javacđź–‰/Node_0.java
tester/javacđź–‰/TokenSet_0.java
tester/javacđź–‰/Token_0.java
tester/javacđź–‰/Util_0.java

index 5e7234b..2399ef0 100644 (file)
@@ -7,99 +7,22 @@ Note the directories: Ariadne/documentđź–‰, Ariadne/developer/documentđź–‰, and
 --------------------------------------------------------------------------------
 Ariadne
 
-Ariadne is a graph based build tool.
+When you are tasked with a project build that is as complex as Daedalus's impossible to solve maze, modern Ariadne hands you a piece of chalk to draw arrows with. She has had a lot of time to think about it, and chalk works even better than a ball of string.
 
-When you are tasked with a project build that is as complex as Daedalus's impossible to solve maze, modern Ariadne hands you a piece of chalk to draw arrows with. It works even better than a ball of string.
+Ariadne is an directed graph based build tool. The tool and its configuration file are written in Java.  We don't brag about this, rather this is the environment for which it came to fruition.  Other language versions will surely follow, hence the source code directory is called javacđź–‰ and it builds to a scratchpad directory.
 
-A tool like Ariadne is useful for projects that have compiled languages, where there are many steps in getting from source code to a loadable set of instructions. At is able to handle complex cases with generation of sources from ANTLR grammars, and the implied dependencies of Java programs.
+Ariadne was developed to be used in a large project research environment where code is synthesized, not all of the code is working at any one time, and there are many steps for getting from authored content to loadable machine code.
 
-Ariadne can also be used to describe dependencies on libraries or other programs used by a given program.  This is useful with both compiled and interpreted languages.
-
-In the Java implementation of Ariadne, everything is coded in Java, including the developer's description of the dependency graph. 
+Ariadne will also be helpful for compiled language projects, such as C, C++.  Ariadne can also be used to describe dependencies on libraries or other programs so it will be useful with interpreted languages also.
 
 If a developer were to compare `Ariadne` with `make`, the file corresponding to the 'make file' is a dynamically loaded Java program known as the 'graph definition'.  Whereas a make file for a complex project will contain a lot of shell code, the Ariadne graph definition is all Java code. Where a make file has 'pattern rules' Ariadne will typically has regular expressions. Make can not backwards chain through pattern rules, Ariadne can. 
 
 Ariadne is more procedural than Maven, which is more descriptive. Ariadne allows for finer grain description of dependencies and finer grain decision making than with Gradle task dependencies.
 
 --------------------------------------------------------------------------------
-General Comments about Graphs
-
-Conceptually a graph is a set with two members, nodes and edges, both also being sets. In turn, each edge is a pair of nodes. In a directed graph, one of the nodes of such a pair is said to be the tail, while the other is said to be the head.  
-
-A leaf node is unusual in that it is not the tail of any edge.
-
-When a node is selected, a set is implied that contains each and every edge that has the selected node as its tail, if any. These are the outgoing edges for the selected node.  Each outgoing edge then has a head. We say that the set of head nodes are distance one from the selected node. (The selected node itself is at distance zero.) Distance one nodes are said to be 'neighbor' nodes.
-
-Deterministic traversal is an algorithm that is given two arguments when it is started, a graph definition, and a start node. The start node is then assigned to a state variable. At each step of the algorithm, the node in the state variable is selected on the graph, then the state variable is re-assigned to be one of the distance one nodes.
-
-Deterministic search for a node is an example of an algorithm that makes use of traversal.  Deterministic search begins with a graph, a start node, a predicate that is said to recognize the searched for node, and a function that guides the traversal.
-
-A self cycle in a graph consists of a node and an edge, where said edge has the node as both its tail and its head. There is no change in the traversal state variable when taking a traversal step through such an edge.  In general, a cycle consists of a start node and all nodes and edges traversed up until arriving back at said start node.
-
-It is a bad thing to have cycles in a build graph, as cycles will correspond to circular dependencies.  Hence Ariadne looks for these and reports them.
-
---------------------------------------------------------------------------------
-The Ariadne Build Graph
-
-An Ariadne graph definition contains a 'graph definition function' list.  A graph definition function is given a node label, and returns a node, or null if it can not find a node with such a label. A common graph definition function contains a map where each entry is a node label and a node.
-
-An Ariadne node is dictionary that maps a string key to a value. The type of the value is implied by the string key. Depending on the Ariadne tool being used, each node map will typically have entries for the keys "label", "build", and "neighbor".
-
-A "label" value is a string that is unique among the nodes in the graph. The "build" value is a function that a build tool will call when a file corresponding to a node is to be built.  The "neighbor" value is a list of neighbor nodes.
-
-The Ariadne graph definition is optimized to be a run time data structure used for traversal, so the neighbor list is held directly in the node. Also, there is only one edge property, that of 'dependency'. As a consequence, there is no need for a separate edge table.
-
---------------------------------------------------------------------------------
-Ariadne Build Tool
-
-For the default Ariadne build tool, each node label is either symbolic, or is a file path. The tool descends into the graph, based on file modification dates, and builds nodes that are modified less recently than their dependencies.
-
---------------------------------------------------------------------------------
-For Developers/Testers
-
-The project has three entry points, one for each project role: developer, tester, and administrator. To enter the project, source the environment appropriate for the role, either `env_developer`, `env_tester`, or `env_administrator`.
-
-1. Production 
-
-  1.1. development
-
-  cd Ariadne
-  . env_developer
-
-  [do work]
-
-  make
-  release
-
-  1.2 regression testing
-
-  cd Ariadne
-  . env_tester
-  make
-  run
-
-2. Debugging
-
-  cd Ariadne
-  . env_developer
-  make
-  # puts links to source files on the `scratchpad`
-  gather_source_links 
-
-  [change to tester module]
-
-  cd Ariadne
-  # the developer parameter links in the actual source in the developer module
-  . env_tester developer
-  make
-  run
-
-The `make` command you see above is a bash script. Version 1.0 of Ariadne uses a direct 'build it all every time' approach. Perhaps in version 2.0 or so, we will use a prior version of Ariadne for the build environment.
-
-In IntelliJ IDEA there are two modules, developer and tester. The output for each module is 'scratchpad' tests are added through the `run edit-configuration` menu. See tool_shared/third_party/documentđź–‰ directory for more information.
-
-Using Ariadne
--------------
-
-After it is built and released the tool will appear in the Ariadne/release directory where it can be regression tested or imported into another project.
+See also:
 
+~RT-project-share/documentsđź–‰  for information about RT projects.
+~Ariadne/documentsđź–‰  for more general information about Ariadne
+~Ariadne/developer/documentsđź–‰  specific information about the code
+~Ariadne/tester/documentsđź–‰  specific information about the tests
diff --git a/developer/deprecated/Build.javax b/developer/deprecated/Build.javax
new file mode 100644 (file)
index 0000000..b0cdab3
--- /dev/null
@@ -0,0 +1,76 @@
+import java.util.List;
+
+public class Build {
+
+    // Function to load the graph class dynamically
+    public static Class<?> includeAClass(String aClassFp) {
+        ClassLoader classLoader = Build.class.getClassLoader();
+        String className = aClassFp.replace('/', '.').replace(".class", "");
+        try {
+            return classLoader.loadClass(className);
+        } catch (Exception e) {
+            System.out.println("Error loading class '" + className + "': " + e.getMessage());
+            return null;
+        }
+    }
+
+    // Build function
+    public static void build(String graphDefinitionFp, List<String> rootNodeLabels) {
+        // Print summary of what we are doing
+        System.out.println("build:: Building targets for graph '" + graphDefinitionFp + ".class'");
+        if (rootNodeLabels.isEmpty()) {
+            System.out.println("No build targets specified. Please provide root node labels to build.");
+            System.exit(0);
+        }
+        System.out.println("Building targets: " + String.join(", ", rootNodeLabels));
+
+        // Load the dependency graph class from arg[1]
+        Class<?> graphDefinitionClass = includeAClass(graphDefinitionFp);
+        if (graphDefinitionClass != null) {
+            System.out.println("build:: loaded " + graphDefinitionFp + ".class");
+        } else {
+            System.out.println("build:: failed to load " + graphDefinitionFp + ".class");
+            System.exit(1);
+        }
+
+        // Get the node_map and node_f_list from the graph class
+        // Assuming these methods are static and return the appropriate types
+        // Replace with actual method calls if they are different
+        Object nodeMap = null;
+        Object nodeFList = null;
+        try {
+            nodeMap = graphDefinitionClass.getMethod("getNodeMap").invoke(null);
+            nodeFList = graphDefinitionClass.getMethod("getNodeFList").invoke(null);
+        } catch (Exception e) {
+            System.out.println("Error invoking methods on graphDefinitionClass: " + e.getMessage());
+            System.exit(1);
+        }
+        System.out.println("node_map: " + nodeMap);
+        System.out.println("node_f_list: " + nodeFList);
+
+        // Create an instance of AriadneGraph, and run the build scripts
+        // Assuming AriadneGraph has a constructor that takes nodeMap and nodeFList
+        // Replace with actual constructor call if it is different
+        try {
+            Class<?> ariadneGraphClass = Class.forName("AriadneGraph");
+            Object graph = ariadneGraphClass.getConstructor(nodeMap.getClass(), nodeFList.getClass()).newInstance(nodeMap, nodeFList);
+            ariadneGraphClass.getMethod("runBuildScriptsF", List.class).invoke(graph, rootNodeLabels);
+        } catch (Exception e) {
+            System.out.println("Error creating or invoking AriadneGraph: " + e.getMessage());
+            System.exit(1);
+        }
+    }
+
+    // Entry point when run as a script
+    public static void main(String[] args) {
+        if (args.length == 0) {
+            System.out.println("Usage: ./build <graph_definition.class> [root_node_labels...]");
+            System.exit(1);
+        }
+
+        // Get graph definition file and root node labels
+        String graphDefinitionFp = args[0];
+        List<String> rootNodeLabels = args.length > 1 ? List.of(args).subList(1, args.length) : List.of();
+        build(graphDefinitionFp, rootNodeLabels);
+    }
+}
diff --git a/developer/documentđź–‰/DirectedGraph_cycle_algorithm.txt b/developer/documentđź–‰/DirectedGraph_cycle_algorithm.txt
new file mode 100644 (file)
index 0000000..7a202e2
--- /dev/null
@@ -0,0 +1,84 @@
+  /*--------------------------------------------------------------------------------
+    Interface
+
+    1. nodes are referenced by label.
+
+    2. A list is a kind of sequence. It consists of a leftmost item, subsequent
+    items, and a rightmost item.
+
+    3. A node list consists of a leftmost node, subsequent nodes, and a rightmost node.
+
+    4. `path_stack`
+        
+        The `path_stack` is a list. Each item in the stack is a node list.
+
+        The rightmost items is the top of the stack.
+
+        The leftmost item is a list of root nodes, where traversal of the graph
+        starts.
+
+        Given two adjacent items on the path stack, say e0 and e1:
+
+            Say k0 is the leftmost node on the node list e0.
+            
+            The e1 will be the neighbor (child) list from node k0.
+
+            Hence, the path stack consists of the child lists of nodes along
+            a traversal. We chose a leftmost traversal.
+
+                e0:   k_0       k_1    ... k_2  
+
+                e1:   k_0_0    k_0_1   ... k_0_2   ; children of k_0
+
+                e2:   K_0_0_0  k_0_0_1 ... k_0_0_2 ; children of k_0_0
+                
+
+    5. `path`
+
+        A list of the leftmost nodes from a path stack.  
+
+        Given that e0 is a root node, `path` will consist of 
+
+            k_0, k_0_0, k_0_0_0 ... k_0_0..._0
+
+        Within the context of a path, k_0 is the leftmost item, and k_n is the
+        rightmost item.
+
+
+    6. removing a cycle
+
+       This is a build tool. Each node corresponds to a build objective, and the
+       neighbor nodes are dependencies. A neighbor node is a child node in our
+       tree descent, and is a dependency to our build tool.
+
+       This routine is called as part of the analysis phase. Nothing is
+       built here, rather we are merely marking dependency cycles that we
+       find when descending from the root nodes.
+
+       When we find a cycle, we remove those nodes from the current traversal
+       path, because we do not went the analysis to do in circles.  It is
+       possible that there are spurs that emanate from the cycle, and following
+       these might lead to finding more cycles.
+
+       Our build tool (which is not in this file) will stop descending through
+       the graph upon finding a cycle, and the effects of this will cause
+       upstream nodes to also not be built. Hence, the cycles hidden behind
+       other cycles are irrelevant.  
+
+       However, if we want to make routine of more general use, then the
+       discovered cycles should be pushed on to a cycle stack, and then each
+       item on the cycle stack would be used as root nodes for a new cycle
+       search. Note the leftmost cycle on each recursive search on the leftmost
+       node, will be the original cycle.
+  */
+
+  /*
+    Given a path to a node in the graph, `left_path`.
+
+    Checks if the rightmost node (referenced by label) recurs earlier in the path.
+    Presumably the rightmost node has been recently appended to the path.
+
+    If there is no cycle, returns null, otherwise returns the interval [i ,n],
+    of indexes into the path where the cycle is found. `n` will always be
+    the index of the rightmost node in the path list.
+  */
diff --git a/developer/documentđź–‰/DirectedGraph_definition.txt b/developer/documentđź–‰/DirectedGraph_definition.txt
new file mode 100644 (file)
index 0000000..9f17927
--- /dev/null
@@ -0,0 +1,26 @@
+
+To create a directed graph, extend the class `Ariadne_DirectedGraph`.
+
+In Ariadne a graph is defined by the `start` and `lookup` functions.
+
+`start` returns a list of start nodes.  We require that `start` returns
+the same list of nodes, no matter when it is called.  It 
+
+
+
+
+
+The graph is not wellformed if `start` returns a label that `lookup` fails to find.
+
+`lookup` is a function. It accepts a node label, and returns the node that has that label. A possible implementation of `lookup` is to lookup the node in a map, but there are many other possible implementations. 
+
+Because lookup is a function who's definition is left to the user, it is not possible in general to analyze `lookup` to know which nodes are in the graph. Even when `lookup` has a definition that is analyzable in theory, it is typically not practical to analyze it to discover the possible node labels. Hence, the user also provides the build tool with a list of possible `start` labels, where graph traversal can start.
+
+After extending `Ariadne_DirectedGraph` the user might want to structure `lookup` by calling a number of helper functions.  These helper functions play the same role as do separate make file rules when using `make`.
+
+
+
+
+
+
+
diff --git a/developer/documentđź–‰/GraphDirectedAcyclic_1.txt b/developer/documentđź–‰/GraphDirectedAcyclic_1.txt
deleted file mode 100644 (file)
index 7a202e2..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-  /*--------------------------------------------------------------------------------
-    Interface
-
-    1. nodes are referenced by label.
-
-    2. A list is a kind of sequence. It consists of a leftmost item, subsequent
-    items, and a rightmost item.
-
-    3. A node list consists of a leftmost node, subsequent nodes, and a rightmost node.
-
-    4. `path_stack`
-        
-        The `path_stack` is a list. Each item in the stack is a node list.
-
-        The rightmost items is the top of the stack.
-
-        The leftmost item is a list of root nodes, where traversal of the graph
-        starts.
-
-        Given two adjacent items on the path stack, say e0 and e1:
-
-            Say k0 is the leftmost node on the node list e0.
-            
-            The e1 will be the neighbor (child) list from node k0.
-
-            Hence, the path stack consists of the child lists of nodes along
-            a traversal. We chose a leftmost traversal.
-
-                e0:   k_0       k_1    ... k_2  
-
-                e1:   k_0_0    k_0_1   ... k_0_2   ; children of k_0
-
-                e2:   K_0_0_0  k_0_0_1 ... k_0_0_2 ; children of k_0_0
-                
-
-    5. `path`
-
-        A list of the leftmost nodes from a path stack.  
-
-        Given that e0 is a root node, `path` will consist of 
-
-            k_0, k_0_0, k_0_0_0 ... k_0_0..._0
-
-        Within the context of a path, k_0 is the leftmost item, and k_n is the
-        rightmost item.
-
-
-    6. removing a cycle
-
-       This is a build tool. Each node corresponds to a build objective, and the
-       neighbor nodes are dependencies. A neighbor node is a child node in our
-       tree descent, and is a dependency to our build tool.
-
-       This routine is called as part of the analysis phase. Nothing is
-       built here, rather we are merely marking dependency cycles that we
-       find when descending from the root nodes.
-
-       When we find a cycle, we remove those nodes from the current traversal
-       path, because we do not went the analysis to do in circles.  It is
-       possible that there are spurs that emanate from the cycle, and following
-       these might lead to finding more cycles.
-
-       Our build tool (which is not in this file) will stop descending through
-       the graph upon finding a cycle, and the effects of this will cause
-       upstream nodes to also not be built. Hence, the cycles hidden behind
-       other cycles are irrelevant.  
-
-       However, if we want to make routine of more general use, then the
-       discovered cycles should be pushed on to a cycle stack, and then each
-       item on the cycle stack would be used as root nodes for a new cycle
-       search. Note the leftmost cycle on each recursive search on the leftmost
-       node, will be the original cycle.
-  */
-
-  /*
-    Given a path to a node in the graph, `left_path`.
-
-    Checks if the rightmost node (referenced by label) recurs earlier in the path.
-    Presumably the rightmost node has been recently appended to the path.
-
-    If there is no cycle, returns null, otherwise returns the interval [i ,n],
-    of indexes into the path where the cycle is found. `n` will always be
-    the index of the rightmost node in the path list.
-  */
diff --git a/developer/documentđź–‰/dependency_graph.html b/developer/documentđź–‰/dependency_graph.html
deleted file mode 100644 (file)
index a728d42..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>Class and mature functions reference</title>
-  <style>
-    body {
-      font-family: 'Noto Sans JP', Arial, sans-serif;
-      background-color: hsl(0, 0%, 0%);
-      color: hsl(42, 100%, 80%);
-      padding: 2rem;
-    }
-    .page {
-      padding: 3rem; /* 20px */
-      margin: 1.25rem auto; /* 20px */
-      max-width: 46.875rem; /* 750px */
-      background-color: hsl(0, 0%, 0%);
-      box-shadow: 0 0 0.625rem hsl(42, 100%, 50%); /* 10px */
-    }
-    h1 {
-      font-size: 1.5rem;
-      text-align: center;
-      color: hsl(42, 100%, 84%);
-      text-transform: uppercase;
-      margin-top: 1.5rem;
-    }
-    h2 {
-      font-size: 1.25rem;
-      color: hsl(42, 100%, 84%);
-      text-align: center;
-      margin-top: 2rem;
-    }
-    h3 {
-      font-size: 1.125rem;
-      color: hsl(42, 100%, 75%);
-      margin-top: 1.5rem;
-    }
-    p, li {
-      color: hsl(42, 100%, 90%);
-      text-align: justify;
-      margin-bottom: 1rem;
-    }
-    .term {
-      font-family: 'Courier New', Courier, monospace;
-/*      background-color: hsl(0, 0%, 19%); */
-      padding: 0.125rem 0.25rem;
-      border-radius: 0.125rem;
-      text-decoration: underline;
-/*      font-style: italic;*/
-      color: hsl(42, 100%, 95%);
-    }
-    code {
-      font-family: 'Courier New', Courier, monospace;
-      background-color: hsl(0, 0%, 25%);
-      padding: 0.125rem 0.25rem;
-      color: hsl(42, 100%, 90%);
-    }
-
-    table {
-      border-collapse: collapse;
-      width: 100%;
-    }
-
-    tr {
-      page-break-inside: avoid;
-      page-break-after: auto;
-    }
-
-    th, td {
-      padding: 0.125rem;;
-/*      hsl(0, 0%, 86.7%) */
-      text-align: left;
-    }
-
-  </style>
-
-</head>
-<body>
-  <div class="page">
-
-    A very rough first draft of a reference to the classes.  
-
-    <h1>Cycle Detection on a Dependency Graph</h1>
-    <h2>Overview</h2>
-
-    <p>A <span class="term">Dependency Graph</span>: Is a directed acyclic graph
-    where non-leaf nodes are build targets, which are either symbolic, or
-    correspond to files in the file system. Leave nodes correspond to files
-    in the file system, and the only edge property is 'dependency'.</p>
-
-    <h2>Functions</h2>
-
-    <h3>1. is_acyclic_q</h3>
-    <p>
-      <strong>Purpose</strong>: To determine if the dependency graph is acyclovir.
-    </p>
-    <p>
-      <strong>Parameters</strong>: 
-      <ul>
-        <li><code>root_node_labels</code>: A list of labels for the root nodes to start the cycle search.</li>
-        <li><code>verbose</code>: A boolean flag for enabling detailed output (default is <code>true</code>).</li>
-      </ul>
-    </p>
-    <p>
-      <strong>Returns</strong>: 
-      <ul>
-        <li><code>'acyclic'</code> if no cycles are found.</li>
-        <li><code>'cycle_found'</code> if cycles are detected.</li>
-      </ul>
-    </p>
-    <p>
-      <strong>Process</strong>:
-      <ul>
-        <li>Initializes a stack for DFS traversal.</li>
-        <li>Iteratively calls the <code>is_acyclic_q_descend</code> function to traverse the graph and detect cycles.</li>
-        <li>Updates the traversal state and continues exploring other paths until the stack is empty.</li>
-      </ul>
-    </p>
-    <h3>2. is_acyclic_q_descend</h3>
-    <p>
-      <strong>Purpose</strong>: To perform the actual DFS traversal and cycle detection for a given path.
-    </p>
-    <p>
-      <strong>Parameters</strong>: 
-      <ul>
-        <li><code>path_stack</code>: A stack representing the current path in the graph.</li>
-        <li><code>verbose</code>: A boolean flag for enabling detailed output (default is <code>true</code>).</li>
-      </ul>
-    </p>
-    <p>
-      <strong>Returns</strong>: 
-      <ul>
-        <li><code>'leaf_node'</code> if the current node has no children.</li>
-        <li><code>'cycle_found'</code> if a cycle is detected.</li>
-      </ul>
-    </p>
-    <p>
-      <strong>Process</strong>:
-      <ul>
-        <li>Collects the current path and node.</li>
-        <li>Checks for cycles by comparing the current node with nodes in the path.</li>
-        <li>Marks nodes involved in cycles and updates the stack to continue traversal.</li>
-      </ul>
-    </p>
-    <h2>Usage</h2>
-    <p>
-      The <code>is_acyclic_q</code> function is used to ensure that the dependency graph defined in the build file is free of cycles. This is crucial for preventing infinite loops and ensuring that the build process can proceed smoothly.
-    </p>
-  </div>
-
-</body>
-</html>
diff --git a/developer/documentđź–‰/graph_print.html b/developer/documentđź–‰/graph_print.html
new file mode 100644 (file)
index 0000000..039ebc8
--- /dev/null
@@ -0,0 +1,327 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP&display=swap" rel="stylesheet">
+  <title>Tree Shell-Based Printout</title>
+  <style>
+    body {
+      font-family: 'Noto Sans JP', Arial, sans-serif;
+      background-color: hsl(0, 0%, 0%);
+      color: hsl(42, 100%, 80%);
+      padding: 2rem;
+    }
+    .page {
+      padding: 3rem;
+      margin: 1.25rem auto;
+      max-width: 46.875rem;
+      background-color: hsl(0, 0%, 0%);
+      box-shadow: 0 0 0.625rem hsl(42, 100%, 50%);
+    }
+    h1 {
+      font-size: 1.5rem;
+      text-align: center;
+      color: hsl(42, 100%, 84%);
+      text-transform: uppercase;
+      margin-top: 1.5rem;
+    }
+    h2 {
+      font-size: 1.25rem;
+      color: hsl(42, 100%, 84%);
+      text-align: center;
+      margin-top: 2rem;
+    }
+    h3 {
+      font-size: 1.125rem;
+      color: hsl(42, 100%, 75%);
+      margin-top: 1.5rem;
+    }
+    p, li {
+      color: hsl(42, 100%, 90%);
+      text-align: justify;
+      margin-bottom: 1rem;
+    }
+    code {
+      font-family: 'Courier New', Courier, monospace;
+      background-color: hsl(0, 0%, 25%);
+      padding: 0.125rem 0.25rem;
+      color: hsl(42, 100%, 90%);
+    }
+  </style>
+</head>
+<body>
+<div class="page">
+  <header>
+    <h1>Tree Shell-Based Printout</h1>
+    <p>Exploring the systematic traversal and printing of unbounded trees using shell concepts.</p>
+  </header>
+
+  <h2>Introduction</h2>
+
+  <p>The Ariadne Graph is generated from the `lookup` function. Hence for any traversal of the graph, we can not know the dimensions of the traversal tree. It can even be unbounded in depth or number of nodes at a given depth, i.e. breadth. This makes it challenging to print the graph.</p>
+
+  <h2>Grid Traversal Techniques</h2>
+  
+  <h3>Diagonal Shell Traversal</h3>
+  <p> A two dimensional grid is also open in two dimensions, but it can be reduced to a linear enumeration by viewing the quarter plain as a stack of
+    diagonal shells.</p>
+  <pre><code>n = x + y</code></pre>
+  <p>Points are then traversed shell-by-shell, starting from the top-left corner. For example:</p>
+  <p>(0,0), (0,1), (1,0), (2,0), (1,1), (0,2), ...</p>
+
+  <h3>Rectangular Shell Traversal</h3>
+  <p>An variation of the diagonal shell approach is the rectangular shell traversal, where shells cover all points within a rectangle defined by:</p>
+  <pre><code>max(x, y) = n</code></pre>
+  <p>Rectangular Shell Traversal fills out the n by n grid at each step. For example:</p>
+  <ul>
+    <li>Rectangular shell n=0: (0,0)</li>
+    <li>Rectangular shell n=1: (0,1), (1,0), (1,1)</li>
+    <li>Rectangular shell n=2: (0,2), (1,2), (2,2), (2,1), (2,0)</li>
+  </ul>
+
+  <h2>Mapping Trees to a Grid</h2>
+
+  <p>A node in a tree can also be given two co-ordinates, that of its depth
+    in the tree, and the node count from the left at that depth, which we
+    call its breadth, giving coordinates (d, b):</p>
+
+  <p>Then nodes on diagonal shell n satisfy the condition:</p>
+  <pre><code>d + b = n</code></pre>
+
+  <p>While those on rectangle shell n satisfy:</p>
+  <pre><code>max(d, b) = n</code></pre>
+  
+
+  <h3>Missing Topology</h3>
+
+  <p>On a two dimensional grid, each point has four distance one neighbors. when the grid nodes are enumerated on shells, each point will have two neighbors; however, we if need be, the other two neighbors can be identified through functions of the index into the enumeration.<p>
+
+  <p>When the nodes on the tree are enumerated, the parent connection information is lost.  As each node in the tree can have a different number of children, we can not compute this information from the enumeration index. However, node labels in the graph are unique, so we can annotate each
+    node in the enumeration with the name of its parent.</p>
+
+  <p>However, such annotations will not always reference nodes that have already been visited in the enumeration. I.e the enumeration does not
+    preserve forward referencing of parent nodes annotations.</p>
+
+  <h4>Example</h4>
+  <p>Consider this tree, subscripts being (d,b):</p>
+  <pre><code>
+                A(0,0)
+           /   /      \    \
+    B(1,0)  C(1,1)  D(1,2)  E(1,3)
+                           /  |   \
+                      F(2,0) G(2,1) H(2,2)
+  </code></pre>
+
+  <p>If printed successive rectangular shell per line:</p>
+  <ul>
+    <li>n=0: A</li>
+    <li>n=1: B(A) C(A)</li>
+    <li>n=2: D(A) F(E) G(E) H(E)
+    <li>n=3: E(A)
+  </ul>
+
+  <p>In this scenario, nodes like E(D), F(D), and G(D) reference their
+    parent D(A), but D(A) is found on the same line. If lower d values
+  are printed first, then </p>
+
+  <p>The same example using diagonal shells</p>
+
+  <p>Traversal using diagonal shells would produce the following order:</p>
+  <ul>
+    <li>n=0: A</li>
+    <li>n=1: B(A)</li>
+    <li>n=2: C(A) F(E)</li>
+    <li>n=3: D(A) G(E)</li>
+    <li>n=4: E(A) H(E)</li>
+  </ul>
+  <p>Note that on shell 3, G references parent E which is on shell 4.</p>
+
+  <h3>Another Example</h3>
+
+  <pre><code>
+         A
+      /  |  \
+     B   C   D
+    /|    \
+   E F     G
+         /   \
+        H     I
+  </code></pre>
+
+  <p>The following grid representation provides a structured view of the tree following the rectangular shell approach. When n is incremented, the grid can grow by a row and a column. 
+  <table>
+    <thead>
+      <tr>
+        <th>Label</th>
+        <th>(d, b) Coordinates</th>
+        <th>Rectangular Shell</th>
+        <th>Diagonal Shell</th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr>
+        <td>A</td>
+        <td>(0, 0)</td>
+        <td>0</td>
+        <td>0</td>
+      </tr>
+      <tr>
+        <td>B</td>
+        <td>(1, 0)</td>
+        <td>1</td>
+        <td>1</td>
+      </tr>
+      <tr>
+        <td>C</td>
+        <td>(1, 1)</td>
+        <td>1</td>
+        <td>2</td>
+      </tr>
+      <tr>
+        <td>D</td>
+        <td>(1, 2)</td>
+        <td>2</td>
+        <td>3</td>
+      </tr>
+      <tr>
+        <td>E</td>
+        <td>(2, 0)</td>
+        <td>2</td>
+        <td>2</td>
+      </tr>
+      <tr>
+        <td>F</td>
+        <td>(2, 1)</td>
+        <td>2</td>
+        <td>3</td>
+      </tr>
+      <tr>
+        <td>G</td>
+        <td>(2, 2)</td>
+        <td>2</td>
+        <td>4</td>
+      </tr>
+      <tr>
+        <td>H</td>
+        <td>(3, 0)</td>
+        <td>3</td>
+        <td>3</td>
+      </tr>
+      <tr>
+        <td>I</td>
+        <td>(3, 1)</td>
+        <td>3</td>
+        <td>4</td>
+      </tr>
+    </tbody>
+  </table>
+
+  <p>However such a grid cannot be directly printed to a stream.  It is a simple matter to add a row by emitting a new line character, but adding a column would require editing downstream data.</p>
+
+  <p>A grid or ASCII-art view of the tree can be generated from a
+    line per shell output stream, though a new diagram will be required
+    for each new line found on the stream.</p>
+
+  <p>Here is a streamable rectangular shell per line output for the
+    tree.</p>
+  <pre><code>
+  Shell 0: A
+  Shell 1: B(A) C(A)
+  Shell 2: D(A) E(B) F(B) G(C)
+  Shell 3: H(G) I(G)
+  </code></pre>
+
+  <p>And here it is as a diagonal shell per line.</p>
+  <pre><code>
+  Shell 0: A
+  Shell 1: B(A) 
+  Shell 2: C(A) E(B) 
+  Shell 3: D(A) F(B) H(G)
+  Shell 4: G(C) I(G)
+  </code></pre>
+
+  <p>Note in this latter example, node H on shell 3 refers to parent G, but
+  G is not output until the next line. This is an example of a forward referencing problem while using diagonal shells.</p>
+
+
+<!--
+
+    A node is
+    a) belongs to a child list of its parent
+    c) can have children
+
+
+    We keep two lists:
+    a) list_of__unopened_node
+    b) list_of__opened_incomplete_child_list
+
+    initially: 
+
+      print root node
+      if root node has children queue on list_of__unopened_node
+
+    At each step:
+
+    1.  each node on list_of__unopened_node
+
+      1.1. open(node) -> child_list
+      1.2. if not null, queue child_list list_of__opened_incomplete_child_list
+
+    2. each list on list_of__opened_incomplete_child_list
+
+      2.1 yield node from list
+      2.2 on list empty, dequeue list
+      2.3 print node
+      2.4 if node has child list -> queue node on list_of__unopened_node
+
+
+
+    -->
+    
+<h2>Algorithm 3: Unbounded Graph Iteration Without Forward Referencing</h2>
+<p>
+This algorithm avoids forward referencing by ensuring that nodes are processed along with their child lists in a structured manner. It uses two lists to manage nodes:
+</p>
+<ul>
+  <li><strong>list_of__unopened_node</strong>: Nodes that have not yet been processed to discover their child lists.</li>
+  <li><strong>list_of__opened_incomplete_child_list</strong>: Partially processed child lists of nodes.</li>
+</ul>
+
+<h3>Initial Setup</h3>
+<p>
+1. Print the root node.
+2. If the root node has children, add its child list to <code>list_of__unopened_node</code>.
+</p>
+
+<h3>Iteration Steps</h3>
+<p>At each step:</p>
+<ul>
+  <li>
+    For each node in <code>list_of__unopened_node</code>:
+    <ul>
+      <li>Open the node to retrieve its child list.</li>
+      <li>If the child list is not null, add it to <code>list_of__opened_incomplete_child_list</code>.</li>
+    </ul>
+  </li>
+  <li>
+    For each child list in <code>list_of__opened_incomplete_child_list</code>:
+    <ul>
+      <li>Yield a node from the list (one at a time).</li>
+      <li>If the list becomes empty, remove it from <code>list_of__opened_incomplete_child_list</code>.</li>
+      <li>Print the node.</li>
+      <li>If the node has its own child list, add it to <code>list_of__unopened_node</code>.</li>
+    </ul>
+  </li>
+</ul>
+
+<h3>End Condition</h3>
+<p>
+The process ends when both <code>list_of__unopened_node</code> and <code>list_of__opened_incomplete_child_list</code> are empty, ensuring all nodes are processed without forward referencing issues.
+</p>
+
+
+
+</div>
+</body>
+</html>
diff --git a/developer/example/CountingNumber.class b/developer/example/CountingNumber.class
new file mode 100644 (file)
index 0000000..a4fa5c6
Binary files /dev/null and b/developer/example/CountingNumber.class differ
diff --git a/developer/example/CountingNumber.java b/developer/example/CountingNumber.java
new file mode 100644 (file)
index 0000000..579049e
--- /dev/null
@@ -0,0 +1,45 @@
+import com.ReasoningTechnology.Ariadne.Ariadne_SRM;
+import com.ReasoningTechnology.Ariadne.Ariadne_Test;
+import java.math.BigInteger;
+
+public class CountingNumber extends Ariadne_SRM<BigInteger>{
+
+  private static final Ariadne_Test test = Ariadne_Test.make("Ariadne_SRM<BigInteger>::");
+
+  public static CountingNumber make(){
+    return new CountingNumber();
+  }
+
+  private BigInteger i;
+
+  protected CountingNumber(){
+    super();
+    i = BigInteger.ZERO;
+    test.print("CountingNumber read() value initialized to: " + i);
+  }
+
+  @Override
+  public Topology topology(){
+    return Topology.INFINITE_RIGHT; // leftmost, no rightmost
+  }
+
+  @Override
+  public Status status(){
+    if( i.equals(BigInteger.ZERO) ) return Status.AT_LEFTMOST;
+    else return Status.AT_MIDWAY;
+  }
+  
+  @Override
+  public BigInteger read(){
+    return i;  // note that BigInteger is immutable
+  }
+
+  @Override
+  public boolean step(){
+    i = i.add(BigInteger.ONE);
+    test.print(" after step right new read() value: " + i);
+    return true;
+  }
+
+}
+
diff --git a/developer/example/Example_Ariadne_SRM b/developer/example/Example_Ariadne_SRM
new file mode 100755 (executable)
index 0000000..dadbafc
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+java Example_Ariadne_SRM
diff --git a/developer/example/Example_Ariadne_SRM.class b/developer/example/Example_Ariadne_SRM.class
new file mode 100644 (file)
index 0000000..ed6f5d6
Binary files /dev/null and b/developer/example/Example_Ariadne_SRM.class differ
diff --git a/developer/example/Example_Ariadne_SRM.java b/developer/example/Example_Ariadne_SRM.java
new file mode 100644 (file)
index 0000000..e7a4e28
--- /dev/null
@@ -0,0 +1,20 @@
+import java.math.BigInteger;
+
+public class Example_Ariadne_SRM {
+
+  public static void main(String[] args) {
+    CountingNumber counting_number = CountingNumber.make();
+
+    System.out.println("Initial Status: " + counting_number.status());
+    System.out.println("Initial Read Value: " + counting_number.read());
+
+    for( int step_index = 0 ;step_index < 10 ;step_index++ ){
+      counting_number.step();
+      System.out.println(
+        "Step: " + step_index 
+       +", Status: " + counting_number.status()
+       +", Read Value: " + counting_number.read()
+      );
+    }
+  }
+}
diff --git a/developer/javacđź–‰/#Ariadne_Node.xjava# b/developer/javacđź–‰/#Ariadne_Node.xjava#
new file mode 100644 (file)
index 0000000..d2d55b4
--- /dev/null
@@ -0,0 +1,50 @@
+package com.ReasoningTechnology.Ariadne;
+import java.util.HashMap;
+import java.util.HashSet;
+
+public class Ariadne_Node extends HashMap<String, Object>{
+
+  // owned by the class
+  //
+  public static Ariadne_Node make(Ariadne_Label label){
+    return new Ariadne_Node(label);
+  }
+
+  // data owned by the instance
+  //
+  private Ariadne_Label label;
+  private HashSet<Ariadne_Label> mark_set;
+
+  // constructors
+  //
+  public Ariadne_Node(Ariadne_Label label){
+    super();
+    this.label = label;
+    this.market_set = new HashSet<Ariadne_Label>;
+  }
+
+  // instance interface
+  //
+  public Ariadne_Label label(){
+    return this.label;
+  }
+
+  public Ariadne_StepRightMachine<Ariadne_Label> neighbor_set(); 
+
+  public void mark(Ariadne_Token token){
+    mark_set.add(token);
+  }
+
+  public boolean has_mark(Ariadne_Token token){
+    return mark_set.contains(token);
+  }
+
+  public Ariadne_LabelList neighbor(){
+    return(Ariadne_LabelList) this.get(neighbor_property_name);
+  }
+
+  // Object interface
+  //
+
+
+}
diff --git a/developer/javacđź–‰/Ariadne_DirectedGraph.xjava b/developer/javacđź–‰/Ariadne_DirectedGraph.xjava
new file mode 100644 (file)
index 0000000..941d935
--- /dev/null
@@ -0,0 +1,26 @@
+package com.ReasoningTechnology.Ariadne;
+
+/*
+  To define a graph, extend this class and define `lookup`.
+
+  For a wellformed graph, each start label will be a label for a node found in the graph.
+*/
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+package com.ReasoningTechnology.Ariadne;
+
+public class Ariadne_Graph{
+
+  public static Ariadne_DirectedGraph make(Object...obj_list){
+    return new Ariadne_DirectedGraph();
+  }
+
+  public Ariadne_StepRightMachine<Ariadne_Node> start();
+  public Ariadne_StepRightMachine<Ariadne_Node> traverse();
+  public Ariadne_Node lookup(String label);
+
+
+}
diff --git a/developer/javacđź–‰/Ariadne_File.java b/developer/javacđź–‰/Ariadne_File.java
deleted file mode 100644 (file)
index 825b499..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.ReasoningTechnology.Ariadne;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class Ariadne_File {
-  static boolean debug = false;
-
-  public static Map<String, String> unpack_file_path(String file_fp) {
-    if (debug) System.out.println("unpack_file_path::file_fp: " + file_fp);
-
-    // Use java.io.File explicitly to avoid conflict with the custom Ariadne_File class
-    java.io.File file = new java.io.File(file_fp);
-    String parent_dp = (file.getParent() != null) ? file.getParent() : "";
-
-    if (!parent_dp.isEmpty() && !parent_dp.endsWith(java.io.File.separator)) {
-      parent_dp += java.io.File.separator;
-    }
-
-    String file_fn = file.getName();
-    String file_fn_base = file_fn;
-    String file_fn_ext = "";
-
-    int last_index = file_fn.lastIndexOf('.');
-    if (last_index > 0) {
-      file_fn_base = file_fn.substring(0, last_index);
-      if (last_index + 1 < file_fn.length()) {
-        file_fn_ext = file_fn.substring(last_index + 1);
-      }
-    }
-
-    Map<String, String> ret_val = new HashMap<>();
-    ret_val.put("dp", parent_dp);
-    ret_val.put("fn", file_fn);
-    ret_val.put("fn_base", file_fn_base);
-    ret_val.put("fn_ext", file_fn_ext);
-
-    if (debug) System.out.println("unpack_file_path::ret_val: " + ret_val);
-
-    return ret_val;
-  }
-
-  public static boolean file_exists_q(String fp_string) {
-    Path fp_object = Paths.get(fp_string);
-    return Files.exists(fp_object);
-  }
-
-  /*
-    Given a target_fp and a list of dependency_fp.
-
-    Returns false if the target is newer than all dependencies or if a file is missing;
-    otherwise, returns true.
-  */
-  public static boolean newer_than_all(String target_fp_string, List<String> dependency_fp_list) throws IOException {
-    Path target_fp_object = Paths.get(target_fp_string);
-    if (!Files.exists(target_fp_object)) return false;
-
-    long target_last_modified_time = Files.getLastModifiedTime(target_fp_object).toMillis();
-
-    return dependency_fp_list.stream().allMatch(dependency_fp -> {
-      try {
-        Path dependency_fp_object = Paths.get(dependency_fp);
-        if (!Files.exists(dependency_fp_object)) return false;
-        long dependency_last_modified_time = Files.getLastModifiedTime(dependency_fp_object).toMillis();
-        return target_last_modified_time > dependency_last_modified_time;
-      } catch (IOException e) {
-        return false;
-      }
-    });
-  }
-}
index 6b54394..c91114d 100644 (file)
@@ -1,73 +1,18 @@
 package com.ReasoningTechnology.Ariadne;
 
-import java.util.HashMap;
-import java.util.Map;
+/*
+  To define a graph, extend this class and define `start` and `lookup`.
 
-public class Ariadne_Graph{
+  For a wellformed graph, each start label will be a label for a node found in the graph.
+*/
 
-  // Test messaging
-  //
-    private static boolean test = false;
-    public static void test_switch(boolean test){
-      if (Ariadne_Graph.test && !test){
-        test_print("Ariadne_Graph:: test messages off");
-      }
-      if (!Ariadne_Graph.test && test){
-        test_print("Ariadne_Graph:: test messages on");
-      }
-    }
-    private static void test_print(String message){
-      if(test){
-        System.out.println(message);
-      }
-    }
+public interface Ariadne_Graph{
 
-  // Class data (static data)
-  //
+  public static Ariadne_Graph make(Object...obj_list){
+    return new Ariadne_Graph();
+  }
 
-
-  // Instance data and access
-  //
-    private Map<Ariadne_Label, Ariadne_Node> node_map;
-    private Ariadne_ProductionList recognizer_f_list;
-
-  // Constructors
-  //
-    public Ariadne_Graph(Map<Ariadne_Label, Ariadne_Node> node_map, Ariadne_ProductionList recognizer_f_list){
-      if (node_map == null && recognizer_f_list == null){
-        System.err.println("Ariadne_Graph: At least one of 'node_map' (Map) or 'recognizer_f_list' (List) must be provided.");
-        System.exit(1);
-      }
-
-      // Initialize each of node_map and recognizer_f_list to empty collections if null
-      this.node_map = (node_map != null) ? node_map : new HashMap<>();
-      this.recognizer_f_list = (recognizer_f_list != null) ? recognizer_f_list : new Ariadne_ProductionList();
-    }
-
-  // Interface methods
-  //
-
-    // Lookup by label
-    public Ariadne_Node lookup(Ariadne_Label node_label){
-      if (node_label == null || node_label.isEmpty()){
-        if (verbose){
-          System.out.println("lookup:: given node_label is null or empty.");
-        }
-        return null;
-      }
-
-      // Try to retrieve the node from the map
-      Ariadne_Node node = this.node_map.get(node_label);
-
-      if(test)
-        if(node == null) test_print("lookup:: node not found for label: " + node_label);
-        else test_print("lookup:: found node: " + node);
-
-      return node;
-    }
-
-  // standard interface
-  //
-  // need a toString ...
+  public Ariadne_SRM<Ariadne_Label> start();
+  public Ariadne_Node lookup(String label);
 
 }
diff --git a/developer/javacđź–‰/Ariadne_GraphDirectedAcyclic.java b/developer/javacđź–‰/Ariadne_GraphDirectedAcyclic.java
deleted file mode 100644 (file)
index 948dc47..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-package com.ReasoningTechnology.Ariadne;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.List;
-import java.util.ArrayList;
-
-public class Ariadne_GraphDirectedAcyclic extends Ariadne_Graph {
-
-  /*--------------------------------------------------------------------------------
-    Constructors
-  */
-
-  public Ariadne_GraphDirectedAcyclic() {
-    super(new HashMap<>(), null);
-  }
-
-  public Ariadne_GraphDirectedAcyclic(Map<Ariadne_Label, Ariadne_Node> node_map, Ariadne_ProductionList recognizer_f_list, Ariadne_LabelList root_node_list, int max_depth, boolean verbose) {
-    super(node_map, recognizer_f_list);
-    Ariadne_TokenSet cycle_detection_result = graph_mark_cycles(root_node_list, max_depth, verbose);
-  }
-
-  public Ariadne_GraphDirectedAcyclic(Map<Ariadne_Label, Ariadne_Node> node_map, Ariadne_ProductionList recognizer_f_list, Ariadne_LabelList root_node_list) {
-    super(node_map, recognizer_f_list);
-    Ariadne_TokenSet cycle_detection_result = graph_mark_cycles(root_node_list);
-  }
-
-  /*--------------------------------------------------------------------------------
-    Instance Data Extension
-  */
-
-  private static boolean debug = true;
-
-  /*--------------------------------------------------------------------------------
-    Interface
-  */
-
-  private List<Integer> path_find_cycle(Ariadne_LabelList path) {
-    if (path.size() <= 1) return null;
-
-    int rightmost_index = path.size() - 1;
-    Ariadne_Label rightmost_node_label = path.get(rightmost_index);
-
-    int cycle_leftmost_index = path.indexOf(rightmost_node_label);
-    Boolean has_cycle = cycle_leftmost_index < rightmost_index;
-    if (!has_cycle) return null;
-
-    List<Integer> result = new ArrayList<>();
-    result.add(cycle_leftmost_index);
-    result.add(rightmost_index);
-    return result;
-  }
-
-  private boolean graph_descend_cycle_case(Ariadne_LabelList left_path, List<Ariadne_LabelList> path_stack, boolean verbose) {
-
-    List<Integer> cycle_index_interval = path_find_cycle(left_path);
-    if (cycle_index_interval == null) {
-      return false;
-    }
-
-    int cycle_i0 = cycle_index_interval.get(0);
-    int cycle_n = cycle_index_interval.get(1);
-
-    if (verbose) Ariadne_Util.print_list(
-      "Found cycle:", 
-      left_path.subList(cycle_i0, cycle_n + 1)
-    );
-
-    Ariadne_LabelList undefined_node_list = new Ariadne_LabelList();
-    for (int i = cycle_i0; i <= cycle_n; i++) {
-      Ariadne_Label node_label = left_path.get(i);
-      Ariadne_Node node = super.lookup(node_label);
-      if (node != null) {
-        node.mark(new Ariadne_Token("cycle_member"));
-      } else {
-        undefined_node_list.add(node_label);
-      }
-    }
-
-    if (verbose) Ariadne_Util.print_list(
-      "Each undefined node could not be marked as a cycle member:", 
-      undefined_node_list
-    );
-
-    path_stack.subList(cycle_i0 + 1, cycle_n + 1).clear();
-
-    return true;
-  }
-
-  private static Ariadne_TokenSet graph_descend_set = new Ariadne_TokenSet() {{
-    add(new Ariadne_Token("empty_path_stack"));
-    add(new Ariadne_Token("cycle_found"));
-    add(new Ariadne_Token("undefined_node"));
-    add(new Ariadne_Token("leaf"));
-    add(new Ariadne_Token("max_depth_reached"));
-  }};
-
-  private Ariadne_TokenSet graph_descend(List<Ariadne_LabelList> path_stack, int max_depth, boolean verbose) {
-    Ariadne_TokenSet ret_value = new Ariadne_TokenSet();
-
-    if (path_stack.isEmpty()) {
-      ret_value.add(new Ariadne_Token("empty_path_stack"));
-      return ret_value;
-    }
-
-    Ariadne_LabelList left_path = new Ariadne_LabelList();
-    for (Ariadne_LabelList neighbor_list : path_stack) {
-      left_path.add(neighbor_list.get(0));
-    }
-
-    do {
-
-      if (graph_descend_cycle_case(left_path, path_stack, verbose)) {
-        ret_value.add(new Ariadne_Token("cycle_found"));
-        return ret_value;
-      }
-
-      Ariadne_Label it_node_label = path_stack.get(path_stack.size() - 1).get(0);
-      Ariadne_Node it_node = super.lookup(it_node_label);
-      if (it_node == null) {
-        ret_value.add(new Ariadne_Token("undefined_node"));
-        return ret_value;
-      }
-        
-      Ariadne_LabelList neighbor_list = it_node.neighbor_LabelList();
-      if (neighbor_list.isEmpty()) {
-        ret_value.add(new Ariadne_Token("leaf"));
-        return ret_value;
-      }
-
-      path_stack.add(new Ariadne_LabelList(neighbor_list));
-      Ariadne_Label it_next_label = neighbor_list.get(0);
-      left_path.add(it_next_label);
-
-      if (max_depth > 0) {
-        max_depth--;
-        if (max_depth == 0) {
-          if (verbose) {
-            Ariadne_Util.print_list("GraphDirectedAcyclic.GraphDescend:: max_depth reached, ending descent:", path_stack);
-          }
-          ret_value.add(new Ariadne_Token("max_depth_reached"));
-          return ret_value;
-        }
-      }
-
-    } while (true);
-  }
-
-  public static Ariadne_TokenSet graph_mark_cycles_set = new Ariadne_TokenSet() {{
-    add(new Ariadne_Token("empty_root_label_list"));
-    add(new Ariadne_Token("cycle_exists"));
-    add(new Ariadne_Token("undefined_node_exists"));
-    add(new Ariadne_Token("bad_descent_termination"));
-    add(new Ariadne_Token("max_depth_reached"));
-  }};
-
-  public Ariadne_TokenSet graph_mark_cycles(Ariadne_LabelList root_node_LabelList, int max_depth, boolean verbose) {
-    Ariadne_TokenSet ret_value = new Ariadne_TokenSet();
-    boolean exists_malformed = false;
-    Ariadne_TokenSet result;
-
-    if (root_node_LabelList.isEmpty()) {
-      ret_value.add(new Ariadne_Token("empty_root_label_list"));
-      return ret_value;
-    }
-
-    List<Ariadne_LabelList> path_stack = new ArrayList<>();
-    path_stack.add(new Ariadne_LabelList(root_node_LabelList));
-
-    do {
-      result = graph_descend(path_stack, max_depth, verbose);
-      if (result.contains(new Ariadne_Token("cycle_found"))) ret_value.add(new Ariadne_Token("cycle_exists"));
-      if (result.contains(new Ariadne_Token("undefined_node"))) ret_value.add(new Ariadne_Token("undefined_node_exists"));
-      if (result.contains(new Ariadne_Token("max_depth_reached"))) ret_value.add(new Ariadne_Token("max_depth_reached"));
-      if (!result.contains(new Ariadne_Token("leaf")) && !result.contains(new Ariadne_Token("cycle_found"))) ret_value.add(new Ariadne_Token("bad_descent_termination"));
-
-      Ariadne_LabelList top_list = path_stack.get(path_stack.size() - 1);
-      top_list.remove(0);
-      if (top_list.isEmpty()) path_stack.remove(path_stack.size() - 1);
-
-    } while (!path_stack.isEmpty());
-
-    if (verbose) {
-      if (ret_value.contains("bad_descent_termination")) {
-        System.out.println("GraphDirectedAcyclic.graph_mark_cycles:: terminated with unexpected condition.");
-      }
-      if (ret_value.contains("cycle_exists")) {
-        System.out.println("GraphDirectedAcyclic.graph_mark_cycles:: One or more cycles detected.");
-      }
-      if (ret_value.contains("undefined_node_exists")) {
-        System.out.println("GraphDirectedAcyclic.graph_mark_cycles:: Undefined nodes exist.");
-      }
-    }
-
-    return ret_value;
-  }
-
-  public Ariadne_TokenSet graph_mark_cycles(Ariadne_LabelList root_node_LabelList) {
-    return graph_mark_cycles(root_node_LabelList, this.debug ? 40 : -1, this.debug);
-  }
-
-  @Override
-  public Ariadne_Node lookup(Ariadne_Label node_label, boolean verbose) {
-    Ariadne_Node node = super.lookup(node_label, verbose);
-    if (node != null && node.has_mark(new Ariadne_Token("cycle_member"))) {
-      if (verbose) {
-        System.out.println("GraphDirectedAcyclic.lookup:: Node is part of a cycle, not returned: " + node_label);
-      }
-      return null;
-    }
-    return node;
-  }
-
-  public Ariadne_Node lookup(Ariadne_Label node_label) {
-    return lookup(node_label, this.debug);
-  }
-
-}
index 9f10fcb..c97f0a3 100644 (file)
@@ -1,5 +1,7 @@
 package com.ReasoningTechnology.Ariadne;
 
+
+
 /*
   A value for the node.label property.
 
@@ -8,18 +10,27 @@ package com.ReasoningTechnology.Ariadne;
 
 */
 public class Ariadne_Label{
-  private final String value;
 
-  public Ariadne_Label(String value){
-    this.value = value;
+  // owned by class
+
+
+  // data owned by instance
+
+    private final String value;
+
+  // constructors
+
+
+  private Ariadne_Label(String s){
+    this.value = s;
   }
 
-  public boolean isEmpty(){
-    return value.isEmpty();
+  Ariadne_Label make(String s){
+    return  new Ariadne_Label(s);
   }
 
-  public String get(){
-    return value;
+  public boolean isEmpty(){
+    return value.isEmpty();
   }
 
   @Override
@@ -39,4 +50,5 @@ public class Ariadne_Label{
   public int hashCode(){
     return value.hashCode();
   }
+
 }
diff --git a/developer/javacđź–‰/Ariadne_LabelList.java b/developer/javacđź–‰/Ariadne_LabelList.java
deleted file mode 100644 (file)
index ae2dd0b..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// LabelList.java
-package com.ReasoningTechnology.Ariadne;
-import java.util.List; 
-import java.util.ArrayList;
-
-public class Ariadne_LabelList extends ArrayList<Ariadne_Label>{
-  // Constructor
-  public Ariadne_LabelList(){
-    super();
-  }
-  public Ariadne_LabelList(List<Ariadne_Label> labels){
-    super();  // Initialize the parent class
-    if(labels != null){
-      this.addAll(labels);  // Copy all elements from the provided list
-    }
-  }
-
-}
diff --git a/developer/javacđź–‰/Ariadne_LabelList.xjava b/developer/javacđź–‰/Ariadne_LabelList.xjava
new file mode 100644 (file)
index 0000000..6b2c3e0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+A list of Labels.
+*/
+
+package com.ReasoningTechnology.Ariadne;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class Ariadne_LabelList extends ArrayList<Ariadne_Label>{
+
+  // owned by the class
+  //
+    public static Ariadne_LabelList make(Object...label_list){
+      return new Ariadne_LabelList(label_list);
+    }
+
+  // data owned by the instance
+  //
+
+  // constructors
+  //
+    public Ariadne_LabelList(Object...label_list){
+      super();
+      if(label_list != null){
+        this.add(List.of(label_list)); // Delegate work to the add method
+      }
+    }
+
+  // instance interface
+  //
+    public boolean add(Object...obj_list){
+      boolean modified = false;
+      if(obj_list != null) for(Object obj:obj_list) modified |= add_one(obj);
+      return modified;
+    }
+
+  // Object interface
+  //
+    @Override
+    public String toString(){
+      return super.toString();
+    }
+
+  // private helpers
+  //
+    private boolean add_one(Object obj){
+      if(obj instanceof String){
+        return add_one((String) obj);
+      }else if(obj instanceof Ariadne_Label){
+        return add_one((Ariadne_Label) obj);
+      }
+      throw new IllegalArgumentException(
+        "Ariadne_LabelList::add_one, cannot make label from object of type: " + obj.getClass().getName()
+      );
+    }
+
+    private boolean add_one(String string){
+      return super.add(Ariadne_Label.make(string));
+    }
+
+    private boolean add_one(Ariadne_Label label){
+      return super.add(label);
+    }
+}
+
+
index 0c49ac2..fac11d5 100644 (file)
@@ -1,30 +1,50 @@
 package com.ReasoningTechnology.Ariadne;
 import java.util.HashMap;
+import java.util.HashSet;
 
 public class Ariadne_Node extends HashMap<String, Object>{
 
-  private static String mark_property_name = "mark";
-  private static String neighbor_property_name = "neighbor";
+  // owned by the class
+  //
+  public static Ariadne_Node make(Ariadne_Label label){
+    return new Ariadne_Node(label);
+  }
+
+  // data owned by the instance
+  //
+  private Ariadne_Label label;
+  private HashSet<Ariadne_Label> mark_set;
 
-  public Ariadne_Node(){
+  // constructors
+  //
+  public Ariadne_Node(Ariadne_Label label){
     super();
-    this.put(neighbor_property_name, new Ariadne_LabelList());
+    this.label = label;
+    this.market_set = new HashSet<Ariadne_Label>;
+  }
+
+  // instance interface
+  //
+  public Ariadne_Label label(){
+    return this.label;
   }
 
+  public Ariadne_StepRightMachine<Ariadne_Label> neighbor_set();
+
   public void mark(Ariadne_Token token){
-    if(this.get(mark_property_name) == null){
-      this.put(mark_property_name, new Ariadne_TokenSet());
-    }
-    ((Ariadne_TokenSet) this.get(mark_property_name)).add(token);
+    mark_set.add(token);
   }
 
   public boolean has_mark(Ariadne_Token token){
-    Ariadne_TokenSet mark =(Ariadne_TokenSet) this.get(mark_property_name);
-    return mark != null && mark.contains(token);
+    return mark_set.contains(token);
   }
 
-  public Ariadne_LabelList neighbor_LabelList(){
+  public Ariadne_LabelList neighbor(){
     return(Ariadne_LabelList) this.get(neighbor_property_name);
   }
 
+  // Object interface
+  //
+
+
 }
diff --git a/developer/javacđź–‰/Ariadne_NodeList.java b/developer/javacđź–‰/Ariadne_NodeList.java
deleted file mode 100644 (file)
index 69e4284..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// NodeList.java
-package com.ReasoningTechnology.Ariadne;
-import java.util.ArrayList;
-
-public class Ariadne_NodeList extends ArrayList<Ariadne_Node> {
-  // Constructor
-  public Ariadne_NodeList(){
-    super();
-  }
-}
diff --git a/developer/javacđź–‰/Ariadne_NodeList.xjava b/developer/javacđź–‰/Ariadne_NodeList.xjava
new file mode 100644 (file)
index 0000000..69e4284
--- /dev/null
@@ -0,0 +1,10 @@
+// NodeList.java
+package com.ReasoningTechnology.Ariadne;
+import java.util.ArrayList;
+
+public class Ariadne_NodeList extends ArrayList<Ariadne_Node> {
+  // Constructor
+  public Ariadne_NodeList(){
+    super();
+  }
+}
diff --git a/developer/javacđź–‰/Ariadne_Production.java b/developer/javacđź–‰/Ariadne_Production.java
deleted file mode 100644 (file)
index ab6aed9..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// Production.java
-package com.ReasoningTechnology.Ariadne;
-import java.util.function.Function;
-
-public interface Ariadne_Production extends Function<Ariadne_Label, Ariadne_Node> {}
diff --git a/developer/javacđź–‰/Ariadne_ProductionList.java b/developer/javacđź–‰/Ariadne_ProductionList.java
deleted file mode 100644 (file)
index 03b2461..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// ProductionList.java
-package com.ReasoningTechnology.Ariadne;
-import java.util.ArrayList;
-
-public class Ariadne_ProductionList extends ArrayList<Ariadne_Production> {
-  // Constructor
-  public Ariadne_ProductionList(){
-    super();
-  }
-}
diff --git a/developer/javacđź–‰/Ariadne_SRM.java b/developer/javacđź–‰/Ariadne_SRM.java
new file mode 100644 (file)
index 0000000..a2aee82
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  A 'tape' as a model for computation is a sequence of cells, where something can be written or read from each cell. We talk about the sequence as though written on paper, running from left to right.  The elements in the sequence have neighbors, so the sequence of cells can be said to be mutually connected. This is to say that if cell B is to the right of cell A in the sequence, then cell A is to the left of cell B; Also if cell A is to the left of cell B, then cell B is to the right of cell A.
+
+  One of the cells on the tape is specially marked as being the 'mounted cell'. This is the cell that can be written or read after the tape is mounted on a 'tape machine', and before any steps have been taken. 
+
+  Information from the `topology` method will remain valid for as long as the topology of
+  the tape is not modified.  
+
+  A finite tape will have a leftmost cell, which has no left neighbor, and a rightmost cell, which has no right neighbor. All other cells will have two neighbors.
+
+  A tape can have an infinite number of cells to the left of the mount point, to the right of the mount point, or in both directions. Hence it is possible that two, one, or zero cells on a tape have only one neighbor, where the zero neighbor case is for finite tapes, and the latter cases are for infinite tapes.
+
+  An algorithm running on a tape machine that has a left going tape can be translated into an algorithm for a right going tape simply by swapping `step_right` for `step_left`. Hence there is no utility to be had by keeping both models.
+
+  Another isomorphism can be setup between a single ended tape and a double direction tape by replacing each step by two steps, and then placing odd cell into correspondence with the right going tape, and even cells with left going tape.  Hence an algorithm implemented over the top of either can be mechanically transformed to an algorithm for the other.
+
+  However, what we can not do without affecting the power of our computation machine is to
+  eliminate 'step-left', yet this is a common simplification in data structures. The Lisp language is based on single linked lists for example.
+
+  This 'Step Right Machine' (SRM) defined here can only be stepped to the right. Thus whether cells are mutually connected, or not, becomes irrelevant.  Also, saying 'leftmost' is a feature of the tape, becomes muddled, as the mount point cell will be the leftmost cell that is ever visited.
+
+  A SRM can be defined using functions, or it can be used as an iterator for traversing through a container.
+
+  The property methods defined here are kept general so that they can be used with other tape machines.
+*/
+
+package com.ReasoningTechnology.Ariadne;
+
+public class Ariadne_SRM<T>{
+
+  // Enum for Tape Topology
+  public enum Topology{
+    NO_CELLS
+    ,SEGMENT
+    ,CIRCLE
+    ,INFINITE_RIGHT
+    ,INFINITE_LEFT
+    ,INFINITE
+    ,UNKNOWN
+    ,UNDEFINED
+    ;
+  }
+
+  // Enum for Machine Status
+  public enum Status{
+    TAPE_NOT_MOUNTED
+    ,AT_LEFTMOST
+    ,AT_MIDWAY
+    ,AT_RIGHTMOST
+    ;
+  }
+
+  public static <T> Ariadne_SRM<T> make(){
+    return new Ariadne_SRM<>();
+  }
+  protected Ariadne_SRM(){}
+
+  public Topology topology(){
+    return Topology.UNDEFINED; // Default topology
+  }
+
+  public Status status(){
+    return Status.TAPE_NOT_MOUNTED; // Default status
+  }
+
+  public T read(){
+    throw new UnsupportedOperationException("Ariadne_SRM::can't read unmounted tape.");
+  }
+
+  public boolean step(){
+    throw new UnsupportedOperationException("Ariadne_SRM::can't step unmounted tape.");
+  }
+}
diff --git a/developer/javacđź–‰/Ariadne_SRMI.java b/developer/javacđź–‰/Ariadne_SRMI.java
new file mode 100644 (file)
index 0000000..60ec791
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+Ariadne_SRM with index
+
+*/
+
+package com.ReasoningTechnology.Ariadne;
+import java.math.BigInteger;
+
+public class Ariadne_SRMI<T> extends Ariadne_SRM<T>{
+
+  private BigInteger index;
+
+  public static <T> Ariadne_SRMI<T> make(){
+    return new Ariadne_SRMI<T>();
+  }
+  protected Ariadne_SRMI(){
+    super();
+    index = BigInteger.ZERO;;
+  }
+
+  @Override
+  public boolean step(){
+    throw new UnsupportedOperationException("Ariadne_SRMI::can't step unmounted tape.");
+    // index.add(BigInteger.ONE);
+  }
+
+  BigInteger index(){return index;}
+  BigInteger leftmost_index(){
+    return BigInteger.ZERO;
+  }
+  BigInteger rightmost_index(){
+    throw new UnsupportedOperationException("Ariadne_SRMI:: rightmost_index() of undefined.");
+  }
+
+}
diff --git a/developer/javacđź–‰/Ariadne_Test.java b/developer/javacđź–‰/Ariadne_Test.java
new file mode 100644 (file)
index 0000000..5ce6637
--- /dev/null
@@ -0,0 +1,32 @@
+package com.ReasoningTechnology.Ariadne;
+
+public class Ariadne_Test {
+
+  private boolean test = false;
+  private String prefix = "";
+
+  public static Ariadne_Test make(String prefix){
+    Ariadne_Test instance = new Ariadne_Test();
+    instance.prefix = prefix;
+    return instance;
+  }
+
+  protected Ariadne_Test(){
+  }
+
+  public void switch_test(boolean enable){
+    if( test && !enable ){
+      print("test messages off");
+    }
+    if( !test && enable ){
+      print("test messages on");
+    }
+    test = enable;
+  }
+
+  public void print(String message){
+    if( test ){
+      System.out.println(prefix + message);
+    }
+  }
+}
diff --git a/developer/javacđź–‰/Build.javax b/developer/javacđź–‰/Build.javax
deleted file mode 100644 (file)
index b0cdab3..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-import java.util.List;
-
-public class Build {
-
-    // Function to load the graph class dynamically
-    public static Class<?> includeAClass(String aClassFp) {
-        ClassLoader classLoader = Build.class.getClassLoader();
-        String className = aClassFp.replace('/', '.').replace(".class", "");
-        try {
-            return classLoader.loadClass(className);
-        } catch (Exception e) {
-            System.out.println("Error loading class '" + className + "': " + e.getMessage());
-            return null;
-        }
-    }
-
-    // Build function
-    public static void build(String graphDefinitionFp, List<String> rootNodeLabels) {
-        // Print summary of what we are doing
-        System.out.println("build:: Building targets for graph '" + graphDefinitionFp + ".class'");
-        if (rootNodeLabels.isEmpty()) {
-            System.out.println("No build targets specified. Please provide root node labels to build.");
-            System.exit(0);
-        }
-        System.out.println("Building targets: " + String.join(", ", rootNodeLabels));
-
-        // Load the dependency graph class from arg[1]
-        Class<?> graphDefinitionClass = includeAClass(graphDefinitionFp);
-        if (graphDefinitionClass != null) {
-            System.out.println("build:: loaded " + graphDefinitionFp + ".class");
-        } else {
-            System.out.println("build:: failed to load " + graphDefinitionFp + ".class");
-            System.exit(1);
-        }
-
-        // Get the node_map and node_f_list from the graph class
-        // Assuming these methods are static and return the appropriate types
-        // Replace with actual method calls if they are different
-        Object nodeMap = null;
-        Object nodeFList = null;
-        try {
-            nodeMap = graphDefinitionClass.getMethod("getNodeMap").invoke(null);
-            nodeFList = graphDefinitionClass.getMethod("getNodeFList").invoke(null);
-        } catch (Exception e) {
-            System.out.println("Error invoking methods on graphDefinitionClass: " + e.getMessage());
-            System.exit(1);
-        }
-        System.out.println("node_map: " + nodeMap);
-        System.out.println("node_f_list: " + nodeFList);
-
-        // Create an instance of AriadneGraph, and run the build scripts
-        // Assuming AriadneGraph has a constructor that takes nodeMap and nodeFList
-        // Replace with actual constructor call if it is different
-        try {
-            Class<?> ariadneGraphClass = Class.forName("AriadneGraph");
-            Object graph = ariadneGraphClass.getConstructor(nodeMap.getClass(), nodeFList.getClass()).newInstance(nodeMap, nodeFList);
-            ariadneGraphClass.getMethod("runBuildScriptsF", List.class).invoke(graph, rootNodeLabels);
-        } catch (Exception e) {
-            System.out.println("Error creating or invoking AriadneGraph: " + e.getMessage());
-            System.exit(1);
-        }
-    }
-
-    // Entry point when run as a script
-    public static void main(String[] args) {
-        if (args.length == 0) {
-            System.out.println("Usage: ./build <graph_definition.class> [root_node_labels...]");
-            System.exit(1);
-        }
-
-        // Get graph definition file and root node labels
-        String graphDefinitionFp = args[0];
-        List<String> rootNodeLabels = args.length > 1 ? List.of(args).subList(1, args.length) : List.of();
-        build(graphDefinitionFp, rootNodeLabels);
-    }
-}
diff --git a/developer/javacđź–‰/DirectedGraph.xjava b/developer/javacđź–‰/DirectedGraph.xjava
new file mode 100644 (file)
index 0000000..c8b2420
--- /dev/null
@@ -0,0 +1,234 @@
+package com.ReasoningTechnology.Ariadne;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+
+public class Ariadne_GraphDirectedAcyclic extends Ariadne_Graph{
+
+  // test messaging
+  //
+    private static boolean test = false;
+    public static void test_switch(boolean test){
+      if(Ariadne_Graph.test && !test){
+        test_print("Ariadne_Graph:: test messages off");
+      }
+      if(!Ariadne_Graph.test && test){
+        test_print("Ariadne_Graph:: test messages on");
+      }
+    }
+    private static void test_print(String message){
+      if(test){
+        System.out.println(message);
+      }
+    }
+
+  // class data
+  //
+
+    // marks this class might put on a node
+    public static Ariadne_TokenSet node_marks = new Ariadne_TokenSet(){{
+      add(new Ariadne_Token("empty_root_label_list"));
+      add(new Ariadne_Token("cycle_exists"));
+      add(new Ariadne_Token("undefined_node_exists"));
+      add(new Ariadne_Token("bad_descent_termination"));
+      add(new Ariadne_Token("max_depth_reached"));
+    }};
+
+    // graph descend method return values
+    private static Ariadne_TokenSet graph_descend_set = new Ariadne_TokenSet(){{
+      add(new Ariadne_Token("empty_path_stack"));
+      add(new Ariadne_Token("cycle_found"));
+      add(new Ariadne_Token("undefined_node"));
+      add(new Ariadne_Token("leaf"));
+      add(new Ariadne_Token("max_depth_reached"));
+    }};
+
+
+  // instance data
+
+  // constructors
+  //
+    public Ariadne_GraphDirectedAcyclic(){
+      super(new HashMap<>(), null);
+    }
+
+    public Ariadne_GraphDirectedAcyclic(Map<Ariadne_Label, Ariadne_Node> node_map, Ariadne_DefinitionList recognizer_f_list, Ariadne_LabelList root_node_list, int max_depth, boolean verbose){
+      super(node_map, recognizer_f_list);
+      Ariadne_TokenSet cycle_detection_result = graph_mark_cycles(root_node_list, max_depth, verbose);
+    }
+
+    public Ariadne_GraphDirectedAcyclic(Map<Ariadne_Label, Ariadne_Node> node_map, Ariadne_DefinitionList recognizer_f_list, Ariadne_LabelList root_node_list){
+      super(node_map, recognizer_f_list);
+      Ariadne_TokenSet cycle_detection_result = graph_mark_cycles(root_node_list);
+    }
+
+  // interface functions
+  //
+    private List<Integer> path_find_cycle(Ariadne_LabelList path){
+      if(path.size() <= 1) return null;
+
+      int rightmost_index = path.size() - 1;
+      Ariadne_Label rightmost_node_label = path.get(rightmost_index);
+
+      int cycle_leftmost_index = path.indexOf(rightmost_node_label);
+      Boolean has_cycle = cycle_leftmost_index < rightmost_index;
+      if(!has_cycle) return null;
+
+      List<Integer> result = new ArrayList<>();
+      result.add(cycle_leftmost_index);
+      result.add(rightmost_index);
+      return result;
+    }
+
+    private boolean graph_descend_cycle_case(Ariadne_LabelList left_path, List<Ariadne_LabelList> path_stack, boolean verbose){
+
+      List<Integer> cycle_index_interval = path_find_cycle(left_path);
+      if(cycle_index_interval == null){
+        return false;
+      }
+
+      int cycle_i0 = cycle_index_interval.get(0);
+      int cycle_n = cycle_index_interval.get(1);
+
+      if(verbose) Ariadne_Util.print_list(
+        "Found cycle:", 
+        left_path.subList(cycle_i0, cycle_n + 1)
+      );
+
+      Ariadne_LabelList undefined_node_list = new Ariadne_LabelList();
+      for (int i = cycle_i0; i <= cycle_n; i++){
+        Ariadne_Label node_label = left_path.get(i);
+        Ariadne_Node node = super.lookup(node_label);
+        if(node != null){
+          node.mark(new Ariadne_Token("cycle_member"));
+        } else{
+          undefined_node_list.add(node_label);
+        }
+      }
+
+      if(verbose) Ariadne_Util.print_list(
+        "Each undefined node could not be marked as a cycle member:", 
+        undefined_node_list
+      );
+
+      path_stack.subList(cycle_i0 + 1, cycle_n + 1).clear();
+
+      return true;
+    }
+
+    private Ariadne_TokenSet graph_descend(List<Ariadne_LabelList> path_stack, int max_depth, boolean verbose){
+      Ariadne_TokenSet ret_value = new Ariadne_TokenSet();
+
+      if(path_stack.isEmpty()){
+        ret_value.add(new Ariadne_Token("empty_path_stack"));
+        return ret_value;
+      }
+
+      Ariadne_LabelList left_path = new Ariadne_LabelList();
+      for (Ariadne_LabelList neighbor_list : path_stack){
+        left_path.add(neighbor_list.get(0));
+      }
+
+      do{
+
+        if(graph_descend_cycle_case(left_path, path_stack, verbose)){
+          ret_value.add(new Ariadne_Token("cycle_found"));
+          return ret_value;
+        }
+
+        Ariadne_Label it_node_label = path_stack.get(path_stack.size() - 1).get(0);
+        Ariadne_Node it_node = super.lookup(it_node_label);
+        if(it_node == null){
+          ret_value.add(new Ariadne_Token("undefined_node"));
+          return ret_value;
+        }
+
+        Ariadne_LabelList neighbor_list = it_node.neighbor_LabelList();
+        if(neighbor_list.isEmpty()){
+          ret_value.add(new Ariadne_Token("leaf"));
+          return ret_value;
+        }
+
+        path_stack.add(new Ariadne_LabelList(neighbor_list));
+        Ariadne_Label it_next_label = neighbor_list.get(0);
+        left_path.add(it_next_label);
+
+        if(max_depth > 0){
+          max_depth--;
+          if(max_depth == 0){
+            if(verbose){
+              Ariadne_Util.print_list("GraphDirectedAcyclic.GraphDescend:: max_depth reached, ending descent:", path_stack);
+            }
+            ret_value.add(new Ariadne_Token("max_depth_reached"));
+            return ret_value;
+          }
+        }
+
+      } while (true);
+    }
+
+
+  public Ariadne_TokenSet graph_mark_cycles(Ariadne_LabelList root_node_LabelList, int max_depth, boolean verbose){
+    Ariadne_TokenSet ret_value = new Ariadne_TokenSet();
+    boolean exists_malformed = false;
+    Ariadne_TokenSet result;
+
+    if(root_node_LabelList.isEmpty()){
+      ret_value.add(new Ariadne_Token("empty_root_label_list"));
+      return ret_value;
+    }
+
+    List<Ariadne_LabelList> path_stack = new ArrayList<>();
+    path_stack.add(new Ariadne_LabelList(root_node_LabelList));
+
+    do{
+      result = graph_descend(path_stack, max_depth, verbose);
+      if(result.contains(new Ariadne_Token("cycle_found"))) ret_value.add(new Ariadne_Token("cycle_exists"));
+      if(result.contains(new Ariadne_Token("undefined_node"))) ret_value.add(new Ariadne_Token("undefined_node_exists"));
+      if(result.contains(new Ariadne_Token("max_depth_reached"))) ret_value.add(new Ariadne_Token("max_depth_reached"));
+      if(!result.contains(new Ariadne_Token("leaf")) && !result.contains(new Ariadne_Token("cycle_found"))) ret_value.add(new Ariadne_Token("bad_descent_termination"));
+
+      Ariadne_LabelList top_list = path_stack.get(path_stack.size() - 1);
+      top_list.remove(0);
+      if(top_list.isEmpty()) path_stack.remove(path_stack.size() - 1);
+
+    } while (!path_stack.isEmpty());
+
+    if(verbose){
+      if(ret_value.contains("bad_descent_termination")){
+        System.out.println("GraphDirectedAcyclic.graph_mark_cycles:: terminated with unexpected condition.");
+      }
+      if(ret_value.contains("cycle_exists")){
+        System.out.println("GraphDirectedAcyclic.graph_mark_cycles:: One or more cycles detected.");
+      }
+      if(ret_value.contains("undefined_node_exists")){
+        System.out.println("GraphDirectedAcyclic.graph_mark_cycles:: Undefined nodes exist.");
+      }
+    }
+
+    return ret_value;
+  }
+
+  public Ariadne_TokenSet graph_mark_cycles(Ariadne_LabelList root_node_LabelList){
+    return graph_mark_cycles(root_node_LabelList, this.debug ? 40 : -1, this.debug);
+  }
+
+  @Override
+  public Ariadne_Node lookup(Ariadne_Label node_label, boolean verbose){
+    Ariadne_Node node = super.lookup(node_label, verbose);
+    if(node != null && node.has_mark(new Ariadne_Token("cycle_member"))){
+      if(verbose){
+        System.out.println("GraphDirectedAcyclic.lookup:: Node is part of a cycle, not returned: " + node_label);
+      }
+      return null;
+    }
+    return node;
+  }
+
+  public Ariadne_Node lookup(Ariadne_Label node_label){
+    return lookup(node_label, this.debug);
+  }
+
+}
diff --git a/developer/javacđź–‰/File.java b/developer/javacđź–‰/File.java
new file mode 100644 (file)
index 0000000..d0b250c
--- /dev/null
@@ -0,0 +1,79 @@
+package com.ReasoningTechnology.Ariadne;
+/*
+  Utilities for dealing with files.
+*/
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class File {
+  static boolean debug = false;
+
+  public static Map<String, String> unpack_file_path(String file_fp) {
+    if (debug) System.out.println("unpack_file_path::file_fp: " + file_fp);
+
+    // Use java.io.File explicitly to avoid conflict with the custom Ariadne_File class
+    java.io.File file = new java.io.File(file_fp);
+    String parent_dp = (file.getParent() != null) ? file.getParent() : "";
+
+    if (!parent_dp.isEmpty() && !parent_dp.endsWith(java.io.File.separator)) {
+      parent_dp += java.io.File.separator;
+    }
+
+    String file_fn = file.getName();
+    String file_fn_base = file_fn;
+    String file_fn_ext = "";
+
+    int last_index = file_fn.lastIndexOf('.');
+    if (last_index > 0) {
+      file_fn_base = file_fn.substring(0, last_index);
+      if (last_index + 1 < file_fn.length()) {
+        file_fn_ext = file_fn.substring(last_index + 1);
+      }
+    }
+
+    Map<String, String> ret_val = new HashMap<>();
+    ret_val.put("dp", parent_dp);
+    ret_val.put("fn", file_fn);
+    ret_val.put("fn_base", file_fn_base);
+    ret_val.put("fn_ext", file_fn_ext);
+
+    if (debug) System.out.println("unpack_file_path::ret_val: " + ret_val);
+
+    return ret_val;
+  }
+
+  public static boolean file_exists_q(String fp_string) {
+    Path fp_object = Paths.get(fp_string);
+    return Files.exists(fp_object);
+  }
+
+  /*
+    Given a target_fp and a list of dependency_fp.
+
+    Returns false if the target is newer than all dependencies or if a file is missing;
+    otherwise, returns true.
+  */
+  public static boolean newer_than_all(String target_fp_string, List<String> dependency_fp_list) throws IOException {
+    Path target_fp_object = Paths.get(target_fp_string);
+    if (!Files.exists(target_fp_object)) return false;
+
+    long target_last_modified_time = Files.getLastModifiedTime(target_fp_object).toMillis();
+
+    return dependency_fp_list.stream().allMatch(dependency_fp -> {
+      try {
+        Path dependency_fp_object = Paths.get(dependency_fp);
+        if (!Files.exists(dependency_fp_object)) return false;
+        long dependency_last_modified_time = Files.getLastModifiedTime(dependency_fp_object).toMillis();
+        return target_last_modified_time > dependency_last_modified_time;
+      } catch (IOException e) {
+        return false;
+      }
+    });
+  }
+}
diff --git a/developer/javacđź–‰/GraphAriadne.javax b/developer/javacđź–‰/GraphAriadne.javax
deleted file mode 100644 (file)
index a5949fe..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-package com.ReasoningTechnology.Ariadne;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class AriadnaGraph extends Graph{
-
-  /*--------------------------------------------------------------------------------
-    constructors
-  */
-
-  public Graph(Map<Label ,Node> node_map ,ProductionList recognizer_f_list){
-
-  }
-
-  /*--------------------------------------------------------------------------------
-   instance data 
-  */
-
-  private static boolean debug = true;
-
-  /*--------------------------------------------------------------------------------
-    About nodes
-
-    A leaf type node specifies a path to a file that should not be deleted by
-    in clean operations. Typically this is the source code. We could add a
-    tool to lock permissions on these before a build, so that the build
-    scripts will also not mess with them (unless they change permissions).
-
-    If the user has multiple dependency graphs defined, a node with no
-    dependencies in one graph, might have dependencies in another.
-
-    An error type node, is one that was found to not have a type, or
-    was constructed by the tool to be a place older, perhaps for a
-    node label that was not found.
-
-  */
-  public static TokenSet all_node_type_set = new TokenSet();
-  static {
-    all_node_type_set.add(new Token("symbol"));
-    all_node_type_set.add(new Token("path"));
-    all_node_type_set.add(new Token("leaf"));
-    all_node_type_set.add(new Token("error"));
-  }
-
-  public static TokenSet persistent_node_mark_set = new TokenSet();
-  static {
-    persistent_node_mark_set.add(new Token("cycle_member"));
-    persistent_node_mark_set.add(new Token("wellformed"));
-    persistent_node_mark_set.add(new Token("build_failed"));
-    persistent_node_mark_set.add(new Token("null_node"));
-  }
-
-  public static boolean leaf_q(Node node){
-    return node != null && "leaf".equals(node.get("type"));
-  }
-
-  public static boolean has_mark(Node node){
-    return node != null && node.get("mark") != null && !( (TokenSet)node.get("mark") ).isEmpty();
-  }
-
-  public static void set_mark(Node node ,Token mark){
-    if( node.get("mark") == null ){
-      node.put("mark" ,new HashTokenSet());
-    }
-    ( (TokenSet)node.get("mark") ).add(mark);
-  }
-
-  public static void clear_mark(Node node ,Token mark){
-    if( node != null && node.get("mark") != null ){
-      ( (TokenSet) node.get("mark") ).remove(mark);
-    }
-  }
-
-  public static boolean marked_good_q(Node node){
-    return node != null && node.get("mark") != null
-      && ( (TokenSet)node.get("mark") ).contains("wellformed")
-      && !( (TokenSet)node.get("mark") ).contains("cycle_member")
-      && !( (TokenSet)node.get("mark") ).contains("build_failed");
-  }
-
-  /*--------------------------------------------------------------------------------
-   Well-formed Node Check
-  */
-
-  public static TokenSet form_condition_set = new TokenSet();
-  static {
-    form_condition_set.add(new Token("no_node"));
-    form_condition_set.add(new Token("node_must_have_label"));
-    form_condition_set.add(new Token("label_must_be_string"));
-    form_condition_set.add(new Token("node_must_have_type"));
-    form_condition_set.add(new Token("bad_node_type"));
-    form_condition_set.add(new Token("neighbor_value_must_be_list"));
-    form_condition_set.add(new Token("neighbor_reference_must_be_string"));
-    form_condition_set.add(new Token("neighbor_label_not_in_graph"));
-    form_condition_set.add(new Token("mark_property_value_must_be_set"));
-    form_condition_set.add(new Token("unregistered_mark"));
-    form_condition_set.add(new Token("missing_required_build_code"));
-    form_condition_set.add(new Token("leaf_given_neighbor_property"));
-    form_condition_set.add(new Token("leaf_given_build_property"));
-  }
-
-  // given a node, collects a description of its form, returns a set form condition tokens
-  public static TokenSet wellformed_node_q(Node node){
-    TokenSet form_error_set = new HashSet<>();
-
-    if(node == null){
-      form_error_set.add("null_node");
-      return form_error_set;
-    }
-
-    if( !node.containsKey("label") )
-      form_error_set.add("node_must_have_label");
-    else if( !(node.get("label") instanceof Label) )
-      form_error_set.add("label_must_be_string");
-
-    if( !node.containsKey("type") )
-      form_error_set.add("node_must_have_type");
-    else if( !(node.get("type") instanceof String) || !all_node_type_set.contains(node.get("type")) )
-      form_error_set.add("bad_node_type");
-
-    if( node.containsKey("neighbor") ){
-      if( !(node.get("neighbor") instanceof List) )
-        form_error_set.add("neighbor_value_must_be_list");
-      else if( !((List<?>) node.get("neighbor")).stream().allMatch(it -> it instanceof Label) )
-        form_error_set.add("neighbor_reference_must_be_string");
-    }
-
-    if( node.containsKey("mark") ){
-      if( !(node.get("mark") instanceof Set) )
-        form_error_set.add("mark_property_value_must_be_set");
-      else if( !((Set<?>) node.get("mark")).stream().allMatch(it -> persistent_node_mark_set.contains(it)) )
-        form_error_set.add("unregistered_mark");
-    }
-
-    if( "path".equals(node.get("type")) && (!node.containsKey("build") || !(node.get("build") instanceof Runnable)) )
-      form_error_set.add("missing_required_build_code");
-
-    if( "leaf".equals(node.get("type")) ){
-      if( node.containsKey("neighbor") ) form_error_set.add("leaf_given_neighbor_property");
-      if( node.containsKey("build") ) form_error_set.add("leaf_given_build_property");
-    }
-
-    return form_error_set;
-  }
-
-  // given a node, potentially marks it as wellformed, returns one of 'wellformed' or 'malformed'
-  public static Token wellformed_mark_node(Node node ,boolean verbose){
-    if(debug){
-      if(node != null){
-        System.out.println("wellformed_mark_node::node: " + node);
-      }else{
-        System.out.println("wellformed_mark_node given a null node");
-      }
-    }
-
-    TokenSet form_errors = wellformed_node_q(node);
-    if( form_errors.isEmpty() ){
-      set_mark( node ,"wellformed" );
-      return "wellformed";
-    }
-
-    // At this point we know that form_errors is not empty
-    if(verbose){
-      if( node != null && node.get("label") != null && ((Label)node.get("label")).length() > 0 ){
-        System.out.print( "node " + node.get("label") + " is malformed due to:" );
-      }else{
-        System.out.print("anonymous node is malformed due to:");
-      }
-      for(Token error : form_errors){
-        System.out.print(" " + error);
-      }
-      System.out.println("");
-    }
-
-    return "malformed";
-  }
-  public Token wellformed_mark_node(Node node){
-    return wellformed_mark_node(node ,true);
-  }
-
-  // given a node_label, potentially marks the corresponding node as 'wellformed', returns a token set.
-  // Tokens included "undefined_node", "malformed", and "defactor_leaf".
-  public TokenSet wellformed_mark_node_label(Label node_label ,boolean verbose){
-    TokenSet ret_value = new HashSet<>();
-    Node node = super.lookup(node_label);
-    if(node == null){
-      ret_value.add("undefined_node");
-      return ret_value;
-    }
-    if( "malformed".equals(wellformed_mark_node(node ,verbose)) ){
-      ret_value.add("malformed");
-    }
-    if( ((List<?>)node.get("neighbor")).isEmpty() ){
-      ret_value.add("defacto_leaf"); // might not be `type:leaf`
-    }
-    return ret_value;
-  }
-  public TokenSet wellformed_mark_node_label(Label node_label){
-    return wellformed_mark_node_label(node_label ,true);
-  }
-
-  /*--------------------------------------------------------------------------------
-   A well formed graph checker.  Traverses entire graph and marks nodes
-   that are not well formed or that are part of a cycle.
-
-   This must be run on the graph for `lookup_marked_good` to work.
-
-   Each node_label must be a string and not empty.
-
-   Subleties here because we have not yet determined if the nodes we are
-   wellformed (after all ,that is what we are determining here).
-
-   If we want to attempt to build 'islands' of things that might be located on
-   the far side of cycles ,then modify the cycle finder to return a list of
-   cycles (i.e. a list of lists) ,then use each of cycle definition (a list) as
-   the root nodes for further search.
-
-   `path_stack` is a stack of LabelList. The first entry is a clone of the list of
-   root nodes, referenced by label. Each subsequent list is a clone of the
-   neighbor list of the leftmost node of the prior entry.
-
-   `path` is a list of the left most nodes, referenced by label, of the entries
-   on the path stack. This is the path to our current location in the tree.
-  */
-
-
-  private boolean find_and_remove_cycle(List<LabelList> path_stack ,LabelList path ,boolean verbose){
-
-    if( path.size() <= 1 ) return false; // 0 or 1 length path can't have a cycle
-
-    // we want to know if the most recent node added to the path occurs at a point earlier
-    // in the path.
-    int rightmost_index = path.size() - 1;
-    Label recent_node_label = path.get( rightmost_index );
-    int cycle_start_index = path.indexOf(recent_node_label);
-    if( cycle_start_index == -1 ){
-      System.err.println("find_and_remove_cycle:: indexOf does not find index of known list member");
-      return false;
-    }
-    Boolean has_cycle =  cycle_start_index < rightmost_index;
-    if(!has_cycle) return false;
-
-    if(verbose) System.out.print("mark_form_graph_descend:: dependency cycle found:");
-    for( Label cycle_node_label : path.subList(cycle_start_index ,path.size()) ){
-      if(verbose) System.out.print(" " + cycle_node_label);
-      Node cycle_node = super.lookup(cycle_node_label);
-      if( cycle_node.get("mark") == null ){
-        cycle_node.put( "mark" ,new HashTokenSet() );
-      }
-      ( (TokenSet)cycle_node.get("mark") ).add("cycle_member");
-    }
-    if(verbose) System.out.println("");
-
-    // We cannot continue searching after the loop, so we pop back to treat
-    // the first node in the loop as though a leaf node.
-    path_stack.subList( cycle_start_index + 1 ,path_stack.size() ).clear();
-
-    return true;
-  }
-
-  private static TokenSet mark_form_graph_descend_set = new TokenSet();
-  static {
-    mark_form_graph_descend_set.add(new Token("empty_path_stack"));
-    mark_form_graph_descend_set.add(new Token("cycle_found"));
-    mark_form_graph_descend_set.add(new Token("undefined_node"));
-    mark_form_graph_descend_set.add(new Token("exists_malformed"));
-    mark_form_graph_descend_set.add(new Token("defacto_leaf"));
-  }
-
-  private TokenSet mark_form_graph_descend( List<LabelList> path_stack ,boolean verbose ){
-    TokenSet ret_value = new HashSet<>();
-    if(path_stack.isEmpty()){
-      if(verbose) System.out.println( "mark_form_graph_descend:: given empty path_stack to descend from" );
-      ret_value.add( "empty_path_stack" );
-      return ret_value;
-    }
-
-    LabelList local_path = new ArrayList<>();
-    for(LabelList path : path_stack){
-      local_path.add( path.get(0) );
-    }
-    Label local_node_label = local_path.get( local_path.size() - 1 );
-  
-    do{
-      
-      if( find_and_remove_cycle(path_stack ,local_path ,verbose) ){
-        ret_value.add("cycle_found");
-        return ret_value;
-      }
-
-      TokenSet wellformed_mark_node_label_result = wellformed_mark_node_label(local_node_label ,verbose);
-      ret_value.addAll( wellformed_mark_node_label_result );
-      if( 
-         wellformed_mark_node_label_result.contains("undefined_node") 
-         || wellformed_mark_node_label_result.contains("defacto_leaf") 
-      ){
-        return ret_value;
-      }
-
-      // Descend further into the tree.
-      path_stack.add( new ArrayList<>((LabelList) super.lookup(local_node_label).get("neighbor")) );
-      local_node_label = (LabelList)super.lookup(local_node_label).get("neighbor").get(0);
-      local_path.add(local_node_label);
-
-    }while(true);
-  }
-
-   
-  /*
-    Given root_node_label_list, marks up the graph and returns a set possibly
-    containing 'all_wellformed' and 'cycles_exist'.
-
-    Marks potentially added to each node include 'cycle_member' and 'wellformed'.
-    Note that these marks are independent.
-  */
-  public TokenSet mark_form_graph(LabelList root_node_label_list ,boolean verbose){
-    TokenSet ret_value = new HashSet<>();
-    boolean exists_malformed = false;
-    TokenSet result; // used variously
-
-    if( root_node_label_list.isEmpty() ) return ret_value;
-
-    // Initialize the DFS tree iterator.
-    List<LabelList> path_stack = new ArrayList<>();
-    path_stack.add( new ArrayList<>(root_node_label_list) );
-
-    // iterate over left side tree descent, not ideal as it starts at the
-    // root each time, but avoids complexity in the cycle detection logic.
-    do{
-      result = mark_form_graph_descend(path_stack ,verbose);
-      if( result.contains("cycle_found") ) ret_value.add("cycle_exists");
-      if( result.contains("undefined_node") ) exists_malformed = true;
-      if( result.contains("exists_malformed") ) exists_malformed = true;
-
-      // increment the iterator to the next leftmost path
-      LabelList top_list = path_stack.get( path_stack.size() - 1 );
-      top_list.remove(0);
-      if( top_list.isEmpty() ) path_stack.remove( path_stack.size() - 1 );
-
-    }while( !path_stack.isEmpty() );
-
-    if( !exists_malformed ) ret_value.add("all_wellformed");
-
-    if( verbose ){
-      if( exists_malformed ) System.out.println("one or more malformed nodes were found");
-      boolean exists_cycle = ret_value.contains("cycle_exists");
-      if( exists_cycle ) System.out.println("one or more cyclic dependency loop found");
-      if( exists_malformed || exists_cycle ) System.out.println("will attempt to build unaffected nodes");
-    }
-
-    return ret_value;
-  }
-  public TokenSet mark_form_graph(LabelList root_node_label_list){
-    return mark_form_graph(root_node_label_list ,true);
-  }
-
-  /*--------------------------------------------------------------------------------
-    Graph traversal
-  */
-
-  // Lookup method to find a node by its label
-  public Node lookup(Label node_label ,boolean verbose){
-    Node node = super.lookup(node_label ,verbose);
-    if(node != null && marked_good_q(node)) return node;
-    return null;
-  }
-
-  // Overloaded lookup method with default verbosity (true)
-  public Node lookup(Label node_label){
-    return lookup(node_label ,true);
-  }
-
-
-
-}
diff --git a/developer/toolđź–‰/make_example b/developer/toolđź–‰/make_example
new file mode 100755 (executable)
index 0000000..5868b53
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+# input guards
+
+  env_must_be="developer/toolđź–‰/env"
+  if [ "$ENV" != "$env_must_be" ]; then
+    echo "$(script_fp):: error: must be run in the $env_must_be environment"
+    exit 1
+  fi
+
+  cd "$REPO_HOME"/developer
+
+
+echo "Compiling example .java files..."
+
+  set -x
+  cd example
+  javac -verbose -g -sourcepath . *.java
+  set +x
+  if [ $? -ne 0 ]; then
+    echo "Compilation failed."
+    exit 1
+  fi
+
+echo "Creating bash wrappers..."
+  # wrapper is a space separated list
+  wrapper=Example_Ariadne_SRM
+  for file in $wrapper;do
+    cat > $file << EOL
+#!/bin/bash
+java $file
+EOL
+    chmod +x $file
+  done
+
+echo "$(script_fp) done."
+
diff --git a/documentđź–‰/Ariadne_tool.txt b/documentđź–‰/Ariadne_tool.txt
new file mode 100644 (file)
index 0000000..f473de6
--- /dev/null
@@ -0,0 +1,33 @@
+--------------------------------------------------------------------------------
+General Comments about Graphs
+
+Conceptually a graph is a set with two members, vertices and edges, both also being sets.In Ariadne land we refer to a vertex as a 'node'. Hence, we say that each edge is a pair of nodes. In a directed graph, one of the nodes in an edge pair is said to be the tail, while the other is said to be the head.
+
+A leaf node is unusual in that it is not the tail of any edge.
+
+When a node is selected, a set is implied that contains each and every edge that has the selected node as its tail, if any. These are the outgoing edges for the selected node.Each outgoing edge then has a head. We say that the set of head nodes are distance one from the selected node. (The selected node itself is at distance zero.) Distance one nodes are said to be 'neighbor' nodes.
+
+Deterministic traversal is an algorithm that is given two arguments when it is started, a graph definition, and a start node. The start node is then assigned to a state variable. At each step of the algorithm, the node in the state variable is selected on the graph, then the state variable is re-assigned to be one of the distance one nodes.
+
+Deterministic search for a node is an example of an algorithm that makes use of traversal.Deterministic search begins with a graph, a start node, a predicate that is said to recognize the searched for node, and a function that guides the traversal.
+
+A self cycle in a graph consists of a node and an edge, where said edge has the node as both its tail and its head. There is no change in the traversal state variable when taking a traversal step through such an edge.In general, a cycle consists of a start node and all nodes and edges traversed up until arriving back at said start node.
+
+It is a bad thing to have cycles in a build graph, as cycles will correspond to circular dependencies.Hence Ariadne looks for these and reports them.
+
+--------------------------------------------------------------------------------
+The Ariadne Build Graph
+
+An Ariadne graph definition contains a 'graph definition function' list.A graph definition function is given a node label, and returns a node, or null if it can not find a node with such a label. A common graph definition function contains a map where each entry is a node label and a node.
+
+An Ariadne node is dictionary that maps a string key to a value. The type of the value is implied by the string key. Depending on the Ariadne tool being used, each node map will typically have entries for the keys "label", "build", and "neighbor".
+
+A "label" value is a string that is unique among the nodes in the graph. The "build" value is a function that a build tool will call when a file corresponding to a node is to be built.The "neighbor" value is a list of neighbor nodes.
+
+The Ariadne graph definition is optimized to be a run time data structure used for traversal, so the neighbor list is held directly in the node. Also, there is only one edge property, that of 'dependency'. As a consequence, there is no need for a separate edge table.
+
+--------------------------------------------------------------------------------
+Ariadne Build Tool
+
+For the default Ariadne build tool, each node label is either symbolic, or is a file path. The tool descends into the graph, based on file modification dates, and builds nodes that are modified less recently than their dependencies.
+
diff --git a/documentđź–‰/project_participants.txt b/documentđź–‰/project_participants.txt
new file mode 100644 (file)
index 0000000..c0755b8
--- /dev/null
@@ -0,0 +1,49 @@
+--------------------------------------------------------------------------------
+For Developers/Testers
+
+The project has three entry points, one for each project role: developer, tester, and administrator. To enter the project, source the environment appropriate for the role, either `env_developer`, `env_tester`, or `env_administrator`.
+
+1. Production 
+
+  1.1. development
+
+  cd Ariadne
+  . env_developer
+
+  [do work]
+
+  make
+  release
+
+  1.2 regression testing
+
+  cd Ariadne
+  . env_tester
+  make
+  run
+
+2. Debugging
+
+  cd Ariadne
+  . env_developer
+  make
+  # puts links to source files on the `scratchpad`
+  gather_source_links 
+
+  [change to tester module]
+
+  cd Ariadne
+  # the developer parameter links in the actual source in the developer module
+  . env_tester developer
+  make
+  run
+
+The `make` command you see above is a bash script. Version 1.0 of Ariadne uses a direct 'build it all every time' approach. Perhaps in version 2.0 or so, we will use a prior version of Ariadne for the build environment.
+
+In IntelliJ IDEA there are two modules, developer and tester. The output for each module is 'scratchpad' tests are added through the `run edit-configuration` menu. See tool_shared/third_party/documentđź–‰ directory for more information.
+
+Using Ariadne
+-------------
+
+After it is built and released the tool will appear in the Ariadne/release directory where it can be regression tested or imported into another project.
+
diff --git a/tester/data/File_0/I_exist b/tester/data/File_0/I_exist
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tester/data/File_0/file_0 b/tester/data/File_0/file_0
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tester/data/File_0/file_1 b/tester/data/File_0/file_1
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tester/data/File_0/file_2 b/tester/data/File_0/file_2
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tester/data/File_0/file_3 b/tester/data/File_0/file_3
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tester/data_File_0/I_exist b/tester/data_File_0/I_exist
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tester/data_File_0/file_0 b/tester/data_File_0/file_0
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tester/data_File_0/file_1 b/tester/data_File_0/file_1
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tester/data_File_0/file_2 b/tester/data_File_0/file_2
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tester/data_File_0/file_3 b/tester/data_File_0/file_3
deleted file mode 100644 (file)
index e69de29..0000000
index cf56c38..0176f9e 100644 (file)
@@ -11,7 +11,7 @@ import java.util.Map;
 
 import com.ReasoningTechnology.Mosaic.Mosaic_IO;
 import com.ReasoningTechnology.Mosaic.Mosaic_Testbench;
-import com.ReasoningTechnology.Mosaic.Mosaic_Util;
+import com.ReasoningTechnology.Mosaic.Mosaic_Quantifier;
 
 import com.ReasoningTechnology.Ariadne.Ariadne_File;
 
@@ -39,7 +39,7 @@ public class File_0 {
                 conditions[i++] = result.get("fn_ext").equals(expected_fn_ext);
                 conditions[i++] = result.size() == 4;
 
-                return Mosaic_Util.all(conditions);
+                return Mosaic_Quantifier.all(conditions);
             } catch (Exception e) {
                 e.printStackTrace();
                 return false;
@@ -51,13 +51,13 @@ public class File_0 {
             int i = 0;
 
             String repoHome = System.getenv("REPO_HOME");
-            String existingFilePath = repoHome + "/tester/data_File_0/I_exist";
-            String nonExistentFilePath = repoHome + "/tester/data_File_0/I_do_not_exist";
+            String existingFilePath = repoHome + "/tester/data/File_0/I_exist";
+            String nonExistentFilePath = repoHome + "/tester/data/File_0/I_do_not_exist";
 
             conditions[i++] = Ariadne_File.file_exists_q(existingFilePath);
             conditions[i++] = !Ariadne_File.file_exists_q(nonExistentFilePath);
 
-            return Mosaic_Util.all(conditions);
+            return Mosaic_Quantifier.all(conditions);
         }
 
         public Boolean newer_than_all_0(Mosaic_IO io) throws IOException {
@@ -65,11 +65,11 @@ public class File_0 {
             int i = 0;
 
             String repoHome = System.getenv("REPO_HOME");
-            String file_0 = repoHome + "/tester/data_File_0/file_0";
-            String file_1 = repoHome + "/tester/data_File_0/file_1";
-            String file_2 = repoHome + "/tester/data_File_0/file_2";
-            String file_3 = repoHome + "/tester/data_File_0/file_3";
-            String missing_file_0 = repoHome + "/tester/data_File_0/missing_file_0";
+            String file_0 = repoHome + "/tester/data/File_0/file_0";
+            String file_1 = repoHome + "/tester/data/File_0/file_1";
+            String file_2 = repoHome + "/tester/data/File_0/file_2";
+            String file_3 = repoHome + "/tester/data/File_0/file_3";
+            String missing_file_0 = repoHome + "/tester/data/File_0/missing_file_0";
 
             // Setting modification times
             Files.setLastModifiedTime(Path.of(file_3), FileTime.fromMillis(System.currentTimeMillis() - 20000));
@@ -90,7 +90,7 @@ public class File_0 {
 
             conditions[i++] = !Ariadne_File.newer_than_all(file_0, List.of(file_1, missing_file_0));
 
-            return Mosaic_Util.all(conditions);
+            return Mosaic_Quantifier.all(conditions);
         }
     }
 
index bfb5dcc..3fdbf63 100644 (file)
@@ -6,7 +6,7 @@ import java.lang.reflect.Method;
 import com.ReasoningTechnology.Mosaic.Mosaic_Dispatch;
 import com.ReasoningTechnology.Mosaic.Mosaic_IO;
 import com.ReasoningTechnology.Mosaic.Mosaic_Testbench;
-import com.ReasoningTechnology.Mosaic.Mosaic_Util;
+import com.ReasoningTechnology.Mosaic.Mosaic_Quantifier;
 
 import com.ReasoningTechnology.Ariadne.Ariadne_Graph;
 import com.ReasoningTechnology.Ariadne.Ariadne_GraphDirectedAcyclic;
@@ -22,12 +22,12 @@ public class Graph_0 {
 
     public TestSuite() {
       this.GraphDirectedAcyclic_proxy =
-        Mosaic_Util.make_all_public_methods_proxy( Ariadne_GraphDirectedAcyclic.class );
+        Mosaic_Quantifier.make_all_public_methods_proxy( Ariadne_GraphDirectedAcyclic.class );
     }
 
     public Boolean path_find_cycle_0( Mosaic_IO io ) {
       Boolean[] conditions = new Boolean[1];
-      Mosaic_Util.all_set_false( conditions );
+      Mosaic_Quantifier.all_set_false( conditions );
       int i = 0;
       try {
         Ariadne_LabelList path = new Ariadne_LabelList(
@@ -47,17 +47,17 @@ public class Graph_0 {
         conditions[i++] = cycle_indices != null && cycle_indices.size() == 2;
         */
       } catch (Exception e) {
-        Mosaic_Util.log_message("path_find_cycle_0", "Test logic error: " + e.getMessage());
+        Mosaic_Quantifier.log_message("path_find_cycle_0", "Test logic error: " + e.getMessage());
         return false;
       }
 
       return true;
-//      return Mosaic_Util.all( conditions );
+//      return Mosaic_Quantifier.all( conditions );
     }
 
     public Boolean lookup_0( Mosaic_IO io ) {
       Boolean[] conditions = new Boolean[1];
-      Mosaic_Util.all_set_false( conditions );
+      Mosaic_Quantifier.all_set_false( conditions );
       int i = 0;
         return true;
     }
index 6b11de6..437b91f 100644 (file)
@@ -2,7 +2,7 @@ import java.util.Arrays;
 import java.util.List;
 
 import com.ReasoningTechnology.Mosaic.Mosaic_IO;
-import com.ReasoningTechnology.Mosaic.Mosaic_Util;
+import com.ReasoningTechnology.Mosaic.Mosaic_Quantifier;
 import com.ReasoningTechnology.Mosaic.Mosaic_Testbench;
 
 import com.ReasoningTechnology.Ariadne.Ariadne_Label;
@@ -26,7 +26,7 @@ public class LabelList_0 {
       conditions[i++] = labelList.size() == 2 && labelList.get(0).get().equals("label1") && labelList.get(1).get().equals("label2"); // Expect true for correct size and contents
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
 
   }
index 817e232..f8450fc 100644 (file)
@@ -1,6 +1,6 @@
 
 import com.ReasoningTechnology.Mosaic.Mosaic_IO;
-import com.ReasoningTechnology.Mosaic.Mosaic_Util;
+import com.ReasoningTechnology.Mosaic.Mosaic_Quantifier;
 import com.ReasoningTechnology.Mosaic.Mosaic_Testbench;
 
 import com.ReasoningTechnology.Ariadne.Ariadne_Label;
@@ -26,7 +26,7 @@ public class Label_0 {
       conditions[i++] = label1.hashCode() == label3.hashCode(); // Expect true, as hash should match for equal labels
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
 
   }
index 21dc2a4..b31a3c6 100644 (file)
@@ -1,5 +1,5 @@
 import com.ReasoningTechnology.Mosaic.Mosaic_IO;
-import com.ReasoningTechnology.Mosaic.Mosaic_Util;
+import com.ReasoningTechnology.Mosaic.Mosaic_Quantifier;
 import com.ReasoningTechnology.Mosaic.Mosaic_Testbench;
 
 import com.ReasoningTechnology.Ariadne.Ariadne_Node;
@@ -23,7 +23,7 @@ public class NodeList_0 {
       conditions[i++] = nodeList.size() == 1 && nodeList.contains(node); // Expect true for correct size and content
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
   }
 
index a8754b6..75d826a 100644 (file)
@@ -1,6 +1,6 @@
 
 import com.ReasoningTechnology.Mosaic.Mosaic_IO;
-import com.ReasoningTechnology.Mosaic.Mosaic_Util;
+import com.ReasoningTechnology.Mosaic.Mosaic_Quantifier;
 import com.ReasoningTechnology.Mosaic.Mosaic_Testbench;
 
 import com.ReasoningTechnology.Ariadne.Ariadne_Node;
@@ -26,7 +26,7 @@ public class Node_0 {
       conditions[i++] = node.get("mark") == null; // Expect true
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
 
     public Boolean node_marking_0(Mosaic_IO io) {
@@ -47,7 +47,7 @@ public class Node_0 {
       conditions[i++] = markSet != null && markSet.contains(token1); // Expect true
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
 
     public Boolean node_neighbor_0(Mosaic_IO io) {
@@ -62,7 +62,7 @@ public class Node_0 {
       conditions[i++] = neighbors.size() == 2 && neighbors.get(0).get().equals("neighbor1") && neighbors.get(1).get().equals("neighbor2"); // Expect true
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
   }
 
index 7eecb83..c99fbc1 100644 (file)
@@ -1,5 +1,5 @@
 import com.ReasoningTechnology.Mosaic.Mosaic_IO;
-import com.ReasoningTechnology.Mosaic.Mosaic_Util;
+import com.ReasoningTechnology.Mosaic.Mosaic_Quantifier;
 import com.ReasoningTechnology.Mosaic.Mosaic_Testbench;
 
 import com.ReasoningTechnology.Ariadne.Ariadne_Token;
@@ -23,7 +23,7 @@ public class TokenSet_0 {
       conditions[i++] = tokenSet.size() == 1 && tokenSet.contains(token); // Expect true for correct size and content
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
 
     public Boolean tokenSet_uniqueness_0(Mosaic_IO io) {
@@ -40,7 +40,7 @@ public class TokenSet_0 {
       conditions[i++] = tokenSet.size() == 1 && tokenSet.contains(token1) && tokenSet.contains(token2); // Expect true for single entry despite duplicate addition
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
   }
 
index e248f6f..47cecdd 100644 (file)
@@ -1,5 +1,5 @@
 import com.ReasoningTechnology.Mosaic.Mosaic_IO;
-import com.ReasoningTechnology.Mosaic.Mosaic_Util;
+import com.ReasoningTechnology.Mosaic.Mosaic_Quantifier;
 import com.ReasoningTechnology.Mosaic.Mosaic_Testbench;
 
 import com.ReasoningTechnology.Ariadne.Ariadne_Token;
@@ -24,7 +24,7 @@ public class Token_0 {
       conditions[i++] = !token1.equals(token2); // Expect false, as values differ
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
 
     public Boolean token_hashCode_0(Mosaic_IO io) {
@@ -38,7 +38,7 @@ public class Token_0 {
       conditions[i++] = token1.hashCode() == token2.hashCode(); // Expect true
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
   }
 
index 8e814ea..1edd154 100644 (file)
@@ -1,5 +1,5 @@
 import com.ReasoningTechnology.Mosaic.Mosaic_IO;
-import com.ReasoningTechnology.Mosaic.Mosaic_Util;
+import com.ReasoningTechnology.Mosaic.Mosaic_Quantifier;
 import com.ReasoningTechnology.Mosaic.Mosaic_Testbench;
 
 import com.ReasoningTechnology.Ariadne.Ariadne_Label;
@@ -42,7 +42,7 @@ public class Util_0 {
       conditions[i++] = stdoutContent3.isEmpty(); // Expect no output for null list
 
       // Return true if all conditions are met
-      return Mosaic_Util.all(conditions);
+      return Mosaic_Quantifier.all(conditions);
     }
   }