From caa8f62f1c989024d4541d307ffb63fafd8c64d6 Mon Sep 17 00:00:00 2001 From: Villu Ruusmann Date: Wed, 11 Dec 2024 17:51:24 +0200 Subject: [PATCH] Imported Java code from JPMML-Evaluator-Python and JPMML-Evaluator-R projects --- .../main/java/org/jpmml/evaluator/Table.java | 130 ++++++++++++++ .../java/org/jpmml/evaluator/TableReader.java | 167 ++++++++++++++++++ .../java/org/jpmml/evaluator/TableUtil.java | 19 ++ .../java/org/jpmml/evaluator/TableWriter.java | 108 +++++++++++ .../java/org/jpmml/evaluator/TableTest.java | 117 ++++++++++++ 5 files changed, 541 insertions(+) create mode 100644 pmml-evaluator/src/main/java/org/jpmml/evaluator/Table.java create mode 100644 pmml-evaluator/src/main/java/org/jpmml/evaluator/TableReader.java create mode 100644 pmml-evaluator/src/main/java/org/jpmml/evaluator/TableUtil.java create mode 100644 pmml-evaluator/src/main/java/org/jpmml/evaluator/TableWriter.java create mode 100644 pmml-evaluator/src/test/java/org/jpmml/evaluator/TableTest.java diff --git a/pmml-evaluator/src/main/java/org/jpmml/evaluator/Table.java b/pmml-evaluator/src/main/java/org/jpmml/evaluator/Table.java new file mode 100644 index 00000000..45235cf8 --- /dev/null +++ b/pmml-evaluator/src/main/java/org/jpmml/evaluator/Table.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2024 Villu Ruusmann + * + * This file is part of JPMML-Evaluator + * + * JPMML-Evaluator is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * JPMML-Evaluator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with JPMML-Evaluator. If not, see . + */ +package org.jpmml.evaluator; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class Table { + + private List columns = null; + + private Map> values = new HashMap<>(); + + + public Table(){ + this(new ArrayList<>()); + } + + public Table(List columns){ + setColumns(columns); + } + + public int getNumberOfRows(){ + Map> columnValues = getValues(); + + int result = 0; + + Collection>> entries = columnValues.entrySet(); + for(Map.Entry> entry : entries){ + List values = entry.getValue(); + + result = Math.max(result, values.size()); + } + + return result; + } + + public int getNumberOfColumns(){ + List columns = getColumns(); + + return columns.size(); + } + + public void canonicalize(){ + List columns = getColumns(); + + int numberOfRows = getNumberOfRows(); + + for(String column : columns){ + List values = getValues(column); + + if(values == null){ + values = new ArrayList<>(numberOfRows); + + setValues(column, values); + } + + TableUtil.ensureSize(values, numberOfRows); + } + } + + public boolean addColumn(String column){ + List columns = getColumns(); + + if(!columns.contains(column)){ + columns.add(column); + + return true; + } + + return false; + } + + public boolean removeColumn(String column){ + List columns = getColumns(); + + boolean result = columns.remove(column); + if(result){ + Map> columnValues = getValues(); + + columnValues.remove(column); + } + + return result; + } + + public List getValues(String column){ + Map> columnValues = getValues(); + + return columnValues.get(column); + } + + public void setValues(String column, List values){ + Map> columnValues = getValues(); + + columnValues.put(column, values); + } + + public List getColumns(){ + return this.columns; + } + + void setColumns(List columns){ + this.columns = Objects.requireNonNull(columns); + } + + public Map> getValues(){ + return this.values; + } +} \ No newline at end of file diff --git a/pmml-evaluator/src/main/java/org/jpmml/evaluator/TableReader.java b/pmml-evaluator/src/main/java/org/jpmml/evaluator/TableReader.java new file mode 100644 index 00000000..ba807d1e --- /dev/null +++ b/pmml-evaluator/src/main/java/org/jpmml/evaluator/TableReader.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2024 Villu Ruusmann + * + * This file is part of JPMML-Evaluator + * + * JPMML-Evaluator is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * JPMML-Evaluator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with JPMML-Evaluator. If not, see . + */ +package org.jpmml.evaluator; + +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Set; + +public class TableReader extends AbstractMap implements Iterator> { + + private Table table = null; + + private int position = -1; + + private int maxPosition = -1; + + + public TableReader(Table table){ + setTable(table); + } + + @Override + public boolean hasNext(){ + int position = getPosition(); + int maxPosition = getMaxPosition(); + + return position < maxPosition; + } + + @Override + public Map next(){ + int position = getPosition(); + int maxPosition = getMaxPosition(); + + if(position < maxPosition){ + setPosition(position + 1); + } else + + { + throw new NoSuchElementException(); + } + + return this; + } + + @Override + public Object get(Object key){ + Table table = getTable(); + int position = ensurePosition(); + + List values = table.getValues((String)key); + if(values != null){ + return values.get(position); + } + + return null; + } + + @Override + public Set> entrySet(){ + Table table = getTable(); + int position = ensurePosition(); + + Set> result = new AbstractSet>(){ + + + @Override + public int size(){ + List columns = table.getColumns(); + + return columns.size(); + } + + @Override + public Iterator> iterator(){ + List columns = table.getColumns(); + + Iterator> result = new Iterator>(){ + + private Iterator it = columns.iterator(); + + + @Override + public boolean hasNext(){ + return this.it.hasNext(); + } + + @Override + public Map.Entry next(){ + String column = this.it.next(); + + List values = table.getValues(column); + if(values != null){ + Object value = values.get(position); + + return new SimpleEntry<>(column, value); + } + + return new SimpleEntry<>(column, null); + } + }; + + return result; + } + }; + + return result; + } + + protected int ensurePosition(){ + int position = getPosition(); + + if(position < 0){ + throw new IllegalStateException(); + } + + return position; + } + + public Table getTable(){ + return this.table; + } + + void setTable(Table table){ + this.table = Objects.requireNonNull(table); + + setPosition(-1); + setMaxPosition(table.getNumberOfRows() - 1); + } + + int getPosition(){ + return this.position; + } + + void setPosition(int position){ + this.position = position; + } + + int getMaxPosition(){ + return this.maxPosition; + } + + void setMaxPosition(int maxPosition){ + this.maxPosition = maxPosition; + } +} \ No newline at end of file diff --git a/pmml-evaluator/src/main/java/org/jpmml/evaluator/TableUtil.java b/pmml-evaluator/src/main/java/org/jpmml/evaluator/TableUtil.java new file mode 100644 index 00000000..ee9b7273 --- /dev/null +++ b/pmml-evaluator/src/main/java/org/jpmml/evaluator/TableUtil.java @@ -0,0 +1,19 @@ +package org.jpmml.evaluator; + +import java.util.List; + +class TableUtil { + + private TableUtil(){ + } + + static + List ensureSize(List values, int size){ + + while(values.size() < size){ + values.add(null); + } + + return values; + } +} \ No newline at end of file diff --git a/pmml-evaluator/src/main/java/org/jpmml/evaluator/TableWriter.java b/pmml-evaluator/src/main/java/org/jpmml/evaluator/TableWriter.java new file mode 100644 index 00000000..8a3abe62 --- /dev/null +++ b/pmml-evaluator/src/main/java/org/jpmml/evaluator/TableWriter.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024 Villu Ruusmann + * + * This file is part of JPMML-Evaluator + * + * JPMML-Evaluator is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * JPMML-Evaluator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with JPMML-Evaluator. If not, see . + */ +package org.jpmml.evaluator; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +public class TableWriter extends AbstractMap { + + private Table table = null; + + private int position = -1; + + + public TableWriter(Table table){ + setTable(table); + } + + public void next(){ + int position = getPosition(); + + setPosition(position + 1); + } + + @Override + public Object get(Object key){ + throw new UnsupportedOperationException(); + } + + @Override + public Set> entrySet(){ + throw new UnsupportedOperationException(); + } + + @Override + public Object put(String key, Object value){ + Table table = getTable(); + int position = ensurePosition(); + + @SuppressWarnings("unchecked") + List values = (List)table.getValues(key); + if(values == null){ + table.addColumn(key); + + values = new ArrayList<>(); + + table.setValues(key, values); + } // End if + + if(position < values.size()){ + return values.set(position, value); + } else + + { + TableUtil.ensureSize(values, position); + + values.add(value); + + return null; + } + } + + protected int ensurePosition(){ + int position = getPosition(); + + if(position < 0){ + throw new IllegalStateException(); + } + + return position; + } + + public Table getTable(){ + return this.table; + } + + private void setTable(Table table){ + this.table = Objects.requireNonNull(table); + } + + int getPosition(){ + return this.position; + } + + void setPosition(int position){ + this.position = position; + } +} \ No newline at end of file diff --git a/pmml-evaluator/src/test/java/org/jpmml/evaluator/TableTest.java b/pmml-evaluator/src/test/java/org/jpmml/evaluator/TableTest.java new file mode 100644 index 00000000..57cc63b1 --- /dev/null +++ b/pmml-evaluator/src/test/java/org/jpmml/evaluator/TableTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024 Villu Ruusmann + * + * This file is part of JPMML-Evaluator + * + * JPMML-Evaluator is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * JPMML-Evaluator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with JPMML-Evaluator. If not, see . + */ +package org.jpmml.evaluator; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class TableTest { + + @Test + public void copy(){ + List columns = new ArrayList<>(); + columns.add("A"); + columns.add("B"); + + Table argumentsTable = new Table(columns); + + argumentsTable.setValues("A", Arrays.asList(1, 2, 3)); + argumentsTable.setValues("B", Arrays.asList(1.0, 2.0, 3.0)); + + assertEquals(2, argumentsTable.getNumberOfColumns()); + assertEquals(3, argumentsTable.getNumberOfRows()); + + TableReader tableReader = new TableReader(argumentsTable); + + try { + tableReader.ensurePosition(); + + fail(); + } catch(IllegalStateException ise){ + // Ignored + } + + Table resultsTable = new Table(); + + assertEquals(0, resultsTable.getNumberOfColumns()); + assertEquals(0, resultsTable.getNumberOfRows()); + + TableWriter tableWriter = new TableWriter(resultsTable); + + try { + tableWriter.ensurePosition(); + + fail(); + } catch(IllegalStateException ise){ + // Ignored + } + + for(int i = 0; tableReader.hasNext(); i++){ + Map row = tableReader.next(); + + tableWriter.next(); + + tableWriter.putAll(row); + + tableWriter.put("C", String.valueOf(i + 1)); + } + + try { + tableReader.next(); + + fail(); + } catch(NoSuchElementException nsee){ + // Ignored + } + + assertEquals(3, resultsTable.getNumberOfColumns()); + assertEquals(3, resultsTable.getNumberOfRows()); + + assertEquals(Arrays.asList("A", "B", "C"), resultsTable.getColumns()); + + assertEquals(Arrays.asList(1, 2, 3), resultsTable.getValues("A")); + assertEquals(Arrays.asList(1.0, 2.0, 3.0), resultsTable.getValues("B")); + assertEquals(Arrays.asList("1", "2", "3"), resultsTable.getValues("C")); + + tableWriter.next(); + + tableWriter.put("A", 4); + + tableWriter.next(); + + tableWriter.put("C", "5"); + + resultsTable.canonicalize(); + + assertEquals(3, resultsTable.getNumberOfColumns()); + assertEquals(5, resultsTable.getNumberOfRows()); + + assertEquals(Arrays.asList(1, 2, 3, 4, null), resultsTable.getValues("A")); + assertEquals(Arrays.asList(1.0, 2.0, 3.0, null, null), resultsTable.getValues("B")); + assertEquals(Arrays.asList("1", "2", "3", null, "5"), resultsTable.getValues("C")); + } +} \ No newline at end of file