Skip to content

Commit

Permalink
Fixup fields
Browse files Browse the repository at this point in the history
- clean up field handling in model compilation and runtime
- changes are internal ; no interface changes but models must be recompiled

Signed-off-by: jrte <jrte.project@gmail.com>
  • Loading branch information
jrte committed Jun 16, 2024
1 parent fd93abc commit 2143fc9
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 107 deletions.
119 changes: 39 additions & 80 deletions src/com/characterforming/jrte/engine/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,9 @@ public record Argument(int transducerOrdinal, BytesArray tokens) {}
protected final Logger rtcLogger;
protected final Logger rteLogger;
protected HashMap<Bytes, Integer> signalOrdinalMap;
protected HashMap<Bytes, Integer> fieldOrdinalMap;
protected HashMap<Bytes, Integer> effectorOrdinalMap;
protected HashMap<Bytes, Integer> transducerOrdinalMap;
protected HashMap<Integer, HashMap<Integer, Integer>> transducerFieldMaps;
protected HashMap<Integer, HashMap<Bytes, Integer>> transducerFieldMaps;
protected IEffector<?>[] proxyEffectors;
protected long[] transducerOffsetIndex;
protected Bytes[] transducerNameIndex;
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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<Integer, Integer> localFieldMap = this.transducerFieldMaps.get(transducerOrdinal);
int[] localFields = new int[localFieldMap.size()];
for (Entry<Integer, Integer> 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];
Expand All @@ -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);
Expand Down Expand Up @@ -316,21 +307,14 @@ 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];
this.transducerOffsetIndex = new long[transducerCount];
for (int transducerOrdinal = 0; transducerOrdinal < transducerCount; transducerOrdinal++) {
this.transducerNameIndex[transducerOrdinal] = new Bytes(this.readBytes());
this.transducerOffsetIndex[transducerOrdinal] = this.readLong();
int[] fields = this.readIntArray();
HashMap<Integer, Integer> 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();
Expand Down Expand Up @@ -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<Bytes, Integer> m : this.fieldOrdinalMap.entrySet())
fieldIndex[m.getValue()] = m.getKey();
Bytes[] transducerIndex = new Bytes[this.transducerOrdinalMap.size()];
for (Map.Entry<Bytes, Integer> 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<Integer, Integer> fieldMap = this.transducerFieldMaps.get(transducerOrdinal);
Map<Bytes, Integer> fieldMap = this.transducerFieldMaps.get(transducerOrdinal);
Bytes[] fields = new Bytes[fieldMap.size()];
for (Entry<Integer, Integer> e : fieldMap.entrySet())
fields[e.getValue()] = fieldIndex[e.getKey()];
for (Entry<Bytes, Integer> 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());
Expand Down Expand Up @@ -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() {
Expand All @@ -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<Bytes, Integer> 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<Integer, Integer> newLocalField(int transducerOrdinal) {
HashMap<Integer, Integer> 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<Integer, Integer> 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<Bytes, Integer> fieldMap = this.transducerFieldMaps.getOrDefault(transducerOrdinal, null);
return fieldMap != null ? fieldMap.getOrDefault(fieldName, -2) : -1;
}

protected int addSignal(Bytes signalName) {
Expand All @@ -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<Bytes, Integer> 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) {
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 2 additions & 6 deletions src/com/characterforming/jrte/engine/ModelCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -429,11 +429,7 @@ else if (token.isSignal()
}

void saveTransducer() throws ModelException, CharacterCodingException {
HashMap<Integer, Integer> localFieldMap = super.transducerFieldMaps.get(this.transducerOrdinal);
int[] fields = new int[localFieldMap.size()];
for (Entry<Integer, Integer> 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;
Expand Down Expand Up @@ -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())
Expand Down
9 changes: 3 additions & 6 deletions src/com/characterforming/jrte/engine/ModelLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,11 @@ public void decompile(final String transducerName)
for (Map.Entry<Bytes, Integer> entry : effectorOrdinalMap)
effectorNames[entry.getValue()] = Codec.decode(
entry.getKey().bytes(), entry.getKey().getLength());
Bytes[] fieldIndex = new Bytes[this.fieldOrdinalMap.size()];
for (Map.Entry<Bytes, Integer> m : this.fieldOrdinalMap.entrySet())
fieldIndex[m.getValue()] = m.getKey();
System.out.printf("%s%n%nFields%n%n", transducerName);
Map<Integer, Integer> fieldMap = this.transducerFieldMaps.get(transducerOrdinal);
Map<Bytes, Integer> fieldMap = this.transducerFieldMaps.get(transducerOrdinal);
Bytes[] fields = new Bytes[fieldMap.size()];
for (Entry<Integer, Integer> e : fieldMap.entrySet())
fields[e.getValue()] = fieldIndex[e.getKey()];
for (Entry<Bytes, Integer> 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);
Expand Down
9 changes: 3 additions & 6 deletions src/com/characterforming/jrte/engine/Token.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Integer, Integer> 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<Bytes, Integer> 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)
Expand Down
14 changes: 7 additions & 7 deletions src/com/characterforming/jrte/engine/Transducer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Bytes, Integer> fields;
private final int[] inputFilter;
private final long[] transitionMatrix;
private final int[] effectorVector;
Expand All @@ -35,7 +39,7 @@ final class Transducer {
Transducer(
String name,
int ordinal,
int[] fields,
HashMap<Bytes, Integer> fields,
int[] inputFilter,
long[] transitionMatrix,
int[] effectorVector
Expand Down Expand Up @@ -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() {
Expand Down
3 changes: 1 addition & 2 deletions src/com/characterforming/jrte/engine/Transductor.java
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 2143fc9

Please sign in to comment.