diff --git a/src/com/characterforming/jrte/engine/Model.java b/src/com/characterforming/jrte/engine/Model.java index 87f563b..c09d31c 100644 --- a/src/com/characterforming/jrte/engine/Model.java +++ b/src/com/characterforming/jrte/engine/Model.java @@ -87,10 +87,9 @@ public record Argument(int transducerOrdinal, BytesArray tokens) {} protected final Logger rtcLogger; protected final Logger rteLogger; protected HashMap signalOrdinalMap; - protected HashMap fieldOrdinalMap; protected HashMap effectorOrdinalMap; protected HashMap transducerOrdinalMap; - protected HashMap> transducerFieldMaps; + protected HashMap> transducerFieldMaps; protected IEffector[] proxyEffectors; protected long[] transducerOffsetIndex; protected Bytes[] transducerNameIndex; @@ -121,14 +120,11 @@ protected Model(final File modelPath, Class targetClass, TargetMode targetMod this.modelVersion = Base.RTE_VERSION; this.modelPath = modelPath; this.deleteOnClose = true; - this.fieldOrdinalMap = new HashMap<>(256); this.signalOrdinalMap = new HashMap<>(256); this.transducerOrdinalMap = new HashMap<>(256); this.transducerOffsetIndex = new long[256]; this.transducerNameIndex = new Bytes[256]; this.transducerFieldMaps = new HashMap<>(256); - this.fieldOrdinalMap.put(new Bytes(Model.ANONYMOUS_FIELD_NAME), Model.ANONYMOUS_FIELD_ORDINAL); - this.fieldOrdinalMap.put(new Bytes(Model.ALL_FIELDS_NAME), Model.ALL_FIELDS_ORDINAL); this.initializeProxyEffectors(); for (Signal signal : Signal.values()) if (!signal.isNone()) { @@ -250,17 +246,12 @@ protected boolean save(Argument[][] effectorParameters) { if (this.transducerOrdinalMap.size() > 0) { this.writeOrdinalMap(signalOrdinalMap, Base.RTE_SIGNAL_BASE); this.writeOrdinalMap(effectorOrdinalMap, 0); - this.writeOrdinalMap(this.fieldOrdinalMap, 0); this.writeOrdinalMap(transducerOrdinalMap, 0); int transducerCount = this.transducerOrdinalMap.size(); for (int transducerOrdinal = 0; transducerOrdinal < transducerCount; transducerOrdinal++) { this.writeBytes(this.transducerNameIndex[transducerOrdinal].bytes()); this.writeLong(this.transducerOffsetIndex[transducerOrdinal]); - HashMap localFieldMap = this.transducerFieldMaps.get(transducerOrdinal); - int[] localFields = new int[localFieldMap.size()]; - for (Entry e : localFieldMap.entrySet()) - localFields[e.getValue()] = e.getKey(); - this.writeIntArray(localFields); + this.writeOrdinalMap(this.transducerFieldMaps.get(transducerOrdinal), 0); } for (int effectorOrdinal = 0; effectorOrdinal < this.effectorOrdinalMap.size(); effectorOrdinal++) { Argument[] arguments = effectorParameters[effectorOrdinal]; @@ -274,9 +265,9 @@ protected boolean save(Argument[][] effectorParameters) { this.writeLong(indexPosition); this.map(mapFile); String stats = String.format( - "%1$s: target class %2$s%n%3$d transducers; %4$d effectors; %5$d fields; %6$d signal ordinals%n", + "%1$s: target class %2$s%n%3$d transducers; %4$d effectors; %5$d signal ordinals%n", this.modelPath.getPath(), this.targetClass.getName(), transducerCount, - this.effectorOrdinalMap.size(), this.getFieldCount(), this.getSignalCount()); + this.effectorOrdinalMap.size(), this.getSignalCount()); this.rtcLogger.log(Level.INFO, () -> stats); this.deleteOnClose = false; System.out.println(stats); @@ -316,7 +307,6 @@ protected Model load() throws ModelException, CharacterCodingException { this.seek(indexPosition); this.signalOrdinalMap = this.readOrdinalMap(Base.RTE_SIGNAL_BASE); this.effectorOrdinalMap = this.readOrdinalMap(0); - this.fieldOrdinalMap = this.readOrdinalMap(0); this.transducerOrdinalMap = this.readOrdinalMap(0); int transducerCount = this.transducerOrdinalMap.size(); this.transducerNameIndex = new Bytes[transducerCount]; @@ -324,13 +314,7 @@ protected Model load() throws ModelException, CharacterCodingException { for (int transducerOrdinal = 0; transducerOrdinal < transducerCount; transducerOrdinal++) { this.transducerNameIndex[transducerOrdinal] = new Bytes(this.readBytes()); this.transducerOffsetIndex[transducerOrdinal] = this.readLong(); - int[] fields = this.readIntArray(); - HashMap localFieldMap = new HashMap<>(fields.length); - for (int i = 0; i < fields.length; i++) { - localFieldMap.computeIfAbsent(fields[i], absent -> localFieldMap.size()); - assert i == localFieldMap.getOrDefault(fields[i], -1); - } - this.transducerFieldMaps.put(transducerOrdinal, localFieldMap); + this.transducerFieldMaps.put(transducerOrdinal, this.readOrdinalMap(0)); assert this.transducerOrdinalMap.get(this.transducerNameIndex[transducerOrdinal]) == transducerOrdinal; } this.initializeProxyEffectors(); @@ -383,19 +367,16 @@ public boolean map(PrintStream mapWriter) { for (int i = 0; i < signalIndex.length; i++) mapWriter.printf("%1$6d signal %2$s%n", i + Base.RTE_SIGNAL_BASE, signalIndex[i].asString()); - Bytes[] fieldIndex = new Bytes[this.fieldOrdinalMap.size()]; - for (Map.Entry m : this.fieldOrdinalMap.entrySet()) - fieldIndex[m.getValue()] = m.getKey(); Bytes[] transducerIndex = new Bytes[this.transducerOrdinalMap.size()]; for (Map.Entry m : this.transducerOrdinalMap.entrySet()) transducerIndex[m.getValue()] = m.getKey(); for (int transducerOrdinal = 0; transducerOrdinal < transducerIndex.length; transducerOrdinal++) { mapWriter.printf("%1$6d transducer %2$s%n", transducerOrdinal, transducerIndex[transducerOrdinal].asString()); - Map fieldMap = this.transducerFieldMaps.get(transducerOrdinal); + Map fieldMap = this.transducerFieldMaps.get(transducerOrdinal); Bytes[] fields = new Bytes[fieldMap.size()]; - for (Entry e : fieldMap.entrySet()) - fields[e.getValue()] = fieldIndex[e.getKey()]; + for (Entry e : fieldMap.entrySet()) + fields[e.getValue()] = e.getKey(); for (int field = 0; field < fields.length; field++) mapWriter.printf("%1$6d field ~%2$s%n", field, fields[field].asString()); @@ -504,15 +485,15 @@ protected File getModelPath() { } protected Integer getInputOrdinal(final byte[] input) throws CompilationException, CharacterCodingException { - if (input.length == 1) - return Byte.toUnsignedInt(input[0]); - else { + if (input.length > 1) { Integer ordinal = this.getSignalOrdinal(new Bytes(input)); - if (ordinal < 0) - throw new CompilationException(String.format("Invalid input token %s", - Codec.decode(input, input.length))); - return ordinal; + if (ordinal >= 0) + return ordinal; + } else if (input.length > 0) { + return Byte.toUnsignedInt(input[0]); } + throw new CompilationException(String.format("Invalid input token '%s'", + Codec.decode(input, input.length))); } protected int getSignalCount() { @@ -527,46 +508,21 @@ protected Integer getSignalOrdinal(final Bytes name) { return this.signalOrdinalMap.get(name); } - protected int getFieldCount() { - return this.fieldOrdinalMap.size(); - } - protected int getFieldCount(int transducerOrdinal) { return this.transducerFieldMaps.containsKey(transducerOrdinal) ? this.transducerFieldMaps.get(transducerOrdinal).size() : 0; } - protected int getFieldOrdinal(Bytes fieldName) { - return this.fieldOrdinalMap.getOrDefault(fieldName, -1); + protected int addField(int transducerOrdinal, Bytes fieldName) { + HashMap fieldMap = this.transducerFieldMaps.getOrDefault(transducerOrdinal, null); + final int mapSize = fieldMap.size(); + return fieldMap.computeIfAbsent(fieldName, absent-> mapSize); } - protected int addField(Bytes fieldName) { - final int mapSize = this.fieldOrdinalMap.size(); - return this.fieldOrdinalMap.computeIfAbsent(fieldName, absent-> mapSize); - } - - protected HashMap newLocalField(int transducerOrdinal) { - HashMap localFieldMap = this.transducerFieldMaps.computeIfAbsent( - transducerOrdinal, absent -> new HashMap<>(256)); - if (localFieldMap.isEmpty()) { - localFieldMap.put(this.fieldOrdinalMap.get(Model.ANONYMOUS_FIELD_BYTES), - Model.ANONYMOUS_FIELD_ORDINAL); - localFieldMap.put(this.fieldOrdinalMap.get(Model.ALL_FIELDS_BYTES), - Model.ALL_FIELDS_ORDINAL); - } - return localFieldMap; - } - - protected int addLocalField(int transducerOrdinal, int fieldOrdinal) { - HashMap localFieldMap = this.newLocalField(transducerOrdinal); - assert localFieldMap.get(Model.ANONYMOUS_FIELD_ORDINAL) == Model.ANONYMOUS_FIELD_ORDINAL; - assert localFieldMap.get(Model.ALL_FIELDS_ORDINAL) == Model.ALL_FIELDS_ORDINAL; - return localFieldMap.computeIfAbsent(fieldOrdinal, absent -> localFieldMap.size()); - } - - protected int getLocalField(int transducerOrdinal, int fieldOrdinal) { - return this.newLocalField(transducerOrdinal).getOrDefault(fieldOrdinal, -1); + protected int getLocalField(int transducerOrdinal, Bytes fieldName) { + HashMap fieldMap = this.transducerFieldMaps.getOrDefault(transducerOrdinal, null); + return fieldMap != null ? fieldMap.getOrDefault(fieldName, -2) : -1; } protected int addSignal(Bytes signalName) { @@ -580,21 +536,25 @@ protected int addTransducer(Bytes transducerName) { || this.transducerNameIndex[this.transducerOrdinalMap.get(transducerName)].equals(transducerName) || this.transducerOffsetIndex[this.transducerOrdinalMap.get(transducerName)] < 0; final int count = this.transducerOrdinalMap.size(); - Integer ordinal = this.transducerOrdinalMap.computeIfAbsent(transducerName, absent -> count); - if (ordinal >= count) { - assert !this.transducerFieldMaps.containsKey(ordinal); - assert transducerNameIndex[ordinal] == null; - assert this.transducerOffsetIndex[ordinal] == 0; - if (ordinal >= this.transducerNameIndex.length) { - int length = ordinal + (Math.max(ordinal, 16) >> 1); + Integer transducerOrdinal = this.transducerOrdinalMap.computeIfAbsent(transducerName, absent -> count); + if (transducerOrdinal >= count) { + assert !this.transducerFieldMaps.containsKey(transducerOrdinal); + assert transducerNameIndex[transducerOrdinal] == null; + assert this.transducerOffsetIndex[transducerOrdinal] == 0; + if (transducerOrdinal >= this.transducerNameIndex.length) { + int length = transducerOrdinal + (Math.max(transducerOrdinal, 16) >> 1); this.transducerNameIndex = Arrays.copyOf(this.transducerNameIndex, length); this.transducerOffsetIndex = Arrays.copyOf(this.transducerOffsetIndex, length); } - this.newLocalField(ordinal); - this.transducerNameIndex[ordinal] = transducerName; - this.transducerOffsetIndex[ordinal] = -1; + this.transducerNameIndex[transducerOrdinal] = transducerName; + this.transducerOffsetIndex[transducerOrdinal] = -1; + HashMap localFieldMap = this.transducerFieldMaps.computeIfAbsent( + transducerOrdinal, absent -> new HashMap<>(256)); + assert localFieldMap.isEmpty(); + localFieldMap.put(Model.ANONYMOUS_FIELD_BYTES, Model.ANONYMOUS_FIELD_ORDINAL); + localFieldMap.put(Model.ALL_FIELDS_BYTES, Model.ALL_FIELDS_ORDINAL); } - return ordinal; + return transducerOrdinal; } protected int getTransducerOrdinal(Bytes transducerName) { @@ -800,7 +760,7 @@ protected Transducer readTransducer(int transducerOrdinal) throws ModelException Transducer transducer = new Transducer( this.readString(), this.readInt(), - this.readIntArray(), + this.transducerFieldMaps.get(transducerOrdinal), this.readIntArray(), this.readTransitionMatrix(), this.readIntArray() @@ -985,12 +945,11 @@ protected void writeTransitionMatrix(final int[][][] matrix) throws ModelExcepti } } - protected void writeTransducer(Bytes transducerName, int transducerOrdinal, int[] fields, int[] inputEquivalenceIndex, int[][][] kernelMatrix, int[] effectorVectors) + protected void writeTransducer(Bytes transducerName, int transducerOrdinal, int[] inputEquivalenceIndex, int[][][] kernelMatrix, int[] effectorVectors) throws ModelException, CharacterCodingException { this.setTransducerOffset(transducerOrdinal, this.seek(-1)); this.writeString(transducerName.asString()); this.writeInt(transducerOrdinal); - this.writeIntArray(fields); this.writeIntArray(inputEquivalenceIndex); this.writeTransitionMatrix(kernelMatrix); this.writeIntArray(effectorVectors); diff --git a/src/com/characterforming/jrte/engine/ModelCompiler.java b/src/com/characterforming/jrte/engine/ModelCompiler.java index ffe54a1..fd9d0c5 100755 --- a/src/com/characterforming/jrte/engine/ModelCompiler.java +++ b/src/com/characterforming/jrte/engine/ModelCompiler.java @@ -429,11 +429,7 @@ else if (token.isSignal() } void saveTransducer() throws ModelException, CharacterCodingException { - HashMap localFieldMap = super.transducerFieldMaps.get(this.transducerOrdinal); - int[] fields = new int[localFieldMap.size()]; - for (Entry e : localFieldMap.entrySet()) - fields[e.getValue()] = e.getKey(); - super.writeTransducer(this.transducerName, this.transducerOrdinal, fields, this.inputEquivalenceIndex, this.kernelMatrix, this.effectorVectors); + super.writeTransducer(this.transducerName, this.transducerOrdinal, this.inputEquivalenceIndex, this.kernelMatrix, this.effectorVectors); int nStates = this.kernelMatrix.length; int nInputs = this.kernelMatrix[0].length; int nTransitions = 0; @@ -490,7 +486,7 @@ else if (transition.tape == 1) this.tapeTokens.get(1).add(token); else if (transition.tape == 2 && !token.isLiteral()) { if (token.isField()) - token.setOrdinal(super.addLocalField(this.transducerOrdinal, super.addField(symbol))); + token.setOrdinal(super.addField(this.transducerOrdinal, symbol)); else if (token.isTransducer()) token.setOrdinal(super.addTransducer(symbol)); else if (token.isSignal()) diff --git a/src/com/characterforming/jrte/engine/ModelLoader.java b/src/com/characterforming/jrte/engine/ModelLoader.java index 98e134a..23f66aa 100644 --- a/src/com/characterforming/jrte/engine/ModelLoader.java +++ b/src/com/characterforming/jrte/engine/ModelLoader.java @@ -224,14 +224,11 @@ public void decompile(final String transducerName) for (Map.Entry entry : effectorOrdinalMap) effectorNames[entry.getValue()] = Codec.decode( entry.getKey().bytes(), entry.getKey().getLength()); - Bytes[] fieldIndex = new Bytes[this.fieldOrdinalMap.size()]; - for (Map.Entry m : this.fieldOrdinalMap.entrySet()) - fieldIndex[m.getValue()] = m.getKey(); System.out.printf("%s%n%nFields%n%n", transducerName); - Map fieldMap = this.transducerFieldMaps.get(transducerOrdinal); + Map fieldMap = this.transducerFieldMaps.get(transducerOrdinal); Bytes[] fields = new Bytes[fieldMap.size()]; - for (Entry e : fieldMap.entrySet()) - fields[e.getValue()] = fieldIndex[e.getKey()]; + for (Entry e : fieldMap.entrySet()) + fields[e.getValue()] = e.getKey(); for (int i = 0; i < fields.length; i++) System.out.printf("%4d: %s%n", i, fields[i]); System.out.printf("%nInput equivalents (equivalent: input...)%n%n", transducerName); diff --git a/src/com/characterforming/jrte/engine/Token.java b/src/com/characterforming/jrte/engine/Token.java index eea787f..f56ec65 100644 --- a/src/com/characterforming/jrte/engine/Token.java +++ b/src/com/characterforming/jrte/engine/Token.java @@ -303,12 +303,9 @@ static IToken[] getParameterTokens(Model model, Argument argument) { Token token = new Token(argument.tokens().getBytes(i)); if (token.type == Token.Type.FIELD) { int transducerOrdinal = argument.transducerOrdinal(); - int fieldOrdinal = model.getFieldOrdinal(token.symbol); - HashMap localFieldMap = model.transducerFieldMaps.get(transducerOrdinal); - int localFieldIndex = localFieldMap.computeIfAbsent(fieldOrdinal, absent -> localFieldMap.size()); - tokens[i] = new Token(bytes[i], localFieldIndex); - assert transducerOrdinal >= 0 && fieldOrdinal >= 0 - && (localFieldMap.isEmpty() || localFieldIndex >= 0); + HashMap localFieldMap = model.transducerFieldMaps.get(transducerOrdinal); + int fieldOrdinal = localFieldMap.computeIfAbsent(token.symbol, absent -> localFieldMap.size()); + tokens[i] = new Token(bytes[i], fieldOrdinal); } else if (token.type == Token.Type.TRANSDUCER) tokens[i] = new Token(bytes[i], model.getTransducerOrdinal(token.symbol)); else if (token.type == Token.Type.SIGNAL) diff --git a/src/com/characterforming/jrte/engine/Transducer.java b/src/com/characterforming/jrte/engine/Transducer.java index 406cf76..1e6f913 100644 --- a/src/com/characterforming/jrte/engine/Transducer.java +++ b/src/com/characterforming/jrte/engine/Transducer.java @@ -20,13 +20,17 @@ package com.characterforming.jrte.engine; +import java.util.HashMap; + +import com.characterforming.ribose.base.Bytes; + /** * @author Kim Briggs */ final class Transducer { private final int ordinal; private final String name; - private final int[] fields; + private final HashMap fields; private final int[] inputFilter; private final long[] transitionMatrix; private final int[] effectorVector; @@ -35,7 +39,7 @@ final class Transducer { Transducer( String name, int ordinal, - int[] fields, + HashMap fields, int[] inputFilter, long[] transitionMatrix, int[] effectorVector @@ -108,12 +112,8 @@ int[] effectorVector() { return this.effectorVector; } - int[] getFields() { - return this.fields; - } - int getFieldCount() { - return this.fields.length; + return this.fields.size(); } int getInputEquivalentsCount() { diff --git a/src/com/characterforming/jrte/engine/Transductor.java b/src/com/characterforming/jrte/engine/Transductor.java index 56c8a15..fe28537 100644 --- a/src/com/characterforming/jrte/engine/Transductor.java +++ b/src/com/characterforming/jrte/engine/Transductor.java @@ -216,8 +216,7 @@ public String getName() { @Override // @see com.characterforming.ribose.IOutput#getLocalizedFieldIndex(Bytes, Bytes) public int getLocalizedFieldIndex(String transducerName, String fieldName) throws CharacterCodingException { int transducerOrdinal = this.model.getTransducerOrdinal(Codec.encode(transducerName)); - int fieldOrdinal = this.model.getFieldOrdinal(Codec.encode(fieldName)); - return this.model.getLocalField(transducerOrdinal, fieldOrdinal); + return this.model.getLocalField(transducerOrdinal, Codec.encode(fieldName)); } @Override // @see com.characterforming.ribose.IOutput#getLocalizedFieldIndex()