public class CountingNumber extends Ariadne_SRM<BigInteger>{
+ public static CountingNumber make(BigInteger maximum){
+ return new CountingNumber(maximum);
+ }
+
+ public static CountingNumber make(){
+ return new CountingNumber();
+ }
+
private BigInteger i;
private BigInteger maximum;
- private final State state_null = new State_Null();
- private final State state_segment = new State_Segment();
- private final State state_rightmost = new State_Rightmost();
- private final State state_infinite = new State_Infinite();
+ private final TopoIface<BigInteger> state_null = new ASRM_Null();
+ private final TopoIface<BigInteger> state_segment = new ASRM_Segment();
+ private final TopoIface<BigInteger> state_rightmost = new ASRM_Rightmost();
+ private final TopoIface<BigInteger> state_infinite = new ASRM_Infinite();
- private CountingNumber(BigInteger maximum){
+ public CountingNumber(){
+ this.i = BigInteger.ONE;
+ this.maximum = maximum;
+ set_topology(state_infinite);
+ }
+
+ public CountingNumber(BigInteger maximum){
this.i = BigInteger.ONE;
this.maximum = maximum;
- if( maximum == null ){
- set_state(state_infinite);
- }else if( maximum.compareTo(BigInteger.ZERO) <= 0 ){
- set_state(state_null);
- }else if( maximum.equals(BigInteger.ONE) ){
- set_state(state_rightmost);
- }else{
- set_state(state_segment);
+ if( maximum.compareTo(BigInteger.ZERO) <= 0 ){
+ set_topology( state_null );
+ return;
}
- }
- public static CountingNumber make(BigInteger maximum){
- return new CountingNumber(maximum);
- }
+ if( maximum.equals(BigInteger.ONE) ){
+ set_topology(state_rightmost);
+ return;
+ }
- public static CountingNumber make(){
- return new CountingNumber(null);
+ set_topology(state_segment);
}
- @Override
- public BigInteger read(){
- return i;
- }
- private class State_Null extends State{
+ private class ASRM_Null implements TopoIface<BigInteger>{
@Override
- boolean can_read(){
+ public boolean can_read(){
return false;
}
@Override
- boolean can_step(){
+ public BigInteger read(){
+ return i;
+ }
+ @Override
+ public boolean can_step(){
return false;
}
@Override
- void step(){
- throw new UnsupportedOperationException("Cannot step from NULL state.");
+ public void step(){
+ throw new UnsupportedOperationException( "Cannot step from NULL state." );
}
@Override
- MachineState state(){
- return MachineState.NULL;
+ public Topology topology(){
+ return Topology.NULL;
}
}
- private class State_Segment extends State{
+ private class ASRM_Segment implements TopoIface<BigInteger>{
@Override
- boolean can_read(){
+ public boolean can_read(){
return true;
}
@Override
- boolean can_step(){
+ public BigInteger read(){
+ return i;
+ }
+ @Override
+ public boolean can_step(){
return true;
}
@Override
- void step(){
- i = i.add(BigInteger.ONE);
- if( i.equals(maximum) ){
- set_state(state_rightmost);
+ public void step(){
+ i = i.add( BigInteger.ONE );
+ if( i.equals( maximum ) ){
+ set_topology( state_rightmost );
}
}
@Override
- MachineState state(){
- return MachineState.SEGMENT;
+ public Topology topology(){
+ return Topology.SEGMENT;
}
}
- private class State_Rightmost extends State{
+ private class ASRM_Rightmost implements TopoIface<BigInteger>{
@Override
- boolean can_read(){
+ public boolean can_read(){
return true;
}
@Override
- boolean can_step(){
+ public BigInteger read(){
+ return i;
+ }
+ @Override
+ public boolean can_step(){
return false;
}
@Override
- void step(){
- throw new UnsupportedOperationException("Cannot step from RIGHTMOST.");
+ public void step(){
+ throw new UnsupportedOperationException( "Cannot step from RIGHTMOST." );
}
@Override
- MachineState state(){
- return MachineState.RIGHTMOST;
+ public Topology topology(){
+ return Topology.RIGHTMOST;
}
}
- private class State_Infinite extends State{
+ private class ASRM_Infinite implements TopoIface<BigInteger>{
@Override
- boolean can_read(){
+ public boolean can_read(){
return true;
}
@Override
- boolean can_step(){
+ public BigInteger read(){
+ return i;
+ }
+ @Override
+ public boolean can_step(){
return true;
}
@Override
- void step(){
- i = i.add(BigInteger.ONE);
+ public void step(){
+ i = i.add( BigInteger.ONE );
}
@Override
- MachineState state(){
- return MachineState.INFINITE;
+ public Topology topology(){
+ return Topology.INFINITE;
}
}
-
}
+++ /dev/null
-#!/bin/bash
-java Example_*
+++ /dev/null
-/*
- User defines a graph by implementing this interface. For the build tool, the defined
- graph is dynamically loaded.
-
- Generally labels are returned and passed around. Only `lookup` returns a Node.
-
- In a wellformed graph, the labels returned by `start()` will be in the graph. This
- can be checked by calling `lookup`.
-*/
-
-package com.ReasoningTechnology.Ariadne;
-
-public interface Ariadne_Graph<TLabel> {
-
- // returns list of TLabel
- Ariadne_SRM<TLabel> start();
-
- // lookup a Node by label
- Ariadne_Node<TLabel> lookup(TLabel label);
-
-}
+++ /dev/null
-package com.ReasoningTechnology.Ariadne;
-
-import java.math.BigInteger;
-
-public class Ariadne_IndexTree_Child_SRM extends Ariadne_SRMI<BigInteger[]>{
-
- private BigInteger[] label;
-
- public static Ariadne_IndexTree_Child_SRM make(BigInteger[] initial_label){
- return new Ariadne_IndexTree_Child_SRM(initial_label);
- }
-
- protected Ariadne_IndexTree_Child_SRM(BigInteger[] initial_label){
- super(BigInteger.ZERO ,null);
- if(initial_label == null || initial_label.length == 0){
- throw new IllegalArgumentException("Initial label must not be null or empty.");
- }
- this.label = initial_label;
- set_state(state_infinite_right);
- }
-
- private final Ariadne_SRM.State state_infinite_right = new Ariadne_SRM.State(){
- @Override boolean can_read(){
- return true;
- }
- @Override boolean can_step(){
- return true;
- }
- @Override void step(){
- increment_label();
- }
- @Override Ariadne_SRM.MachineState state(){
- return Ariadne_SRM.MachineState.INFINITE;
- }
- };
-
- private void increment_label(){
- label[label.length - 1] = super.index();
- }
-
- @Override public void step(){
- super.step();
- label[label.length - 1] = super.index();
- }
-
- @Override public BigInteger[] read(){
- return label;
- }
-}
+++ /dev/null
-package com.ReasoningTechnology.Ariadne;
-
-import java.math.BigInteger;
-
-public class Ariadne_IndexTree_Graph implements Ariadne_Graph<BigInteger[]>{
-
- @Override
- public Ariadne_IndexTree_Child_SRM start(){
- return Ariadne_IndexTree_Child_SRM.make(new BigInteger[0]);
- }
-
- @Override
- public Ariadne_IndexTree_Node lookup(BigInteger[] label){
- return Ariadne_IndexTree_Node.make(label);
- }
-
-}
-
+++ /dev/null
-package com.ReasoningTechnology.Ariadne;
-
-import java.math.BigInteger;
-import java.util.Arrays;
-
-public class Ariadne_IndexTree_Node extends Ariadne_Node<BigInteger[]>{
-
- public static Ariadne_IndexTree_Node make(BigInteger[] label){
- return new Ariadne_IndexTree_Node(label);
- }
-
- private final BigInteger[] first_child_label;
-
- public Ariadne_IndexTree_Node(BigInteger[] label){
- super(label);
- this.first_child_label = new BigInteger[label.length + 1];
- System.arraycopy(label, 0, this.first_child_label, 0, label.length);
- this.first_child_label[label.length] = BigInteger.ZERO;
- }
-
- @Override
- public Ariadne_IndexTree_Child_SRM neighbor(){
- return Ariadne_IndexTree_Child_SRM.make(first_child_label);
- }
-
- @Override
- public String toString(){
- return
- "<"
- + String.join("," ,Arrays.stream(label()).map(BigInteger::toString).toArray(String[]::new))
- + ">";
- }
-}
+++ /dev/null
-package com.ReasoningTechnology.Ariadne;
-
-
-
-/*
- A value for the node.label property.
-
- This is a wrapper for a String. We can't instead use an alias by extending
- String, because String is a JavaScript 'final' type.
-
-*/
-public class Ariadne_Label{
-
- // owned by class
-
-
- // data owned by instance
-
- private final String value;
-
- // constructors
-
-
- private Ariadne_Label(String s){
- this.value = s;
- }
-
- Ariadne_Label make(String s){
- return new Ariadne_Label(s);
- }
-
- public boolean isEmpty(){
- return value.isEmpty();
- }
-
- @Override
- public String toString(){
- return value;
- }
-
- @Override
- public boolean equals(Object o){
- if(this == o) return true;
- if( o == null || getClass() != o.getClass() ) return false;
- Ariadne_Label label = (Ariadne_Label)o;
- return value.equals( label.value );
- }
-
- @Override
- public int hashCode(){
- return value.hashCode();
- }
-
-}
+++ /dev/null
-/*
-A node extends a Map. This map is for use by the user to add properties to the node.
-It is not used by the Ariadne code. The class itself is already a sort of map, so
-node specific fields are expressed in the class itself.
-
-Node specific fields include the node label, and a set for Ariadne algorithms
-to use when adding token marks to nodes. An extension will have to add
-a function or data set to hold the labels of neighboring nodes.
-
-Currently node labels are strings. I should probably have made them a
-generic type.
-
-A graph itself is a similar data structure to the Node. A graph is defined by its
-lookup function, that makes it a map. Also there is a start function that returns
-node labels, while a node has 'neighbor' which returns node labels. Here are the
-differences:
-
- The graph type lookup implementation is not constrained to any type, and
- could be a function. The node lookup comes from a HashMap, and thus is
- guaranteed to have a finite number of entries.
-
- The graph type is defined by the user, where as the node type is defined
- by the programmer who is creating a graph based application.
-
-We should take a closer look at the possibility of unifying these later.
-
-*/
-
-package com.ReasoningTechnology.Ariadne;
-
-import java.util.HashMap;
-import java.util.HashSet;
-
-public class Ariadne_Node<TLabel> extends HashMap<String, Object> {
-
- // Owned by the class
- public static <TLabel> Ariadne_Node<TLabel> make(TLabel label) {
- return new Ariadne_Node<>(label);
- }
-
- // Data owned by the instance
- private final TLabel label;
- private final HashSet<Ariadne_Token> markSet;
- private static final String NEIGHBOR_PROPERTY_NAME = "neighbor_property";
-
- // Constructors
- public Ariadne_Node(TLabel label) {
- super();
- this.label = label;
- this.markSet = new HashSet<>();
- }
-
- // Instance interface
- public TLabel label() {
- return this.label;
- }
-
- public Ariadne_SRM<TLabel> neighbor(){
- throw new UnsupportedOperationException("Neighbor is not implemented in the base class.");
- }
-
- public void mark(Ariadne_Token token) {
- markSet.add(token);
- }
-
- public boolean hasMark(Ariadne_Token token) {
- return markSet.contains(token);
- }
-
- public void removeMark(Ariadne_Token token) {
- markSet.remove(token);
- }
-
- // Object interface
- @Override
- public String toString() {
- return "Ariadne_Node{"
- + "label=" + label
- + " ,markSet=" + markSet
- + "}";
- }
-}
*/
package com.ReasoningTechnology.Ariadne;
-public abstract class Ariadne_SRM<T>{
+public class Ariadne_SRM<T>{
- public enum MachineState{
+ public enum Topology{
NULL
,CYCLIC
,SEGMENT
;
}
- protected abstract class State{
- abstract boolean can_read();
- abstract boolean can_step();
- abstract void step();
- abstract MachineState state();
+ public static <TElement> Ariadne_SRM<TElement> make(){
+ return new Ariadne_SRM<>();
}
- protected State current_state;
+ protected TopoIface<T> current_topology;
+ public final TopoIface<T> not_mounted = new NotMounted();
- protected void set_state(State new_state){
- this.current_state = new_state;
+ protected Ariadne_SRM(){
+ set_topology(not_mounted);
+ }
+
+ public boolean is_mounted(){
+ return
+ current_topology != null
+ && current_topology != not_mounted;
+ }
+
+ // Interface for interacting with a tape.
+ protected interface TopoIface<T>{
+ boolean can_read();
+ T read();
+ boolean can_step();
+ void step();
+ Topology topology();
+ }
+
+ // Initially the tape has not been mounted so it can not be interacted with.
+ protected class NotMounted implements TopoIface<T>{
+ public boolean can_read(){
+ return false;
+ }
+ public T read(){
+ throw new UnsupportedOperationException("Ariadne_SRM::NotMounted::read.");
+ }
+ public boolean can_step(){
+ return false;
+ }
+ public void step(){
+ throw new UnsupportedOperationException("Ariadne_SRM::NotMounted::step.");
+ }
+ public Topology topology(){
+ throw new UnsupportedOperationException("Ariadne_SRM::NotMounted::topology.");
+ }
+ }
+
+ // sets the tape access methods to be used
+ protected void set_topology(TopoIface<T> new_topology){
+ current_topology = new_topology;
}
public boolean can_read(){
- return current_state.can_read();
+ return current_topology.can_read();
+ }
+ public T read(){
+ return current_topology.read();
}
public boolean can_step(){
- return current_state.can_step();
+ return current_topology.can_step();
}
public void step(){
- current_state.step();
+ current_topology.step();
}
- public MachineState state(){
- return current_state.state();
+ public Topology topology(){
+ return current_topology.topology();
}
- public abstract T read();
}
+++ /dev/null
-/*
-Ariadne_SRM with index
-
-*/
-
-package com.ReasoningTechnology.Ariadne;
-import java.math.BigInteger;
-
-public abstract class Ariadne_SRMI<T> extends Ariadne_SRM<T>{
-
- private BigInteger current_index;
- private final BigInteger leftmost_index;
- private final BigInteger rightmost_index;
-
- public Ariadne_SRMI(BigInteger leftmost_index, BigInteger rightmost_index){
- if(leftmost_index == null
- || rightmost_index == null
- || leftmost_index.compareTo(rightmost_index) > 0
- ){
- throw new IllegalArgumentException("Invalid tape bounds.");
- }
- this.leftmost_index = leftmost_index;
- this.rightmost_index = rightmost_index;
- this.current_index = leftmost_index;
- }
-
- public BigInteger index(){
- return current_index;
- }
-
- public BigInteger leftmost_index(){
- return leftmost_index;
- }
-
- public BigInteger rightmost_index(){
- return rightmost_index;
- }
-
- public void seek(BigInteger new_index){
- if(new_index.compareTo(leftmost_index) < 0 || new_index.compareTo(rightmost_index) > 0){
- throw new IndexOutOfBoundsException("Index out of bounds.");
- }
- this.current_index = new_index;
- }
-
- @Override
- public void step(){
- current_state.step();
- current_index = current_index.add(BigInteger.ONE);
- }
-}
+++ /dev/null
-package com.ReasoningTechnology.Ariadne;
-
-import java.math.BigInteger;
-import java.util.List;
-
-public class Ariadne_SRMI_Array<TElement> extends Ariadne_SRMI<TElement> {
-
- private final List<TElement> array;
-
- public Ariadne_SRMI_Array(List<TElement> array) {
- super(BigInteger.ZERO, array == null || array.isEmpty() ? BigInteger.ZERO : BigInteger.valueOf(array.size() - 1));
-
- if (array == null || array.isEmpty()) {
- set_state(state_null);
- } else if (array.size() == 1) {
- set_state(state_rightmost);
- } else {
- set_state(state_segment);
- }
-
- this.array = array;
- }
-
- @Override
- public TElement read() {
- if (!can_read()) {
- throw new UnsupportedOperationException("Cannot read from the current state.");
- }
- return array.get(index().intValueExact());
- }
-
- private final State state_null = new State() {
- @Override
- boolean can_read() {
- return false;
- }
- @Override
- boolean can_step() {
- return false;
- }
- @Override
- void step() {
- throw new UnsupportedOperationException("Cannot step from NULL state.");
- }
- @Override
- MachineState state() {
- return MachineState.NULL;
- }
- };
-
- private final State state_segment = new State() {
- @Override
- boolean can_read() {
- return true;
- }
- @Override
- boolean can_step() {
- return index().compareTo(rightmost_index().subtract(BigInteger.ONE)) < 0;
- }
- @Override
- void step() {
- if (can_step()) {
- seek(index().add(BigInteger.ONE));
- } else {
- set_state(state_rightmost);
- }
- }
- @Override
- MachineState state() {
- return MachineState.SEGMENT;
- }
- };
-
- private final State state_rightmost = new State() {
- @Override
- boolean can_read() {
- return true;
- }
- @Override
- boolean can_step() {
- return false;
- }
- @Override
- void step() {
- throw new UnsupportedOperationException("Cannot step from RIGHTMOST state.");
- }
- @Override
- MachineState state() {
- return MachineState.RIGHTMOST;
- }
- };
-}
}
}
- private final State state_null = new State(){
- @Override
- boolean can_read(){
+ private final ASRM state_null = new ASRM(){
+ @Override public boolean can_read(){
return false;
}
- @Override
- boolean can_step(){
+ @Override public void read(){
+ throw new UnsupportedOperationException("Cannot read from NULL state.");
+ }
+ @Override public boolean can_step(){
return false;
}
- @Override
- void step(){
+ @Override public void step(){
throw new UnsupportedOperationException("Cannot step from NULL state.");
}
- @Override
- MachineState state(){
- return MachineState.NULL;
+ @Override public State state(){
+ return State.NULL;
}
};
- private final State state_segment = new State(){
- @Override
- boolean can_read(){
+ private final ASRM state_segment = new ASRM(){
+ @Override public boolean can_read(){
return true;
}
- @Override
- boolean can_step(){
+ @Override public void read(){
+ return list.get(current_index);
+ }
+ @Override public boolean can_step(){
return current_index < list.size() - 1;
}
- @Override
- void step(){
+ @Override public void step(){
if(can_step()){
current_index++;
}else{
set_state(state_rightmost);
}
}
- @Override
- MachineState state(){
- return MachineState.SEGMENT;
+ @Override public State state(){
+ return State.SEGMENT;
}
};
- private final State state_rightmost = new State(){
- @Override
- boolean can_read(){
+ private final ASRM state_rightmost = new ASRM(){
+ @Override public boolean can_read(){
return true;
}
- @Override
- boolean can_step(){
+ @Override public void read(){
+ return list.get(current_index);
+ }
+ @Override public boolean can_step(){
return false;
}
- @Override
- void step(){
+ @Override public void step(){
throw new UnsupportedOperationException("Cannot step from RIGHTMOST state.");
}
- @Override
- MachineState state(){
- return MachineState.RIGHTMOST;
+ @Override public State state(){
+ return State.RIGHTMOST;
}
};
- @Override
- public T read(){
- if(!can_read()){
- throw new UnsupportedOperationException("Cannot read from NULL state.");
- }
- return list.get(current_index);
- }
}
+++ /dev/null
-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);
- }
- }
-}
+++ /dev/null
-package com.ReasoningTechnology.Ariadne;
-
-/*
-An error token.
-
-*/
-public class Ariadne_Token {
- private final String value;
-
- public Ariadne_Token(String value){
- this.value = value;
- }
-
- public String get(){
- return value;
- }
-
- @Override
- public String toString(){
- return value;
- }
-
- @Override
- public boolean equals(Object o){
- if(this == o) return true; // No padding, not nested
- if( o == null || getClass() != o.getClass() ) return false; // Padded, because it's nested
- Ariadne_Token token = (Ariadne_Token)o;
- return value.equals( token.value );
- }
-
- @Override
- public int hashCode(){
- return value.hashCode();
- }
-}
+++ /dev/null
-// TokenSet.java
-package com.ReasoningTechnology.Ariadne;
-import java.util.HashSet;
-
-public class Ariadne_TokenSet extends HashSet<Ariadne_Token> {
- // Constructor
- public Ariadne_TokenSet(){
- super();
- }
-}
+++ /dev/null
-package com.ReasoningTechnology.Ariadne;
-import java.util.List;
-
-public class Ariadne_Util{
- static boolean debug = false;
-
- public static void print_list(String prefix ,List<?> item_list){
- if( item_list == null || item_list.isEmpty() ){
- return;
- }
- if( prefix != null && !prefix.isEmpty() ){
- System.out.print(prefix);
- }
- int i = 0;
- int n = item_list.size() - 1;
- System.out.print( " '" + item_list.get(i) + "'" );
- do{
- i++;
- if( i > n ) break;
- System.out.print(", " + "'" + item_list.get(i) + "'");
- }while( true );
- System.out.println(".");
- }
-
-}
+++ /dev/null
-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);
- }
-
-}
+++ /dev/null
-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;
- }
- });
- }
-}
--- /dev/null
+/*
+ User defines a graph by implementing this interface. For the build tool, the defined
+ graph is dynamically loaded.
+
+ Generally labels are returned and passed around. Only `lookup` returns a Node.
+
+ In a wellformed graph, the labels returned by `start()` will be in the graph. This
+ can be checked by calling `lookup`.
+*/
+
+package com.ReasoningTechnology.Ariadne;
+
+public interface Ariadne_Graph<TLabel> {
+
+ // returns list of TLabel
+ Ariadne_SRM<TLabel> start();
+
+ // lookup a Node by label
+ Ariadne_Node<TLabel> lookup(TLabel label);
+
+}
--- /dev/null
+package com.ReasoningTechnology.Ariadne;
+
+import java.math.BigInteger;
+
+public class Ariadne_IndexTree_Child_SRM extends Ariadne_SRMI<BigInteger[]>{
+
+ private BigInteger[] label;
+
+ public static Ariadne_IndexTree_Child_SRM make(BigInteger[] initial_label){
+ return new Ariadne_IndexTree_Child_SRM(initial_label);
+ }
+
+ protected Ariadne_IndexTree_Child_SRM(BigInteger[] initial_label){
+ super(BigInteger.ZERO ,null);
+ if(initial_label == null || initial_label.length == 0){
+ throw new IllegalArgumentException("Initial label must not be null or empty.");
+ }
+ this.label = initial_label;
+ set_state(state_infinite_right);
+ }
+
+ private final Ariadne_SRM.ASRM state_infinite_right = new Ariadne_SRM.ASRM(){
+ @Override public boolean can_read(){
+ return true;
+ }
+ @Override public BigInteger[] read(){
+ return label;
+ }
+ @Override public boolean can_step(){
+ return true;
+ }
+ @Override public void step(){
+ label[label.length - 1] = super.index();
+ }
+ @Override public Ariadne_SRM.State state(){
+ return Ariadne_SRM.State.INFINITE;
+ }
+ };
+
+}
--- /dev/null
+package com.ReasoningTechnology.Ariadne;
+
+import java.math.BigInteger;
+
+public class Ariadne_IndexTree_Graph implements Ariadne_Graph<BigInteger[]>{
+
+ @Override
+ public Ariadne_IndexTree_Child_SRM start(){
+ return Ariadne_IndexTree_Child_SRM.make(new BigInteger[0]);
+ }
+
+ @Override
+ public Ariadne_IndexTree_Node lookup(BigInteger[] label){
+ return Ariadne_IndexTree_Node.make(label);
+ }
+
+}
+
--- /dev/null
+package com.ReasoningTechnology.Ariadne;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+public class Ariadne_IndexTree_Node extends Ariadne_Node<BigInteger[]>{
+
+ public static Ariadne_IndexTree_Node make(BigInteger[] label){
+ return new Ariadne_IndexTree_Node(label);
+ }
+
+ private final BigInteger[] first_child_label;
+
+ public Ariadne_IndexTree_Node(BigInteger[] label){
+ super(label);
+ this.first_child_label = new BigInteger[label.length + 1];
+ System.arraycopy(label, 0, this.first_child_label, 0, label.length);
+ this.first_child_label[label.length] = BigInteger.ZERO;
+ }
+
+ @Override
+ public Ariadne_IndexTree_Child_SRM neighbor(){
+ return Ariadne_IndexTree_Child_SRM.make(first_child_label);
+ }
+
+ @Override
+ public String toString(){
+ return
+ "<"
+ + String.join("," ,Arrays.stream(label()).map(BigInteger::toString).toArray(String[]::new))
+ + ">";
+ }
+}
--- /dev/null
+package com.ReasoningTechnology.Ariadne;
+
+
+
+/*
+ A value for the node.label property.
+
+ This is a wrapper for a String. We can't instead use an alias by extending
+ String, because String is a JavaScript 'final' type.
+
+*/
+public class Ariadne_Label{
+
+ // owned by class
+
+
+ // data owned by instance
+
+ private final String value;
+
+ // constructors
+
+
+ private Ariadne_Label(String s){
+ this.value = s;
+ }
+
+ Ariadne_Label make(String s){
+ return new Ariadne_Label(s);
+ }
+
+ public boolean isEmpty(){
+ return value.isEmpty();
+ }
+
+ @Override
+ public String toString(){
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o){
+ if(this == o) return true;
+ if( o == null || getClass() != o.getClass() ) return false;
+ Ariadne_Label label = (Ariadne_Label)o;
+ return value.equals( label.value );
+ }
+
+ @Override
+ public int hashCode(){
+ return value.hashCode();
+ }
+
+}
--- /dev/null
+/*
+A node extends a Map. This map is for use by the user to add properties to the node.
+It is not used by the Ariadne code. The class itself is already a sort of map, so
+node specific fields are expressed in the class itself.
+
+Node specific fields include the node label, and a set for Ariadne algorithms
+to use when adding token marks to nodes. An extension will have to add
+a function or data set to hold the labels of neighboring nodes.
+
+Currently node labels are strings. I should probably have made them a
+generic type.
+
+A graph itself is a similar data structure to the Node. A graph is defined by its
+lookup function, that makes it a map. Also there is a start function that returns
+node labels, while a node has 'neighbor' which returns node labels. Here are the
+differences:
+
+ The graph type lookup implementation is not constrained to any type, and
+ could be a function. The node lookup comes from a HashMap, and thus is
+ guaranteed to have a finite number of entries.
+
+ The graph type is defined by the user, where as the node type is defined
+ by the programmer who is creating a graph based application.
+
+We should take a closer look at the possibility of unifying these later.
+
+*/
+
+package com.ReasoningTechnology.Ariadne;
+
+import java.util.HashMap;
+import java.util.HashSet;
+
+public class Ariadne_Node<TLabel> extends HashMap<String, Object>{
+
+ // Owned by the class
+ public static <TLabel> Ariadne_Node<TLabel> make(TLabel label){
+ return new Ariadne_Node<>(label);
+ }
+
+ // Data owned by the instance
+ private final TLabel label;
+ private final HashSet<Ariadne_Token> markSet;
+ private static final String NEIGHBOR_PROPERTY_NAME = "neighbor_property";
+
+ // Constructors
+ protected Ariadne_Node(TLabel label){
+ super();
+ this.label = label;
+ this.markSet = new HashSet<>();
+ }
+
+ // Instance interface
+ public TLabel label(){
+ return this.label;
+ }
+
+ public Ariadne_SRM<TLabel> neighbor(){
+ throw new UnsupportedOperationException("Neighbor is not implemented in the base class.");
+ }
+
+ public void mark(Ariadne_Token token){
+ markSet.add(token);
+ }
+
+ public boolean hasMark(Ariadne_Token token){
+ return markSet.contains(token);
+ }
+
+ public void removeMark(Ariadne_Token token){
+ markSet.remove(token);
+ }
+
+ // Object interface
+ @Override
+ public String toString(){
+ return "Ariadne_Node{"
+ + "label=" + label
+ + " ,markSet=" + markSet
+ + "}";
+ }
+}
--- /dev/null
+/*
+Ariadne_SRM with index
+
+*/
+
+package com.ReasoningTechnology.Ariadne;
+import java.math.BigInteger;
+
+public abstract class Ariadne_SRMI<T> extends Ariadne_SRM<T>{
+
+ private BigInteger current_index;
+ private final BigInteger leftmost_index;
+ private final BigInteger rightmost_index;
+
+ public static
+
+ public Ariadne_SRMI(BigInteger leftmost_index, BigInteger rightmost_index){
+ if(leftmost_index == null
+ || rightmost_index == null
+ || leftmost_index.compareTo(rightmost_index) > 0
+ ){
+ throw new IllegalArgumentException("Invalid tape bounds.");
+ }
+ this.leftmost_index = leftmost_index;
+ this.rightmost_index = rightmost_index;
+ this.current_index = leftmost_index;
+ }
+
+ public BigInteger index(){
+ return current_index;
+ }
+
+ public BigInteger leftmost_index(){
+ return leftmost_index;
+ }
+
+ public BigInteger rightmost_index(){
+ return rightmost_index;
+ }
+
+ public void seek(BigInteger new_index){
+ if(new_index.compareTo(leftmost_index) < 0 || new_index.compareTo(rightmost_index) > 0){
+ throw new IndexOutOfBoundsException("Index out of bounds.");
+ }
+ this.current_index = new_index;
+ }
+
+ @Override
+ public void step(){
+ super.step();
+ current_index = current_index.add(BigInteger.ONE);
+ }
+}
--- /dev/null
+package com.ReasoningTechnology.Ariadne;
+
+import java.math.BigInteger;
+import java.util.List;
+
+public class Ariadne_SRMI_Array<T> extends Ariadne_SRMI<T>{
+
+ private final List<T> array;
+
+ public Ariadne_SRMI_Array(List<T> array){
+ super(BigInteger.ZERO, array == null || array.isEmpty() ? BigInteger.ZERO : BigInteger.valueOf(array.size() - 1));
+
+ if (array == null || array.isEmpty()){
+ set_state(state_null);
+ } else if (array.size() == 1){
+ set_state(state_rightmost);
+ } else{
+ set_state(state_segment);
+ }
+
+ this.array = array;
+ }
+
+ private final ASRM state_null = new ASRM(){
+ @Override public boolean can_read(){
+ return false;
+ }
+ @Override public T read(){
+ throw new UnsupportedOperationException("Cannot read from NULL state.");
+ }
+ @Override public boolean can_step(){
+ return false;
+ }
+ @Override public void step(){
+ throw new UnsupportedOperationException("Cannot step from NULL state.");
+ }
+ @Override public State state(){
+ return State.NULL;
+ }
+ };
+
+ private final ASRM state_segment = new ASRM(){
+ @Override public boolean can_read(){
+ return true;
+ }
+ @Override public void read(){
+ return array.get(index().intValueExact());
+ }
+ @Override public boolean can_step(){
+ return index().compareTo(rightmost_index().subtract(BigInteger.ONE)) < 0;
+ }
+ @Override public void step(){
+ if (can_step()){
+ seek(index().add(BigInteger.ONE));
+ } else{
+ set_state(state_rightmost);
+ }
+ }
+ @Override public State state(){
+ return State.SEGMENT;
+ }
+ };
+
+ private final ASRM state_rightmost = new ASRM(){
+ @Override public boolean can_read(){
+ return true;
+ }
+ @Override public void read(){
+ return array.get(index().intValueExact());
+ }
+ @Override public boolean can_step(){
+ return false;
+ }
+ @Override public void step(){
+ throw new UnsupportedOperationException("Cannot step from RIGHTMOST state.");
+ }
+ @Override public State state(){
+ return State.RIGHTMOST;
+ }
+ };
+}
--- /dev/null
+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);
+ }
+ }
+}
--- /dev/null
+package com.ReasoningTechnology.Ariadne;
+
+/*
+An error token.
+
+*/
+public class Ariadne_Token {
+ private final String value;
+
+ public Ariadne_Token(String value){
+ this.value = value;
+ }
+
+ public String get(){
+ return value;
+ }
+
+ @Override
+ public String toString(){
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o){
+ if(this == o) return true; // No padding, not nested
+ if( o == null || getClass() != o.getClass() ) return false; // Padded, because it's nested
+ Ariadne_Token token = (Ariadne_Token)o;
+ return value.equals( token.value );
+ }
+
+ @Override
+ public int hashCode(){
+ return value.hashCode();
+ }
+}
--- /dev/null
+// TokenSet.java
+package com.ReasoningTechnology.Ariadne;
+import java.util.HashSet;
+
+public class Ariadne_TokenSet extends HashSet<Ariadne_Token> {
+ // Constructor
+ public Ariadne_TokenSet(){
+ super();
+ }
+}
--- /dev/null
+package com.ReasoningTechnology.Ariadne;
+import java.util.List;
+
+public class Ariadne_Util{
+ static boolean debug = false;
+
+ public static void print_list(String prefix ,List<?> item_list){
+ if( item_list == null || item_list.isEmpty() ){
+ return;
+ }
+ if( prefix != null && !prefix.isEmpty() ){
+ System.out.print(prefix);
+ }
+ int i = 0;
+ int n = item_list.size() - 1;
+ System.out.print( " '" + item_list.get(i) + "'" );
+ do{
+ i++;
+ if( i > n ) break;
+ System.out.print(", " + "'" + item_list.get(i) + "'");
+ }while( true );
+ System.out.println(".");
+ }
+
+}
--- /dev/null
+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);
+ }
+
+}
--- /dev/null
+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;
+ }
+ });
+ }
+}