This is an automated email from the ASF dual-hosted git repository. mboehm7 pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/systemds.git
The following commit(s) were added to refs/heads/main by this push: new b1c5d64d78 [SYSTEMDS-3860] Extended sparsity exploitation in codegen row templates b1c5d64d78 is described below commit b1c5d64d7884f3c63284bbfea6003d13faec4a33 Author: Frxms <tomoki.men...@gmail.com> AuthorDate: Wed Aug 20 14:00:30 2025 +0200 [SYSTEMDS-3860] Extended sparsity exploitation in codegen row templates Finalized runtime kernels, code generation, and optimization Closes #2297. Closes #2277. Closes #2276. --- src/main/java/org/apache/sysds/api/DMLOptions.java | 15 +- src/main/java/org/apache/sysds/api/DMLScript.java | 4 + .../apache/sysds/hops/codegen/SpoofCompiler.java | 2 +- .../org/apache/sysds/hops/codegen/cplan/CNode.java | 20 +- .../sysds/hops/codegen/cplan/CNodeBinary.java | 197 +++- .../apache/sysds/hops/codegen/cplan/CNodeNary.java | 5 +- .../apache/sysds/hops/codegen/cplan/CNodeRow.java | 4 +- .../sysds/hops/codegen/cplan/CNodeTernary.java | 7 +- .../sysds/hops/codegen/cplan/CNodeUnary.java | 65 +- .../sysds/hops/codegen/cplan/CodeTemplate.java | 18 +- .../sysds/hops/codegen/cplan/java/Binary.java | 62 +- .../sysds/hops/codegen/cplan/java/Ternary.java | 2 +- .../sysds/hops/codegen/cplan/java/Unary.java | 25 +- .../sysds/hops/codegen/template/TemplateRow.java | 26 +- .../sysds/runtime/codegen/LibSpoofPrimitives.java | 1226 ++++++++++++++++++++ .../apache/sysds/runtime/codegen/SpoofRowwise.java | 45 +- .../codegen/CPlanVectorPrimitivesTest.java | 461 ++++++++ .../component/codegen/SparseVectorAllocTest.java | 133 +++ .../test/functions/codegen/RowAggTmplTest.java | 12 +- .../scripts/functions/codegen/rowAggPattern49.R | 54 + .../scripts/functions/codegen/rowAggPattern49.dml | 52 + .../scripts/functions/codegen/rowAggPattern50.R | 43 + .../scripts/functions/codegen/rowAggPattern50.dml | 40 + 23 files changed, 2436 insertions(+), 82 deletions(-) diff --git a/src/main/java/org/apache/sysds/api/DMLOptions.java b/src/main/java/org/apache/sysds/api/DMLOptions.java index 97d5f54a4a..917aecc4ab 100644 --- a/src/main/java/org/apache/sysds/api/DMLOptions.java +++ b/src/main/java/org/apache/sysds/api/DMLOptions.java @@ -86,6 +86,7 @@ public class DMLOptions { public boolean federatedCompilation = false; // Compile federated instructions based on input federation state and privacy constraints. public boolean noFedRuntimeConversion = false; // If activated, no runtime conversion of CP instructions to FED instructions will be performed. public int seed = -1; // The general seed for the execution, if -1 random (system time). + public boolean sparseIntermediate = false; // whether SparseRowIntermediates should be used for rowwise operations public final static DMLOptions defaultOptions = new DMLOptions(null); @@ -119,7 +120,8 @@ public class DMLOptions { ", w=" + fedWorker + ", federatedCompilation=" + federatedCompilation + ", noFedRuntimeConversion=" + noFedRuntimeConversion + - ", seed=" + seed + + ", seed=" + seed + + ", sparseIntermediate=" + sparseIntermediate + '}'; } @@ -353,6 +355,11 @@ public class DMLOptions { dmlOptions.seed = Integer.parseInt(line.getOptionValue("seed")); } + //TODO move to systemds-config instead of command-line arg + if(line.hasOption("sparseIntermediate")){ + dmlOptions.sparseIntermediate = true; + } + return dmlOptions; } @@ -436,7 +443,10 @@ public class DMLOptions { Option commandlineSeed = OptionBuilder .withDescription("A general seed for the execution through the commandline") .hasArg().create("seed"); - + Option sparseRowIntermediates = OptionBuilder + .withDescription("If activated, sparseRowVector intermediates will be used to calculate rowwise operations.") + .create("sparseIntermediate"); + options.addOption(configOpt); options.addOption(cleanOpt); options.addOption(statsOpt); @@ -457,6 +467,7 @@ public class DMLOptions { options.addOption(federatedCompilation); options.addOption(noFedRuntimeConversion); options.addOption(commandlineSeed); + options.addOption(sparseRowIntermediates); // Either a clean(-clean), a file(-f), a script(-s) or help(-help) needs to be specified OptionGroup fileOrScriptOpt = new OptionGroup() diff --git a/src/main/java/org/apache/sysds/api/DMLScript.java b/src/main/java/org/apache/sysds/api/DMLScript.java index 2bc8d3b816..65805b5c2e 100644 --- a/src/main/java/org/apache/sysds/api/DMLScript.java +++ b/src/main/java/org/apache/sysds/api/DMLScript.java @@ -155,6 +155,9 @@ public class DMLScript // Global seed public static int SEED = -1; + // Sparse row flag + public static boolean SPARSE_INTERMEDIATE = false; + public static String MONITORING_ADDRESS = null; // flag that indicates whether or not to suppress any prints to stdout @@ -278,6 +281,7 @@ public class DMLScript LINEAGE_ESTIMATE = dmlOptions.lineage_estimate; LINEAGE_DEBUGGER = dmlOptions.lineage_debugger; SEED = dmlOptions.seed; + SPARSE_INTERMEDIATE = dmlOptions.sparseIntermediate; String fnameOptConfig = dmlOptions.configFile; diff --git a/src/main/java/org/apache/sysds/hops/codegen/SpoofCompiler.java b/src/main/java/org/apache/sysds/hops/codegen/SpoofCompiler.java index 34329ca64d..307205dbc8 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/SpoofCompiler.java +++ b/src/main/java/org/apache/sysds/hops/codegen/SpoofCompiler.java @@ -470,7 +470,7 @@ public class SpoofCompiler { * @param recompile true if invoked during dynamic recompilation * @return dag root nodes of modified dag */ - public static ArrayList<Hop> optimize(ArrayList<Hop> roots, boolean recompile) + public static ArrayList<Hop> optimize(ArrayList<Hop> roots, boolean recompile) { if( roots == null || roots.isEmpty() ) return roots; diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNode.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNode.java index 36cc8f4979..36ebd238ac 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNode.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNode.java @@ -19,6 +19,7 @@ package org.apache.sysds.hops.codegen.cplan; +import org.apache.sysds.api.DMLScript; import org.apache.sysds.common.Types.DataType; import org.apache.sysds.hops.codegen.SpoofCompiler.GeneratorAPI; import org.apache.sysds.hops.codegen.template.TemplateUtils; @@ -77,6 +78,14 @@ public abstract class CNode _genVar = "TMP"+_seqVar.getNextID(); return _genVar; } + + public String createVarname(boolean sparse) { + if(!sparse) { + return createVarname(); + } else { + return _genVar = "S" + createVarname(); + } + } public String getVarname() { return _genVar; @@ -98,6 +107,8 @@ public abstract class CNode return "len"; if(getVarname().startsWith("b")) return getVarname() + ".clen"; + else if(getVarname().startsWith("STMP")) + return "len"; else if(_dataType == DataType.MATRIX) return getVarname() + ".length"; } @@ -222,8 +233,13 @@ public abstract class CNode protected String replaceUnaryPlaceholders(String tmp, String varj, boolean vectIn, GeneratorAPI api) { //replace sparse and dense inputs - tmp = tmp.replace("%IN1v%", varj+"vals"); - tmp = tmp.replace("%IN1i%", varj+"ix"); + if(DMLScript.SPARSE_INTERMEDIATE) { + tmp = tmp.replace("%IN1v%", varj.startsWith("STMP") ? varj+".values()" : varj+"vals"); + tmp = tmp.replace("%IN1i%", varj.startsWith("STMP") ? varj+".indexes()" :varj+"ix"); + } else { + tmp = tmp.replace("%IN1v%", varj+"vals"); + tmp = tmp.replace("%IN1i%", varj+"ix"); + } tmp = tmp.replace("%IN1%", (vectIn && TemplateUtils.isMatrix(_inputs.get(0))) ? ((api == GeneratorAPI.JAVA) ? varj + ".values(rix)" : varj + ".vals(0)" ) : diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeBinary.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeBinary.java index b29d586c38..6031d8492a 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeBinary.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeBinary.java @@ -22,6 +22,7 @@ package org.apache.sysds.hops.codegen.cplan; import java.util.Arrays; import org.apache.commons.lang3.StringUtils; +import org.apache.sysds.api.DMLScript; import org.apache.sysds.common.Opcodes; import org.apache.sysds.hops.codegen.template.TemplateUtils; import org.apache.sysds.common.Types.DataType; @@ -126,7 +127,8 @@ public class CNodeBinary extends CNode { } private final BinType _type; - + private boolean sparseTemplate; + public CNodeBinary( CNode in1, CNode in2, BinType type ) { //canonicalize commutative matrix-scalar operations //to increase reuse potential @@ -143,6 +145,23 @@ public class CNodeBinary extends CNode { setOutputDims(); } + public CNodeBinary( CNode in1, CNode in2, BinType type, double sparsityEst, double scalarVal ) { + //canonicalize commutative matrix-scalar operations + //to increase reuse potential + if( type.isCommutative() && in1 instanceof CNodeData + && in1.getDataType()==DataType.SCALAR ) { + CNode tmp = in1; + in1 = in2; + in2 = tmp; + } + + _inputs.add(in1); + _inputs.add(in2); + _type = type; + setOutputDims(); + sparseTemplate = getTemplateType(sparsityEst, scalarVal); + } + public BinType getType() { return _type; } @@ -157,60 +176,63 @@ public class CNodeBinary extends CNode { //generate children sb.append(_inputs.get(0).codegen(sparse, api)); sb.append(_inputs.get(1).codegen(sparse, api)); - + //generate binary operation (use sparse template, if data input) - boolean lsparseLhs = sparse && _inputs.get(0) instanceof CNodeData - && _inputs.get(0).getVarname().startsWith("a"); - boolean lsparseRhs = sparse && _inputs.get(1) instanceof CNodeData - && _inputs.get(1).getVarname().startsWith("a"); + boolean lsparseLhs = sparse ? _inputs.get(0) instanceof CNodeData + && _inputs.get(0).getVarname().startsWith("a") || + _inputs.get(0).getVarname().startsWith("STMP") : false; + boolean lsparseRhs = sparse ? _inputs.get(1) instanceof CNodeData + && _inputs.get(1).getVarname().startsWith("a") || + _inputs.get(1).getVarname().startsWith("STMP") : false; boolean scalarInput = _inputs.get(0).getDataType().isScalar(); boolean scalarVector = (_inputs.get(0).getDataType().isScalar() && _inputs.get(1).getDataType().isMatrix()); boolean vectorVector = _inputs.get(0).getDataType().isMatrix() && _inputs.get(1).getDataType().isMatrix(); - String var = createVarname(); + String var = createVarname(sparse && sparseTemplate && getOutputType(scalarVector, lsparseLhs, lsparseRhs)); String tmp = getLanguageTemplateClass(this, api) - .getTemplate(_type, lsparseLhs, lsparseRhs, scalarVector, scalarInput, vectorVector); + .getTemplate(_type, lsparseLhs, lsparseRhs, scalarVector, scalarInput, vectorVector, sparseTemplate); tmp = tmp.replace("%TMP%", var); - + //replace input references and start indexes for( int j=0; j<2; j++ ) { String varj = _inputs.get(j).getVarname(api); - //replace sparse and dense inputs - tmp = tmp.replace("%IN"+(j+1)+"v%", varj+"vals"); - tmp = tmp.replace("%IN"+(j+1)+"i%", varj+"ix"); + tmp = tmp.replace("%IN"+(j+1)+"v%", varj.startsWith("STMP") ? varj+".values()" : varj+"vals"); + tmp = tmp.replace("%IN"+(j+1)+"i%", varj.startsWith("STMP") ? varj+".indexes()" : varj+"ix"); tmp = tmp.replace("%IN"+(j+1)+"%", - varj.startsWith("a") ? (api == GeneratorAPI.JAVA ? varj : - (_inputs.get(j).getDataType() == DataType.MATRIX ? varj + ".vals(0)" : varj)) : - varj.startsWith("b") ? (api == GeneratorAPI.JAVA ? varj + ".values(rix)" : - (_type == BinType.VECT_MATRIXMULT ? varj : varj + ".vals(0)")) : - _inputs.get(j).getDataType() == DataType.MATRIX ? (api == GeneratorAPI.JAVA ? varj : varj + ".vals(0)") : varj); - + varj.startsWith("a") ? (api == GeneratorAPI.JAVA ? varj : + (_inputs.get(j).getDataType() == DataType.MATRIX ? varj + ".vals(0)" : varj)) : + varj.startsWith("b") ? (api == GeneratorAPI.JAVA ? varj + ".values(rix)" : + (_type == BinType.VECT_MATRIXMULT ? varj : varj + ".vals(0)")) : + _inputs.get(j).getDataType() == DataType.MATRIX ? (api == GeneratorAPI.JAVA ? varj : varj + ".vals(0)") : varj); + + tmp = tmp.replace("%SLEN"+(j+1)+"%", varj.startsWith("STMP") ? varj+".size()" : varj.startsWith("a") ? "alen" : "blen"); + //replace start position of main input - tmp = tmp.replace("%POS"+(j+1)+"%", (_inputs.get(j) instanceof CNodeData - && _inputs.get(j).getDataType().isMatrix()) ? (!varj.startsWith("b")) ? varj+"i" : - ((TemplateUtils.isMatrix(_inputs.get(j)) || (_type.isElementwise() - && TemplateUtils.isColVector(_inputs.get(j)))) && _type!=BinType.VECT_MATRIXMULT) ? + tmp = tmp.replace("%POS"+(j+1)+"%", (_inputs.get(j) instanceof CNodeData + && _inputs.get(j).getDataType().isMatrix()) ? (!varj.startsWith("b")) ? varj+"i" : + ((TemplateUtils.isMatrix(_inputs.get(j)) || (_type.isElementwise() + && TemplateUtils.isColVector(_inputs.get(j)))) && _type!=BinType.VECT_MATRIXMULT) ? varj + ".pos(rix)" : "0" : "0"); } //replace length information (e.g., after matrix mult) - if( _type == BinType.VECT_OUTERMULT_ADD || (_type == BinType.VECT_CBIND && vectorVector) ) { + if( _type == BinType.VECT_OUTERMULT_ADD || (_type == BinType.VECT_CBIND && vectorVector)) { for( int j=0; j<2; j++ ) tmp = tmp.replace("%LEN"+(j+1)+"%", _inputs.get(j).getVectorLength(api)); } - else { //general case + else { //general case CNode mInput = getIntermediateInputVector(); if( mInput != null ) tmp = tmp.replace("%LEN%", mInput.getVectorLength(api)); } - + sb.append(tmp); - + //mark as generated _generated = true; - + return sb.toString(); } @@ -219,7 +241,126 @@ public class CNodeBinary extends CNode { if( getInput().get(i).getDataType().isMatrix() ) return getInput().get(i); return null; - } + } + + private boolean getTemplateType(double sparsityEst, double scalarVal) { + if(!DMLScript.SPARSE_INTERMEDIATE) + return false; + else { + switch(_type) { + case VECT_MULT: + case VECT_DIV: + case VECT_LESS: + case VECT_MINUS: + case VECT_PLUS: + case VECT_XOR: + case VECT_BITWAND: + case VECT_BIASADD: + case VECT_BIASMULT: + case VECT_MIN: + case VECT_MAX: + case VECT_NOTEQUAL: + case VECT_GREATER: + case VECT_EQUAL: + case VECT_LESSEQUAL: + case VECT_GREATEREQUAL: return sparsityEst < 0.1; + case VECT_MULT_SCALAR: + case VECT_DIV_SCALAR: + case VECT_XOR_SCALAR: + case VECT_BITWAND_SCALAR: return sparsityEst < 0.3; + case VECT_GREATER_SCALAR: { + if(scalarVal != Double.NaN) { + return _inputs.get(1).getDataType().isScalar() ? scalarVal >= 0 && sparsityEst < 0.2 + : _inputs.get(0).getDataType().isScalar() && scalarVal < 0 && sparsityEst < 0.2; + } else + return false; + } + case VECT_GREATEREQUAL_SCALAR: { + if(scalarVal != Double.NaN) { + return _inputs.get(1).getDataType().isScalar() ? scalarVal > 0 && sparsityEst < 0.2 + : _inputs.get(0).getDataType().isScalar() && scalarVal <= 0 && sparsityEst < 0.2; + } else + return false; + } + case VECT_MIN_SCALAR: { + if(scalarVal != Double.NaN) { + return _inputs.get(1).getDataType().isScalar() ? scalarVal >= 0 && sparsityEst < 0.2 + : _inputs.get(0).getDataType().isScalar() && scalarVal >= 0 && sparsityEst < 0.2; + } else + return false; + } + case VECT_LESS_SCALAR: { + if(scalarVal != Double.NaN) { + return _inputs.get(1).getDataType().isScalar() ? scalarVal <= 0 && sparsityEst < 0.2 + : _inputs.get(0).getDataType().isScalar() && scalarVal > 0 && sparsityEst < 0.2; + } else + return false; + } + case VECT_LESSEQUAL_SCALAR: { + if(scalarVal != Double.NaN) { + return _inputs.get(1).getDataType().isScalar() ? scalarVal < 0 && sparsityEst < 0.2 + : _inputs.get(0).getDataType().isScalar() && scalarVal >= 0 && sparsityEst < 0.2; + } else + return false; + } + case VECT_MAX_SCALAR: { + if(scalarVal != Double.NaN) { + return _inputs.get(1).getDataType().isScalar() ? scalarVal <= 0 && sparsityEst < 0.2 + : _inputs.get(0).getDataType().isScalar() && scalarVal <= 0 && sparsityEst < 0.2; + } else + return false; + } + case VECT_POW_SCALAR: + case VECT_EQUAL_SCALAR:{ + if(scalarVal != Double.NaN) { + return _inputs.get(1).getDataType().isScalar() ? scalarVal != 0 && sparsityEst < 0.2 + : _inputs.get(0).getDataType().isScalar() && scalarVal != 0 && sparsityEst < 0.2; + } else + return false; + } + case VECT_NOTEQUAL_SCALAR:{ + if(scalarVal != Double.NaN) { + return _inputs.get(1).getDataType().isScalar() ? scalarVal == 0 && sparsityEst < 0.2 + : _inputs.get(0).getDataType().isScalar() && scalarVal == 0 && sparsityEst < 0.2; + } else + return false; + } + default: return sparsityEst < 0.3; + } + } + } + + public boolean getOutputType(boolean scalarVector, boolean lsparseLhs, boolean lsparseRhs) { + switch(_type) { + case VECT_POW_SCALAR: return !scalarVector && lsparseLhs; + case VECT_MULT_SCALAR: + case VECT_DIV_SCALAR: + case VECT_XOR_SCALAR: + case VECT_MIN_SCALAR: + case VECT_MAX_SCALAR: + case VECT_EQUAL_SCALAR: + case VECT_NOTEQUAL_SCALAR: + case VECT_LESS_SCALAR: + case VECT_LESSEQUAL_SCALAR: + case VECT_GREATER_SCALAR: + case VECT_GREATEREQUAL_SCALAR: + case VECT_BITWAND_SCALAR: return lsparseLhs || lsparseRhs; + case VECT_MULT: + case VECT_DIV: + case VECT_MINUS: + case VECT_PLUS: + case VECT_XOR: + case VECT_BITWAND: + case VECT_BIASADD: + case VECT_BIASMULT: + case VECT_MIN: + case VECT_MAX: + case VECT_NOTEQUAL: + case VECT_LESS: + case VECT_GREATER: return lsparseLhs && lsparseRhs; + default: return false; + } + } @Override public String toString() { diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeNary.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeNary.java index dcf18ec656..35c351546d 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeNary.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeNary.java @@ -60,7 +60,10 @@ public class CNodeNary extends CNode sb.append( sparseInput ? " LibSpoofPrimitives.vectWrite("+varj+"vals, %TMP%, " +varj+"ix, "+pos+", "+off+", "+input._cols+");\n" : - " LibSpoofPrimitives.vectWrite("+(varj.startsWith("b")?varj+".values(rix)":varj) + varj.startsWith("STMP") ? + " LibSpoofPrimitives.vectWrite("+varj+".values(), %TMP%, " + +varj+".indexes(), "+pos+", "+off+", "+varj+".size());\n" : + " LibSpoofPrimitives.vectWrite("+(varj.startsWith("b")?varj+".values(rix)":varj) +", %TMP%, "+pos+", "+off+", "+input._cols+");\n"); off += input._cols; } diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeRow.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeRow.java index 77dec97cbe..c0d06b4bcb 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeRow.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeRow.java @@ -37,6 +37,7 @@ public class CNodeRow extends CNodeTpl + "import org.apache.sysds.runtime.codegen.SpoofOperator.SideInput;\n" + "import org.apache.sysds.runtime.codegen.SpoofRowwise;\n" + "import org.apache.sysds.runtime.codegen.SpoofRowwise.RowType;\n" + + "import org.apache.sysds.runtime.data.SparseRowVector;\n" + "import org.apache.commons.math3.util.FastMath;\n" + "\n" + "public final class %TMP% extends SpoofRowwise { \n" @@ -162,7 +163,8 @@ private static final String TEMPLATE_ROWAGG_OUT_CUDA = "\t\tif(threadIdx.x == 0 case NO_AGG_B1: case NO_AGG_CONST: if(api == GeneratorAPI.JAVA) - return TEMPLATE_NOAGG_OUT.replace("%IN%", varName).replace("%LEN%", _output.getVarname()+".length"); + return TEMPLATE_NOAGG_OUT.replace("%IN%", varName.startsWith("STMP")?varName+".values(), "+varName+".indexes()":varName).replace("%LEN%", + varName.startsWith("STMP") ? varName+".size()" : _output.getVarname()+".length"); else return TEMPLATE_NOAGG_CONST_OUT_CUDA.replace("%IN%", varName + ".vals(0)").replaceAll("%LEN%", _output.getVarname()+".length"); case FULL_AGG: diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeTernary.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeTernary.java index 5e81109283..c6ff9802b1 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeTernary.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeTernary.java @@ -82,10 +82,13 @@ public class CNodeTernary extends CNode String varj = _inputs.get(j-1).getVarname(); //replace sparse and dense inputs tmp = tmp.replace("%IN"+j+"v%", - varj+(varj.startsWith("a")?"vals":"") ); + varj+(varj.startsWith("a")?"vals" : varj.startsWith("STMP") ? ".values()" :"") ); tmp = tmp.replace("%IN"+j+"i%", - varj+(varj.startsWith("a")?"ix":"") ); + varj+(varj.startsWith("a")?"ix": varj.startsWith("STMP") ? ".indexes()" :"") ); tmp = tmp.replace("%IN"+j+"%", varj ); + tmp = tmp.replace("%POS%", varj.startsWith("a") ? varj+"i" : varj.startsWith("STMP") ? "0" : ""); + tmp = tmp.replace("%LEN%", + varj.startsWith("a") ? "alen" : varj.startsWith("STMP") ? varj+".size()" : ""); } sb.append(tmp); diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeUnary.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeUnary.java index fe67995b6b..ffbe0087f1 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeUnary.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/CNodeUnary.java @@ -23,6 +23,7 @@ import java.util.Arrays; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.sysds.api.DMLScript; import org.apache.sysds.common.Opcodes; import org.apache.sysds.common.Types.DataType; import org.apache.sysds.runtime.util.UtilFunctions; @@ -85,13 +86,21 @@ public class CNodeUnary extends CNode } private UnaryType _type; - + private boolean sparseTemplate; + public CNodeUnary( CNode in1, UnaryType type ) { _inputs.add(in1); _type = type; setOutputDims(); } - + + public CNodeUnary( CNode in1, UnaryType type, double sparsity ) { + _inputs.add(in1); + _type = type; + setOutputDims(); + sparseTemplate = getTemplateType(sparsity); + } + public UnaryType getType() { return _type; } @@ -111,11 +120,13 @@ public class CNodeUnary extends CNode sb.append(_inputs.get(0).codegen(sparse, api)); //generate unary operation - boolean lsparse = sparse && (_inputs.get(0) instanceof CNodeData - && _inputs.get(0).getVarname().startsWith("a") - && !_inputs.get(0).isLiteral()); - String var = createVarname(); - String tmp = getLanguageTemplateClass(this, api).getTemplate(_type, lsparse); + boolean lsparse = sparse && + ((_inputs.get(0) instanceof CNodeData + && _inputs.get(0).getVarname().startsWith("a") + && !_inputs.get(0).isLiteral()) + || _inputs.get(0).getVarname().startsWith("STMP")); + String var = createVarname(sparseTemplate && lsparse && getOutputType()); + String tmp = getLanguageTemplateClass(this, api).getTemplate(_type, lsparse, sparseTemplate); tmp = tmp.replaceAll("%TMP%", var); //replace sparse and dense inputs @@ -130,6 +141,46 @@ public class CNodeUnary extends CNode return sb.toString(); } + + public boolean getTemplateType(double sparsity) { + if(!DMLScript.SPARSE_INTERMEDIATE) + return false; + else { + switch(_type) { + case VECT_SQRT: + case VECT_ABS: + case VECT_ROUND: + case VECT_CEIL: + case VECT_FLOOR: + case VECT_SIN: + case VECT_TAN: + case VECT_ASIN: + case VECT_ATAN: + case VECT_SINH: + case VECT_TANH: + case VECT_SIGN: return sparsity <= 0.3; + default: return false; + } + } + } + + public boolean getOutputType() { + switch(_type) { + case VECT_SQRT: + case VECT_ABS: + case VECT_ROUND: + case VECT_CEIL: + case VECT_FLOOR: + case VECT_SIN: + case VECT_TAN: + case VECT_ASIN: + case VECT_ATAN: + case VECT_SINH: + case VECT_TANH: + case VECT_SIGN: return true; + default: return false; + } + } @Override public String toString() { diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/CodeTemplate.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/CodeTemplate.java index e29594f525..1ca8b4a3c1 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/CodeTemplate.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/CodeTemplate.java @@ -31,9 +31,17 @@ public abstract class CodeTemplate { public String getTemplate() { throw new RuntimeException("Calling wrong getTemplate method on " + getClass().getCanonicalName()); } - + + /** + * @param sparseTemplate added to turn SparseRowVector intermediates on and off + */ public String getTemplate(CNodeBinary.BinType type, boolean sparseLhs, boolean sparseRhs, boolean scalarVector, - boolean scalarInput, boolean vectorVector) { + boolean scalarInput, boolean vectorVector, boolean sparseTemplate) { + throw new RuntimeException("Calling wrong getTemplate method on " + getClass().getCanonicalName()); + } + + public String getTemplate(CNodeBinary.BinType type, boolean sparseLhs, boolean sparseRhs, + boolean scalarVector, boolean scalarInput, boolean vectorVector) { throw new RuntimeException("Calling wrong getTemplate method on " + getClass().getCanonicalName()); } @@ -44,6 +52,10 @@ public abstract class CodeTemplate { public String getTemplate(CNodeUnary.UnaryType type, boolean sparse) { throw new RuntimeException("Calling wrong getTemplate method on " + getClass().getCanonicalName()); } + + public String getTemplate(CNodeUnary.UnaryType type, boolean sparse, boolean sparseTemplate) { + throw new RuntimeException("Calling wrong getTemplate method on " + getClass().getCanonicalName()); + } public static String getTemplate(String templateFileName) { try { @@ -68,5 +80,5 @@ public abstract class CodeTemplate { return null; } } - + } diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Binary.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Binary.java index 40496249e5..34c4ee9088 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Binary.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Binary.java @@ -25,7 +25,7 @@ import org.apache.sysds.hops.codegen.cplan.CodeTemplate; public class Binary extends CodeTemplate { public String getTemplate(BinType type, boolean sparseLhs, boolean sparseRhs, - boolean scalarVector, boolean scalarInput, boolean vectorVector) + boolean scalarVector, boolean scalarInput, boolean vectorVector, boolean sparseTemplate) { switch (type) { case ROWMAXS_VECTMULT: @@ -68,13 +68,22 @@ public class Binary extends CodeTemplate { } //vector-scalar operations + case VECT_POW_SCALAR: { + String vectName = type.getVectorPrimitiveName(); + if( scalarVector ) + return sparseRhs ? " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2v%, %IN2i%, %POS2%, alen, %LEN%);\n" : + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2%, %POS2%, %LEN%);\n"; + else if(sparseTemplate) { + return sparseLhs ? " SparseRowVector %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%LEN%, %IN1v%, %IN2%, %IN1i%, %POS1%, %SLEN1%);\n" : + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2%, %POS1%, %LEN%);\n"; + } else { + return sparseLhs ? " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1v%, %IN2%, %IN1i%, %POS1%, alen, %LEN%);\n" : + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2%, %POS1%, %LEN%);\n"; + } + } case VECT_MULT_SCALAR: case VECT_DIV_SCALAR: - case VECT_MINUS_SCALAR: - case VECT_PLUS_SCALAR: - case VECT_POW_SCALAR: case VECT_XOR_SCALAR: - case VECT_BITWAND_SCALAR: case VECT_MIN_SCALAR: case VECT_MAX_SCALAR: case VECT_EQUAL_SCALAR: @@ -82,7 +91,22 @@ public class Binary extends CodeTemplate { case VECT_LESS_SCALAR: case VECT_LESSEQUAL_SCALAR: case VECT_GREATER_SCALAR: - case VECT_GREATEREQUAL_SCALAR: { + case VECT_GREATEREQUAL_SCALAR: + case VECT_BITWAND_SCALAR: { + String vectName = type.getVectorPrimitiveName(); + if(scalarVector) { + if(sparseRhs) + return sparseTemplate ? " SparseRowVector %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%LEN%, %IN1%, %IN2v%, %IN2i%, %POS2%, %SLEN1%);\n" : + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2v%, %IN2i%, %POS2%, alen, %LEN%);\n"; + } else { + if(sparseLhs) + return sparseTemplate ? " SparseRowVector %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%LEN%, %IN1v%, %IN2%, %IN1i%, %POS1%, %SLEN1%);\n" : + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1v%, %IN2%, %IN1i%, %POS1%, alen, %LEN%);\n"; + } + return " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2%, %POS1%, %LEN%);\n"; + } + case VECT_MINUS_SCALAR: + case VECT_PLUS_SCALAR: { String vectName = type.getVectorPrimitiveName(); if( scalarVector ) return sparseRhs ? " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2v%, %IN2i%, %POS2%, alen, %LEN%);\n" : @@ -115,20 +139,34 @@ public class Binary extends CodeTemplate { case VECT_BIASMULT: case VECT_MIN: case VECT_MAX: - case VECT_EQUAL: case VECT_NOTEQUAL: case VECT_LESS: + case VECT_GREATER:{ + String vectName = type.getVectorPrimitiveName(); + if(sparseTemplate && sparseLhs && sparseRhs) { + return " SparseRowVector %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%LEN%, %IN1v%, %IN2v%, %IN1i%, %IN2i%, %POS1%, %POS2%, %SLEN1%, %SLEN2%);\n"; + } else { + return sparseLhs ? + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1v%, %IN2%, %IN1i%, %POS1%, %POS2%, alen, %LEN%);\n" : + sparseRhs ? + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2v%, %POS1%, %IN2i%, %POS2%, alen, %LEN%);\n" : + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2%, %POS1%, %POS2%, %LEN%);\n"; + } + } + case VECT_EQUAL: case VECT_LESSEQUAL: - case VECT_GREATER: case VECT_GREATEREQUAL: { String vectName = type.getVectorPrimitiveName(); - return sparseLhs ? + if(sparseTemplate && sparseLhs && sparseRhs) { + return " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%LEN%, %IN1v%, %IN2v%, %IN1i%, %IN2i%, %POS1%, %POS2%, %SLEN1%, %SLEN2%);\n"; + } else { + return sparseLhs ? " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1v%, %IN2%, %IN1i%, %POS1%, %POS2%, alen, %LEN%);\n" : sparseRhs ? - " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2v%, %POS1%, %IN2i%, %POS2%, alen, %LEN%);\n" : - " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2%, %POS1%, %POS2%, %LEN%);\n"; + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2v%, %POS1%, %IN2i%, %POS2%, alen, %LEN%);\n" : + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %IN2%, %POS1%, %POS2%, %LEN%);\n"; + } } - //scalar-scalar operations case MULT: return " double %TMP% = %IN1% * %IN2%;\n"; diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Ternary.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Ternary.java index a86d51cca8..64d282bbb8 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Ternary.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Ternary.java @@ -51,7 +51,7 @@ public class Ternary extends CodeTemplate { case LOOKUP_RC1: return sparse ? - " double %TMP% = getValue(%IN1v%, %IN1i%, ai, alen, %IN3%-1);\n" : + " double %TMP% = getValue(%IN1v%, %IN1i%, %POS%, %LEN%, %IN3%-1);\n" : " double %TMP% = getValue(%IN1%, %IN2%, rix, %IN3%-1);\n"; case LOOKUP_RVECT1: diff --git a/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Unary.java b/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Unary.java index d8a1085df5..ef256223b9 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Unary.java +++ b/src/main/java/org/apache/sysds/hops/codegen/cplan/java/Unary.java @@ -25,7 +25,7 @@ import org.apache.sysds.hops.codegen.cplan.CodeTemplate; public class Unary extends CodeTemplate { @Override - public String getTemplate(UnaryType type, boolean sparse) { + public String getTemplate(UnaryType type, boolean sparse, boolean sparseTemplate) { switch( type ) { case ROW_SUMS: case ROW_SUMSQS: @@ -38,25 +38,32 @@ public class Unary extends CodeTemplate { return sparse ? " double %TMP% = LibSpoofPrimitives.vect"+vectName+"(%IN1v%, %IN1i%, %POS1%, alen, len);\n": " double %TMP% = LibSpoofPrimitives.vect"+vectName+"(%IN1%, %POS1%, %LEN%);\n"; } - case VECT_EXP: - case VECT_POW2: - case VECT_MULT2: + case VECT_SQRT: - case VECT_LOG: case VECT_ABS: case VECT_ROUND: case VECT_CEIL: case VECT_FLOOR: - case VECT_SIGN: case VECT_SIN: - case VECT_COS: case VECT_TAN: case VECT_ASIN: - case VECT_ACOS: case VECT_ATAN: case VECT_SINH: - case VECT_COSH: case VECT_TANH: + case VECT_SIGN:{ + String vectName = type.getVectorPrimitiveName(); + return sparse ? sparseTemplate ? + " SparseRowVector %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(len, %IN1v%, %IN1i%, %POS1%, alen);\n" : + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1v%, %IN1i%, %POS1%, alen, len);\n" : + " double[] %TMP% = LibSpoofPrimitives.vect"+vectName+"Write(%IN1%, %POS1%, %LEN%);\n"; + } + case VECT_EXP: + case VECT_POW2: + case VECT_MULT2: + case VECT_LOG: + case VECT_COS: + case VECT_ACOS: + case VECT_COSH: case VECT_CUMSUM: case VECT_CUMMIN: case VECT_CUMMAX: diff --git a/src/main/java/org/apache/sysds/hops/codegen/template/TemplateRow.java b/src/main/java/org/apache/sysds/hops/codegen/template/TemplateRow.java index 955bf778b8..8efb0245e9 100644 --- a/src/main/java/org/apache/sysds/hops/codegen/template/TemplateRow.java +++ b/src/main/java/org/apache/sysds/hops/codegen/template/TemplateRow.java @@ -37,6 +37,7 @@ import org.apache.sysds.hops.NaryOp; import org.apache.sysds.hops.ParameterizedBuiltinOp; import org.apache.sysds.hops.TernaryOp; import org.apache.sysds.hops.UnaryOp; +import org.apache.sysds.hops.OptimizerUtils; import org.apache.sysds.hops.codegen.cplan.CNode; import org.apache.sysds.hops.codegen.cplan.CNodeBinary; import org.apache.sysds.hops.codegen.cplan.CNodeData; @@ -391,7 +392,7 @@ public class TemplateRow extends TemplateBase { if( HopRewriteUtils.isUnary(hop, SUPPORTED_VECT_UNARY) ) { String opname = "VECT_"+((UnaryOp)hop).getOp().name(); - out = new CNodeUnary(cdata1, UnaryType.valueOf(opname)); + out = new CNodeUnary(cdata1, UnaryType.valueOf(opname), hop.getInput(0).getSparsity()); if( cdata1 instanceof CNodeData && !inHops2.containsKey("X") ) inHops2.put("X", hop.getInput().get(0)); } @@ -403,7 +404,7 @@ public class TemplateRow extends TemplateBase { cdata1 = TemplateUtils.wrapLookupIfNecessary(cdata1, hop.getInput().get(0)); String primitiveOpName = ((UnaryOp)hop).getOp().name(); - out = new CNodeUnary(cdata1, UnaryType.valueOf(primitiveOpName)); + out = new CNodeUnary(cdata1, UnaryType.valueOf(primitiveOpName), hop.getInput(0).getSparsity()); } } else if(HopRewriteUtils.isBinary(hop, OpOp2.CBIND)) { @@ -440,7 +441,14 @@ public class TemplateRow extends TemplateBase cdata1 = new CNodeUnary(cdata1, UnaryType.LOOKUP_R); if( TemplateUtils.isColVector(cdata2) ) cdata2 = new CNodeUnary(cdata2, UnaryType.LOOKUP_R); - out = getVectorBinary(cdata1, cdata2, ((BinaryOp)hop).getOp().name()); + String opName = ((BinaryOp)hop).getOp().name(); + Hop hopIn1 = hop.getInput(0); + Hop hopIn2 = hop.getInput(1); + double sparsityEst = OptimizerUtils.getBinaryOpSparsity( + hopIn1.getSparsity(), hopIn2.getSparsity(), OpOp2.valueOf(opName), false); + double literalVal = hopIn1 instanceof LiteralOp ? ((LiteralOp) hopIn1).getDoubleValue() + : hopIn2 instanceof LiteralOp ? ((LiteralOp) hopIn2).getDoubleValue() : Double.NaN; + out = getVectorBinary(cdata1, cdata2, opName, sparsityEst, literalVal); if( cdata1 instanceof CNodeData && !inHops2.containsKey("X") && !(cdata1.getDataType()==DataType.SCALAR) ) { inHops2.put("X", hop.getInput().get(0)); @@ -569,7 +577,17 @@ public class TemplateRow extends TemplateBase return new CNodeBinary(cdata1, cdata2, BinType.valueOf("VECT_"+name+"_SCALAR")); } } - + + private static CNodeBinary getVectorBinary(CNode cdata1, CNode cdata2, String name, double sparsity, double literalVal) { + if( TemplateUtils.isMatrix(cdata1) && (TemplateUtils.isMatrix(cdata2) + || TemplateUtils.isRowVector(cdata2)) ) { + return new CNodeBinary(cdata1, cdata2, BinType.valueOf("VECT_"+name), sparsity, literalVal); + } + else { + return new CNodeBinary(cdata1, cdata2, BinType.valueOf("VECT_"+name+"_SCALAR"), sparsity, literalVal); + } + } + /** * Comparator to order input hops of the row aggregate template. We try * to order matrices-vectors-scalars via sorting by number of cells but diff --git a/src/main/java/org/apache/sysds/runtime/codegen/LibSpoofPrimitives.java b/src/main/java/org/apache/sysds/runtime/codegen/LibSpoofPrimitives.java index 6c0dc395c3..bc6ba19895 100644 --- a/src/main/java/org/apache/sysds/runtime/codegen/LibSpoofPrimitives.java +++ b/src/main/java/org/apache/sysds/runtime/codegen/LibSpoofPrimitives.java @@ -23,6 +23,7 @@ import java.util.Arrays; import org.apache.commons.math3.util.FastMath; import org.apache.sysds.runtime.data.DenseBlockFP64; +import org.apache.sysds.runtime.data.SparseRowVector; import org.apache.sysds.runtime.functionobjects.BitwAnd; import org.apache.sysds.runtime.functionobjects.IntegerDivide; import org.apache.sysds.runtime.functionobjects.Modulus; @@ -51,6 +52,10 @@ public class LibSpoofPrimitives @Override protected VectorBuffer initialValue() { return new VectorBuffer(0,0,0); } }; + private static ThreadLocal<SparseVectorBuffer> sparseMemPool = new ThreadLocal<>() { + @Override protected SparseVectorBuffer initialValue() { return new SparseVectorBuffer(0,0,0); } + }; + public static double rowMaxsVectMult(double[] a, double[] b, int ai, int bi, int len) { double val = Double.NEGATIVE_INFINITY; int j=0; @@ -2164,6 +2169,1155 @@ public class LibSpoofPrimitives return (vectSum(avalsSqr, 0, len)-len*meanVal)/(len-1); } + /** + * Vector primitives with SparseRowVector intermediates + * Changes: + * - Changed method signature to avoid method duplicate conflicts + * e.g. (double[], double, int[], int, int, int) --> (int, double[], double, int[], int, int) + * - Added blen for vector - vector calculations to be able to use both vectors as SparseRowVectors + * - Implemented a new SparseVectorBuffer class that creates a ring buffer for SparseRowVectors in different sizes + */ + + public static SparseRowVector vectMultWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + if( a == null ) return c; + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = a[ai+j]*bval; + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectMultWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectMultWrite(len, a, bval, aix, ai, alen); + } + + //old version with branching (not used) + public static SparseRowVector vectMultWriteB(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(Math.min(alen, blen)); + if( a == null || b == null ) return c; + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while(aItr < ai+alen && bItr < bi+blen) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + if(aIdx == bIdx) { + indexes[index] = aIdx; + values[index] = a[aItr] * b[bItr]; + aItr++; + bItr++; + index++; + } else if(aIdx < bIdx) + aItr++; + else + bItr++; + } + c.setSize(index); + return c; + } + + //version without branching + public static SparseRowVector vectMultWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(Math.min(alen, blen)); + int index = 0; + int aItr = ai; + int bItr = bi; + int[] indexes = c.indexes(); + double[] values = c.values(); + while(aItr < ai+alen && bItr < bi+blen) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + indexes[index] = aIdx; + values[index] = a[aItr] * b[bItr]; + index += aIdx == bIdx ? 1 : 0; + aItr += aIdx <= bIdx ? 1 : 0; + bItr += aIdx >= bIdx ? 1 : 0; + } + c.setSize(index); + return c; + } + + public static void vectWrite(double[] a, int[] aix, double[] c, int ci, int len) { + if( a == null ) return; + for(int j = 0; j < len; j++) + c[ci+aix[j]] = a[j]; + } + + public static void vectWrite(double[] a, double[] c, int[] aix, int ai, int ci, int alen) { + if( a == null ) return; + for(int j = 0; j < alen; j++) + c[ci+aix[ai+j]] = a[ai+j]; + } + + public static SparseRowVector vectDivWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for( int j = 0; j < alen; j++ ) { + indexes[j] = aix[ai+j]; + values[j] = a[ai+j] / bval; + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectDivWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = bval / a[ai+j]; + } + c.setSize(alen); + return c; + } + + //old version with branching (not used) + public static SparseRowVector vectDivWriteB(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen); + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while(aItr < ai+alen && bItr < bi+blen) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + if(aIdx == bIdx) { + indexes[index] = aIdx; + values[index] = a[aItr] / b[bItr]; + aItr++; + bItr++; + index++; + } else if(aIdx < bIdx) { + indexes[index] = aIdx; + values[index] = (a[aItr]>0) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY; + aItr++; + index++; + } else { + bItr++; + } + } + c.setSize(index); + return c; + } + + //version without branching + public static SparseRowVector vectDivWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(Math.min(alen, blen)); + int index = 0; + int aItr = ai; + int bItr = bi; + int[] indexes = c.indexes(); + double[] values = c.values(); + while(aItr < ai+alen && bItr < bi+blen) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + indexes[index] = aIdx; + values[index] = a[aItr] / b[bItr]; + index += aIdx == bIdx ? 1 : 0; + aItr += aIdx <= bIdx ? 1 : 0; + bItr += aIdx >= bIdx ? 1 : 0; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectMinusWriteB(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen+blen); + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while(aItr < ai+alen && bItr < bi+blen) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + if(aIdx == bIdx) { + indexes[index] = aIdx; + values[index] = a[aItr] - b[bItr]; + aItr++; + bItr++; + index++; + } else if(aIdx < bIdx) { + indexes[index] = aIdx; + values[index] = a[aItr]; + aItr++; + index++; + } else { + indexes[index] = bIdx; + values[index] = -b[bItr]; + bItr++; + index++; + } + } + for (; aItr < ai+alen; aItr++) { + indexes[index] = aix[aItr]; + values[index] = a[aItr]; + index++; + } + for (; bItr < bi+blen; bItr++) { + indexes[index] = bix[bItr]; + values[index] = -b[bItr]; + index++; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectMinusWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen+blen); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while (aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + indexes[index] = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + values[index] = av - bv; + aItr += useA; + bItr += useB; + index++; + } + for (; aItr < aEnd; aItr++, index++) { + indexes[index] = aix[aItr]; + values[index] = a[aItr]; + } + for (; bItr < bEnd; bItr++, index++) { + indexes[index] = bix[bItr]; + values[index] = -b[bItr]; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectPlusWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen+blen); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while (aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + indexes[index] = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + values[index] = av + bv; + aItr += useA; + bItr += useB; + index++; + } + for (; aItr < aEnd; aItr++) { + indexes[index] = aix[aItr]; + values[index] = a[aItr]; + index++; + } + for (; bItr < bEnd; bItr++) { + indexes[index] = bix[bItr]; + values[index] = b[bItr]; + index++; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectXorWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval != 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = !(a[aItr] != 0) ? 1 : 0; + aItr++; + } else { + values[index] = 1; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = 1; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = (a[ai+j] != 0) ? 1 : 0; + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectXorWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectXorWrite(len, a, bval, aix, ai, alen); + } + + public static SparseRowVector vectXorWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen+blen); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while (aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + indexes[index] = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + values[index] = ((av != 0) != (bv != 0)) ? 1 : 0; + aItr += useA; + bItr += useB; + index++; + } + for (; aItr < aEnd; aItr++) { + indexes[index] = aix[aItr]; + values[index] = (a[aItr] != 0) ? 1 : 0; + index++; + } + for (; bItr < bEnd; bItr++) { + indexes[index] = bix[bItr]; + values[index] = (b[bItr] != 0) ? 1 : 0; + index++; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectPowWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval == 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = Math.pow(a[aItr], bval) - 1; + aItr++; + } else { + values[index] = 1; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = 1; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.pow(a[ai+j], bval); + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectMinWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval < 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = Math.min(a[aItr], bval); + aItr++; + } else { + values[index] = bval; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = bval; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.min(a[ai+j], bval); + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectMinWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectMinWrite(len, a, bval, aix, ai, alen); + } + + public static SparseRowVector vectMinWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen+blen); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while (aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + indexes[index] = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + values[index] = Math.min(av, bv); + aItr += useA; + bItr += useB; + index++; + } + for (; aItr < aEnd; aItr++) { + indexes[index] = aix[aItr]; + values[index] = Math.min(a[aItr], 0); + index++; + } + for (; bItr < bEnd; bItr++) { + indexes[index] = bix[bItr]; + values[index] = Math.min(b[bItr], 0); + index++; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectMaxWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval > 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = Math.max(a[aItr], bval); + aItr++; + } else { + values[index] = bval; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = bval; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.max(a[ai+j], bval); + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectMaxWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectMaxWrite(len, a, bval, aix, ai, alen); + } + + public static SparseRowVector vectMaxWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen+blen); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while (aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + indexes[index] = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + values[index] = Math.max(av, bv); + aItr += useA; + bItr += useB; + index++; + } + for (; aItr < aEnd; aItr++) { + indexes[index] = aix[aItr]; + values[index] = Math.max(a[aItr], 0); + index++; + } + for (; bItr < bEnd; bItr++) { + indexes[index] = bix[bItr]; + values[index] = Math.max(b[bItr], 0); + index++; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectEqualWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval == 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = a[aItr] == bval ? 1 : 0; + aItr++; + } else { + values[index] = 1; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = 1; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = a[ai+j] == bval ? 1 : 0; + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectEqualWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectEqualWrite(len, a, bval, aix, ai, alen); + } + + //doesn't return SparseRowVector, but still uses two sparse vectors as inputs + public static double[] vectEqualWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + double[] c = allocVector(len, true, 1); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + while(aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + int index = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + c[index] = av == bv ? 1 : 0; + aItr += useA; + bItr += useB; + } + for (; aItr < aEnd; aItr++) c[aix[aItr]] = 0; + for (; bItr < bEnd; bItr++) c[bix[bItr]] = 0; + return c; + } + + public static SparseRowVector vectNotequalWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval != 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = a[aItr] != bval ? 1 : 0; + aItr++; + } else { + values[index] = 1; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = 1; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = a[ai+j] != bval ? 1 : 0; + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectNotequalWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectNotequalWrite(len, a, bval, aix, ai, alen); + } + + public static SparseRowVector vectNotequalWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen+blen); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while (aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + indexes[index] = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + values[index] = (av != bv) ? 1 : 0; + aItr += useA; + bItr += useB; + index++; + } + for (; aItr < aEnd; aItr++) { + indexes[index] = aix[aItr]; + values[index] = a[aItr] != 0 ? 1 : 0; + index++; + } + for (; bItr < bEnd; bItr++) { + indexes[index] = bix[bItr]; + values[index] = b[bItr] != 0 ? 1 : 0; + index++; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectLessWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval > 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = a[aItr] < bval ? 1 : 0; + aItr++; + } else { + values[index] = 1; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = 1; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = a[ai+j] < bval ? 1 : 0; + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectLessWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectGreaterequalWrite(len, a, bval, aix, ai, alen); + } + + public static SparseRowVector vectLessWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen+blen); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while (aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + indexes[index] = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + values[index] = av < bv ? 1 : 0; + aItr += useA; + bItr += useB; + index++; + } + for (; aItr < aEnd; aItr++) { + indexes[index] = aix[aItr]; + values[index] = a[aItr] < 0? 1 : 0; + index++; + } + for (; bItr < bEnd; bItr++) { + indexes[index] = bix[bItr]; + values[index] = 0 < b[bItr] ? 1 : 0; + index++; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectLessequalWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval >= 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = a[aItr] <= bval ? 1 : 0; + aItr++; + } else { + values[index] = 1; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = 1; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = a[ai+j] <= bval ? 1 : 0; + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectLessequalWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectGreaterWrite(len, a, bval, aix, ai, alen); + } + + //doesn't return SparseRowVector, but still uses two sparse vectors as inputs + public static double[] vectLessequalWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + double[] c = allocVector(len, true, 1); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + while(aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + int index = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + c[index] = av <= bv ? 1 : 0; + aItr += useA; + bItr += useB; + } + for(; aItr < ai+alen; aItr++) c[aix[aItr]] = (a[aItr] <= 0) ? 1 : 0; + for(; bItr < bi+blen; bItr++) c[bix[bItr]] = (0 <= b[bItr]) ? 1 : 0; + return c; + } + + public static SparseRowVector vectGreaterWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval < 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = a[aItr] > bval ? 1 : 0; + aItr++; + } else { + values[index] = 1; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = 1; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = a[ai+j] > bval ? 1 : 0; + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectGreaterWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectLessequalWrite(len, a, bval, aix, ai, alen); + } + + public static SparseRowVector vectGreaterWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(alen+blen); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + int index = 0; + int[] indexes = c.indexes(); + double[] values = c.values(); + while (aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + indexes[index] = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + values[index] = av >bv ? 1 : 0; + aItr += useA; + bItr += useB; + index++; + } + for (; aItr < ai+alen; aItr++) { + indexes[index] = aix[aItr]; + values[index] = a[aItr] > 0 ? 1 : 0; + index++; + } + for (; bItr < bi+blen; bItr++) { + indexes[index] = bix[bItr]; + values[index] = 0 > b[bItr] ? 1 : 0; + index++; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectGreaterequalWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + if(bval <= 0) { + SparseRowVector c = allocSparseVector(len); + int[] indexes = c.indexes(); + double[] values = c.values(); + int index = 0; + int aItr = 0; + while(aItr < ai+alen && index < len) { + indexes[index] = index; + if(aix[aItr] == index) { + values[index] = a[aItr] >= bval ? 1 : 0; + aItr++; + } else { + values[index] = 1; + } + index++; + } + for(; index < len; index++) { + indexes[index] = index; + values[index] = 1; + } + c.setSize(len); + return c; + } else { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = a[ai+j] >= bval ? 1 : 0; + } + c.setSize(alen); + return c; + } + } + + public static SparseRowVector vectGreaterequalWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectLessWrite(len, a, bval, aix, ai, alen); + } + + //doesn't return SparseRowVector, but still uses two sparse vectors as inputs + public static double[] vectGreaterequalWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + double[] c = allocVector(len, true, 1); + int aEnd = ai+alen; + int bEnd = bi+blen; + int aItr = ai; + int bItr = bi; + while(aItr < aEnd && bItr < bEnd) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + int useA = (aIdx <= bIdx) ? 1 : 0; + int useB = (aIdx >= bIdx) ? 1 : 0; + int index = (useA == 1) ? aIdx : bIdx; + double av = (useA == 1) ? a[aItr] : 0.0; + double bv = (useB == 1) ? b[bItr] : 0.0; + + c[index] = av >= bv ? 1 : 0; + aItr += useA; + bItr += useB; + } + for(; aItr < ai+alen; aItr++) c[aix[aItr]] = (a[aItr] >= 0) ? 1 : 0; + for(; bItr < bi+blen; bItr++) c[bix[bItr]] = (0 >= b[bItr]) ? 1 : 0; + return c; + } + + public static SparseRowVector vectBitwandWrite(int len, double[] a, double bval, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + int bval1 = (int) bval; + for( int j = 0; j < alen; j++ ) { + indexes[j] = aix[ai+j]; + values[j] = bwAnd(a[ai+j], bval1); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectBitwandWrite(int len, double bval, double[] a, int[] aix, int ai, int alen) { + return vectBitwandWrite(len, a, bval, aix, ai, alen); + } + + public static SparseRowVector vectBitwandWrite(int len, double[] a, double[] b, int[] aix, int[] bix, int ai, int bi, int alen, int blen) { + SparseRowVector c = allocSparseVector(Math.min(alen, blen)); + int index = 0; + int aItr = ai; + int bItr = bi; + int[] indexes = c.indexes(); + double[] values = c.values(); + while(aItr < ai+alen && bItr < bi+blen) { + int aIdx = aix[aItr]; + int bIdx = bix[bItr]; + indexes[index] = aIdx; + values[index] = bwAnd(a[aItr], b[bItr]); + index += aIdx == bIdx ? 1 : 0; + aItr += aIdx <= bIdx ? 1 : 0; + bItr += aIdx >= bIdx ? 1 : 0; + } + c.setSize(index); + return c; + } + + public static SparseRowVector vectSqrtWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.sqrt(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectAbsWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.abs(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectRoundWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.round(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectCeilWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.ceil(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectFloorWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.floor(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectSinWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.sin(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectTanWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.tan(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectAsinWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.asin(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectAtanWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.atan(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectSinhWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.sinh(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectTanhWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.tanh(a[ai+j]); + } + c.setSize(alen); + return c; + } + + public static SparseRowVector vectSignWrite(int len, double[] a, int[] aix, int ai, int alen) { + SparseRowVector c = allocSparseVector(alen); + int[] indexes = c.indexes(); + double[] values = c.values(); + for(int j = 0; j < alen; j++) { + indexes[j] = aix[ai+j]; + values[j] = Math.signum(a[ai+j]); + } + c.setSize(alen); + return c; + } + //complex builtin functions that are not directly generated //(included here in order to reduce the number of imports) @@ -2194,10 +3348,19 @@ public class LibSpoofPrimitives if( numVectors > 0 ) memPool.set(new VectorBuffer(numVectors, len, len2)); } + + public static void setupSparseThreadLocalMemory(int numVectors, int len, int len2) { + if( numVectors > 0 ) + sparseMemPool.set(new SparseVectorBuffer(numVectors, len, len2)); + } public static void cleanupThreadLocalMemory() { memPool.remove(); } + + public static void cleanupSparseThreadLocalMemory() { + sparseMemPool.remove(); + } public static double[] allocVector(int len, boolean reset) { return allocVector(len, reset, 0); @@ -2217,6 +3380,21 @@ public class LibSpoofPrimitives Arrays.fill(vect, resetVal); return vect; } + + public static SparseRowVector allocSparseVector(int len) { + SparseVectorBuffer buff = sparseMemPool.get(); + + //find next matching vector in ring buffer or + //allocate new vector if no vector was returned + SparseRowVector vect = buff.next(len); + if(vect == null) + vect = new SparseRowVector(len); + //reset vector for normal outputs + else if(vect.size() != 0) + vect.reset(len, len); + + return vect; + } /** * Simple ring buffer of allocated vectors, where @@ -2265,4 +3443,52 @@ public class LibSpoofPrimitives && _data.length == lnum); } } + + /** + * Simple ring buffer of allocated SparseRowVectors, where + * vectors of different sizes are interspersed. + */ + private static class SparseVectorBuffer { + private static final int MAX_SIZE = 512*1024; //4MB + private final SparseRowVector[] _data; + private int _pos; + private int _len1; + private int _len2; + + public SparseVectorBuffer(int num, int len1, int len2) { + //best effort size restriction since large intermediates + //not necessarily used (num refers to the total number) + len1 = Math.min(len1, MAX_SIZE); + len2 = Math.min(len2, MAX_SIZE); + //pre-allocate ring buffer + int lnum = (len2>0 && len1!=len2) ? 2*num : num; + _data = new SparseRowVector[lnum]; + for( int i=0; i<num; i++ ) { + if( lnum > num ) { + _data[2*i] = new SparseRowVector(len1); + _data[2*i+1] = new SparseRowVector(len2); + } + else { + _data[i] = new SparseRowVector(len1); + } + } + _pos = -1; + _len1 = len1; + _len2 = len2; + } + public SparseRowVector next(int len) { + if( _len1<len && _len2<len ) + return null; + do { + _pos = (_pos+1>=_data.length) ? 0 : _pos+1; + } while( _data[_pos].values().length<len ); + return _data[_pos]; + } + @SuppressWarnings("unused") + public boolean isReusable(int num, int len1, int len2) { + int lnum = (len2>0 && len1!=len2) ? 2*num : num; + return (_len1 == len1 && _len2 == len2 + && _data.length == lnum); + } + } } diff --git a/src/main/java/org/apache/sysds/runtime/codegen/SpoofRowwise.java b/src/main/java/org/apache/sysds/runtime/codegen/SpoofRowwise.java index eab223bc97..e48d44f33f 100644 --- a/src/main/java/org/apache/sysds/runtime/codegen/SpoofRowwise.java +++ b/src/main/java/org/apache/sysds/runtime/codegen/SpoofRowwise.java @@ -27,6 +27,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.stream.IntStream; +import org.apache.sysds.api.DMLScript; import org.apache.sysds.runtime.DMLRuntimeException; import org.apache.sysds.runtime.compress.CompressedMatrixBlock; import org.apache.sysds.runtime.controlprogram.caching.MatrixObject; @@ -187,7 +188,12 @@ public abstract class SpoofRowwise extends SpoofOperator //setup thread-local memory if necessary if( allocTmp &&_reqVectMem > 0 ) - LibSpoofPrimitives.setupThreadLocalMemory(_reqVectMem, n, n2); + if(inputs.get(0).isInSparseFormat() && DMLScript.SPARSE_INTERMEDIATE) { + LibSpoofPrimitives.setupSparseThreadLocalMemory(_reqVectMem, n, n2); + LibSpoofPrimitives.setupThreadLocalMemory(_reqVectMem, n, n2); + } else { + LibSpoofPrimitives.setupThreadLocalMemory(_reqVectMem, n, n2); + } //core sequential execute MatrixBlock a = inputs.get(0); @@ -201,7 +207,12 @@ public abstract class SpoofRowwise extends SpoofOperator //post-processing if( allocTmp &&_reqVectMem > 0 ) - LibSpoofPrimitives.cleanupThreadLocalMemory(); + if(inputs.get(0).isInSparseFormat() && DMLScript.SPARSE_INTERMEDIATE) { + LibSpoofPrimitives.cleanupSparseThreadLocalMemory(); + LibSpoofPrimitives.cleanupThreadLocalMemory(); + } else { + LibSpoofPrimitives.cleanupThreadLocalMemory(); + } if( flipOut ) { fixTransposeDimensions(out); out = LibMatrixReorg.transpose(out, new MatrixBlock( @@ -431,7 +442,12 @@ public abstract class SpoofRowwise extends SpoofOperator //allocate vector intermediates and partial output if( _reqVectMem > 0 ) - LibSpoofPrimitives.setupThreadLocalMemory(_reqVectMem, _clen, _clen2); + if(_a.isInSparseFormat() && DMLScript.SPARSE_INTERMEDIATE) { + LibSpoofPrimitives.setupSparseThreadLocalMemory(_reqVectMem, _clen, _clen2); + LibSpoofPrimitives.setupThreadLocalMemory(_reqVectMem, _clen, _clen2); + } else { + LibSpoofPrimitives.setupThreadLocalMemory(_reqVectMem, _clen, _clen2); + } DenseBlock c = DenseBlockFactory.createDenseBlock(1, _outLen); if( !_a.isInSparseFormat() ) @@ -440,7 +456,12 @@ public abstract class SpoofRowwise extends SpoofOperator executeSparse(_a.getSparseBlock(), _b, _scalars, c, _clen, _rl, _ru, 0); if( _reqVectMem > 0 ) - LibSpoofPrimitives.cleanupThreadLocalMemory(); + if(_a.isInSparseFormat() && DMLScript.SPARSE_INTERMEDIATE) { + LibSpoofPrimitives.cleanupSparseThreadLocalMemory(); + LibSpoofPrimitives.cleanupThreadLocalMemory(); + } else { + LibSpoofPrimitives.cleanupThreadLocalMemory(); + } return c; } } @@ -474,15 +495,25 @@ public abstract class SpoofRowwise extends SpoofOperator public Long call() { //allocate vector intermediates if( _reqVectMem > 0 ) - LibSpoofPrimitives.setupThreadLocalMemory(_reqVectMem, _clen, _clen2); + if(_a.isInSparseFormat() && DMLScript.SPARSE_INTERMEDIATE) { + LibSpoofPrimitives.setupSparseThreadLocalMemory(_reqVectMem, _clen, _clen2); + LibSpoofPrimitives.setupThreadLocalMemory(_reqVectMem, _clen, _clen2); + } else { + LibSpoofPrimitives.setupThreadLocalMemory(_reqVectMem, _clen, _clen2); + } if( !_a.isInSparseFormat() ) executeDense(_a.getDenseBlock(), _b, _scalars, _c.getDenseBlock(), _clen, _rl, _ru, 0); else executeSparse(_a.getSparseBlock(), _b, _scalars, _c.getDenseBlock(), _clen, _rl, _ru, 0); - + if( _reqVectMem > 0 ) - LibSpoofPrimitives.cleanupThreadLocalMemory(); + if(_a.isInSparseFormat() && DMLScript.SPARSE_INTERMEDIATE) { + LibSpoofPrimitives.cleanupSparseThreadLocalMemory(); + LibSpoofPrimitives.cleanupThreadLocalMemory(); + } else { + LibSpoofPrimitives.cleanupThreadLocalMemory(); + } //maintain nnz for row partition return _c.recomputeNonZeros(_rl, _ru-1, 0, _c.getNumColumns()-1); diff --git a/src/test/java/org/apache/sysds/test/component/codegen/CPlanVectorPrimitivesTest.java b/src/test/java/org/apache/sysds/test/component/codegen/CPlanVectorPrimitivesTest.java index 7d8b4c9096..bae22b1c38 100644 --- a/src/test/java/org/apache/sysds/test/component/codegen/CPlanVectorPrimitivesTest.java +++ b/src/test/java/org/apache/sysds/test/component/codegen/CPlanVectorPrimitivesTest.java @@ -21,6 +21,7 @@ package org.apache.sysds.test.component.codegen; import java.lang.reflect.Method; +import org.apache.sysds.runtime.data.SparseRowVector; import org.junit.Test; import org.apache.sysds.common.Types.OpOp2; import org.apache.sysds.hops.codegen.cplan.CNodeBinary.BinType; @@ -716,6 +717,287 @@ public class CPlanVectorPrimitivesTest extends AutomatedTestBase testVectorBinaryPrimitive(BinType.VECT_BITWAND, InputType.VECTOR_SPARSE, InputType.VECTOR_DENSE); } + //********************testing with sparse intermediates********************// + //vector - scalar + + @Test + public void testVectorScalarMultSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MULT_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarDivSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_DIV_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarMinSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MIN_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarMaxSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MAX_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarPowSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_POW_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_EQUAL_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarNotEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_NOTEQUAL_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarLessSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_LESS_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarLessEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_LESSEQUAL_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarGreaterSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_GREATER_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarGreaterEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_GREATEREQUAL_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + //todo: this only makes sense, when bval is 0 + @Test + public void testVectorScalarXorSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_XOR_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + @Test + public void testVectorScalarBitwAndSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_BITWAND_SCALAR, InputType.VECTOR_SPARSE, InputType.SCALAR); + } + + //scalar - vector + + @Test + public void testScalarVectorMultSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MULT_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorDivSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_DIV_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorMinSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MIN_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorMaxSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MAX_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_EQUAL_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorNotEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_NOTEQUAL_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorLessSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_LESS_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorLessEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_LESSEQUAL_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorGreaterSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_GREATER_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorGreaterEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_GREATEREQUAL_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorXorSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_XOR_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + @Test + public void testScalarVectorBitwAndSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_BITWAND_SCALAR, InputType.SCALAR, InputType.VECTOR_SPARSE); + } + + //special binary + + // @Test + // public void testVectorPow2SparseToSparse() { + // testVectorUnarySparsePrimitive(UnaryType.VECT_POW2, InputType.VECTOR_SPARSE); + // } + // + // @Test + // public void testVectorMult2SparseToSparse() { + // testVectorUnarySparsePrimitive(UnaryType.VECT_MULT2, InputType.VECTOR_SPARSE); + // } + + //vector - vector + + @Test + public void testVectorVectorMultSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MULT, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorDivSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_DIV, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorPlusSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_PLUS, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorMinusSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MINUS, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorMinSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MIN, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + @Test + public void testVectorVectorMaxSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_MAX, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_EQUAL, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorNotEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_NOTEQUAL, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorLessSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_LESS, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorLessEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_LESSEQUAL, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorGreaterSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_GREATER, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorGreaterEqualSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_GREATEREQUAL, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorXorSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_XOR, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorVectorBitwAndSparseToSparse() { + testVectorBinarySparsePrimitive(BinType.VECT_BITWAND, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + } + + // @Test + // public void testVectorVectorMatrixMultSparseToSparse() { + // testVectorBinarySparsePrimitive(BinType.VECT_MATRIXMULT, InputType.VECTOR_SPARSE, InputType.VECTOR_SPARSE); + // } + + //unary primitives with sparse intermediates + + @Test + public void testVectorSqrtSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_SQRT, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorAbsSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_ABS, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorRoundSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_ROUND, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorCeilSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_CEIL, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorFloorSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_FLOOR, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorSinSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_SIN, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorTanSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_TAN, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorAsinSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_ASIN, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorAtanSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_ATAN, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorSinhSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_SINH, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorTanhSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_TANH, InputType.VECTOR_SPARSE); + } + + @Test + public void testVectorSignSparseToSparse() { + testVectorUnarySparsePrimitive(UnaryType.VECT_SIGN, InputType.VECTOR_SPARSE); + } + @SuppressWarnings("incomplete-switch") private static void testVectorAggPrimitive(UnaryType aggtype, InputType type1) { @@ -792,6 +1074,45 @@ public class CPlanVectorPrimitivesTest extends AutomatedTestBase throw new RuntimeException(ex); } } + + private static void testVectorUnarySparsePrimitive(UnaryType utype, InputType type1) + { + try { + //generate input data + double sparsity = (type1 == InputType.VECTOR_DENSE) ? sparsity1 : sparsity2; + MatrixBlock in = MatrixBlock.randOperations(m, n, sparsity, -1, 1, "uniform", 7); + + //get vector primitive via reflection + String meName = "vect"+StringUtils.camelize(utype.name().split("_")[1])+"Write"; + Method me = LibSpoofPrimitives.class.getMethod(meName, new Class[]{int.class, double[].class, int[].class, int.class, int.class}); + + + for( int i=0; i<m; i++ ) { + double[] ret1 = new double[n]; + //execute vector primitive via reflection + SparseRowVector retX = (SparseRowVector) me.invoke(null, n, in.getSparseBlock().values(i), in.getSparseBlock().indexes(i), + in.getSparseBlock().pos(i), in.getSparseBlock().size(i)); + + int[] indexes = retX.indexes(); + for (int j = 0; j < retX.size(); j++) { + ret1[indexes[j]] = retX.get(indexes[j]); + } + + //execute comparison operation + String opcode = utype.name().split("_")[1].toLowerCase(); + UnaryOperator uop = new UnaryOperator(Builtin.getBuiltinFnObject(opcode)); + double[] ret2 = DataConverter.convertToDoubleVector( + in.slice(i, i, 0, n-1, new MatrixBlock()) + .unaryOperations(uop, new MatrixBlock()), false); + + //compare results + TestUtils.compareMatrices(ret1, ret2, eps); + } + } + catch( Exception ex ) { + throw new RuntimeException(ex); + } + } private static void testVectorBinaryPrimitive(BinType bintype, InputType type1, InputType type2) { @@ -868,4 +1189,144 @@ public class CPlanVectorPrimitivesTest extends AutomatedTestBase throw new RuntimeException(ex); } } + + private static void testVectorBinarySparsePrimitive(BinType bintype, InputType type1, InputType type2) { + try { + //generate input data (scalar later derived if needed) + double sparsityA = (type1 == InputType.VECTOR_DENSE) ? sparsity1 : sparsity2; + MatrixBlock inA = MatrixBlock.randOperations(m, n, sparsityA, -5, 5, "uniform", 3); + double sparsityB = (type2 == InputType.VECTOR_DENSE) ? sparsity1 : sparsity2; + MatrixBlock inB = MatrixBlock.randOperations(m, n, sparsityB, -5, 5, "uniform", 7); + + boolean sparse = getOutputType(bintype); + int testType = getTestType(bintype); + + //get vector primitive via reflection + String meName = "vect"+StringUtils.camelize(bintype.name().split("_")[1])+"Write"; + final Method me ; + if( type1==InputType.VECTOR_SPARSE && type2==InputType.SCALAR ) + me = LibSpoofPrimitives.class.getMethod(meName, new Class[]{int.class, double[].class, double.class, int[].class, int.class, int.class}); + else if( type1==InputType.SCALAR && type2==InputType.VECTOR_SPARSE ) + me = LibSpoofPrimitives.class.getMethod(meName, new Class[]{int.class, double.class, double[].class, int[].class, int.class, int.class}); + else //if( type1==InputType.VECTOR_SPARSE && type2==InputType.VECTOR_SPARSE ) + me = LibSpoofPrimitives.class.getMethod(meName, new Class[]{int.class, double[].class, double[].class, int[].class, int[].class, int.class, int.class, int.class, int.class}); + + for( int i=0; i<m; i++ ) { + //execute vector primitive via reflection + double[] ret1 = new double[n]; + SparseRowVector retX = null; + if( type1==InputType.VECTOR_SPARSE && type2==InputType.SCALAR ) + if(testType >= 0 && i == m-1) { + if(testType == 0) { + retX = (SparseRowVector) me.invoke(null, n, inA.getSparseBlock().values(i), 0, inA.getSparseBlock().indexes(i), + inA.getSparseBlock().pos(i), inA.getSparseBlock().size(i)); + } else { + retX = (SparseRowVector) me.invoke(null, n, inA.getSparseBlock().values(i), inB.min(), inA.getSparseBlock().indexes(i), + inA.getSparseBlock().pos(i), inA.getSparseBlock().size(i)); + } + } else { + retX = (SparseRowVector) me.invoke(null, n, inA.getSparseBlock().values(i), inB.max(), inA.getSparseBlock().indexes(i), + inA.getSparseBlock().pos(i), inA.getSparseBlock().size(i)); + } + else if( type1==InputType.SCALAR && type2==InputType.VECTOR_SPARSE ) + if(testType >= 0 && i == m-1) { + if(testType == 0) { + retX = (SparseRowVector) me.invoke(null, n, 0, inB.getSparseBlock().values(i), + inB.getSparseBlock().indexes(i), inB.getSparseBlock().pos(i), inB.getSparseBlock().size(i)); + } else { + retX = (SparseRowVector) me.invoke(null, n, inA.min(), inB.getSparseBlock().values(i), + inB.getSparseBlock().indexes(i), inB.getSparseBlock().pos(i), inB.getSparseBlock().size(i)); + } + } else { + retX = (SparseRowVector) me.invoke(null, n, inA.max(), inB.getSparseBlock().values(i), + inB.getSparseBlock().indexes(i), inB.getSparseBlock().pos(i), inB.getSparseBlock().size(i)); + } + else if( type1==InputType.VECTOR_SPARSE && type2==InputType.VECTOR_SPARSE ) + if(sparse) + retX = (SparseRowVector) me.invoke(null, n, inA.getSparseBlock().values(i), inB.getSparseBlock().values(i), + inA.getSparseBlock().indexes(i), inB.getSparseBlock().indexes(i), inA.getSparseBlock().pos(i), inB.getSparseBlock().pos(i), inA.getSparseBlock().size(i), inB.getSparseBlock().size(i)); + else + ret1 = (double[]) me.invoke(null, n, inA.getSparseBlock().values(i), inB.getSparseBlock().values(i), + inA.getSparseBlock().indexes(i), inB.getSparseBlock().indexes(i), inA.getSparseBlock().pos(i), inB.getSparseBlock().pos(i), inA.getSparseBlock().size(i), inB.getSparseBlock().size(i)); + + if(sparse) { + int[] indexes = retX.indexes(); + for (int j = 0; j < retX.size(); j++) { + ret1[indexes[j]] = retX.get(indexes[j]); + } + } + + //execute comparison operation + String opcode = OpOp2.valueOf(bintype.name().split("_")[1]).toString(); + MatrixBlock in1 = inA.slice(i, i, 0, n-1, new MatrixBlock()); + MatrixBlock in2 = inB.slice(i, i, 0, n-1, new MatrixBlock()); + double[] ret2 = null; + if( type1 == InputType.SCALAR ) { + ScalarOperator bop = InstructionUtils.parseScalarBinaryOperator(opcode, true); + bop = bop.setConstant(testType >= 0 && i == m-1 ? testType == 0 ? 0 : inA.min() : inA.max()); + ret2 = DataConverter.convertToDoubleVector( + in2.scalarOperations(bop, new MatrixBlock()), false); + } + else if( type2 == InputType.SCALAR ) { + ScalarOperator bop = InstructionUtils.parseScalarBinaryOperator(opcode, false); + bop = bop.setConstant(testType >= 0 && i == m-1 ? testType == 0 ? 0 : inB.min() : inB.max()); + ret2 = DataConverter.convertToDoubleVector( + in1.scalarOperations(bop, new MatrixBlock()), false); + } + else { //vector-vector + BinaryOperator bop = InstructionUtils.parseBinaryOperator(opcode); + ret2 = DataConverter.convertToDoubleVector( + in1.binaryOperations(bop, in2, new MatrixBlock()), false); + } + + //compare results + TestUtils.compareMatrices(ret2, ret1, eps); + } + } + catch( Exception ex ) { + throw new RuntimeException(ex); + } + } + + + /** + * @param type + * @return {@code true}, when the matching method has a sparse return + */ + private static boolean getOutputType(BinType type) { + switch(type) { + case VECT_EQUAL: + case VECT_LESSEQUAL: + case VECT_GREATEREQUAL: + return false; + default: + return true; + } + } + + /** + * @param type + * @return returns {@code -1}, for normal testing;<br> + * returns {@code 0}, for testing with 0 and non-zeros;<br> + * returns {@code 1}, for testing with negative and positive numbers; + */ + private static int getTestType(BinType type) { + switch(type) { + case VECT_DIV_SCALAR: + case VECT_EQUAL_SCALAR: + case VECT_NOTEQUAL_SCALAR: + case VECT_XOR_SCALAR: + // case VECT_POW_SCALAR: + return 0; + case VECT_GREATER_SCALAR: + case VECT_GREATEREQUAL_SCALAR: + case VECT_LESS_SCALAR: + case VECT_LESSEQUAL_SCALAR: + case VECT_MIN_SCALAR: + case VECT_MAX_SCALAR: + return 1; + default: + return -1; + } + } } diff --git a/src/test/java/org/apache/sysds/test/component/codegen/SparseVectorAllocTest.java b/src/test/java/org/apache/sysds/test/component/codegen/SparseVectorAllocTest.java new file mode 100644 index 0000000000..e777e4ef6d --- /dev/null +++ b/src/test/java/org/apache/sysds/test/component/codegen/SparseVectorAllocTest.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sysds.test.component.codegen; + +import org.apache.sysds.runtime.codegen.LibSpoofPrimitives; +import org.apache.sysds.runtime.data.SparseRowVector; +import org.apache.sysds.test.AutomatedTestBase; +import org.apache.sysds.test.TestUtils; +import org.junit.Assert; +import org.junit.Test; + +/** + * This is the component test for the ring buffer used in LibSpoofPrimitives.java, + * that allocates a vector with a certain size. + * Every allocation method is tested to achieve the needed coverage. + */ +public class SparseVectorAllocTest extends AutomatedTestBase +{ + double[] val1 = new double[]{1.5, 5.7, 9.1, 3.7, 5.3}; + double[] val2 = new double[]{9.6, 7.1, 2.7}; + int[] indexes1 = new int[]{3, 7, 14, 20, 81}; + int[] indexes2 = new int[]{20, 30, 90}; + + @Override + public void setUp() { + TestUtils.clearAssertionInformation(); + } + + @Test + public void testBasicAllocationSameLen() { + testBasicSparseVectorAllocation(1, 10, 10); + } + + @Test + public void testBasicAllocationLongerExp() { + testBasicSparseVectorAllocation(1, 10, 15); + } + + @Test + public void testBasicAllocationShorterExp() { + testBasicSparseVectorAllocation(1, 10, 7); + } + + @Test + public void testVectorReuse1() { + testBufferReuse(3, 10, 5, 5); + } + + @Test + public void testVectorReuse2() { + testBufferReuse(3, 10, -1, 5); + } + + /** tests the allocation of an empty vector + * @param numVectors number of vectors that should be pre-allocated + * @param len the length of the vector + * @param expLen the expected length of the allocated vector + */ + public void testBasicSparseVectorAllocation(int numVectors, int len, int expLen) { + //test the basic allocation of an empty vector + LibSpoofPrimitives.setupSparseThreadLocalMemory(numVectors, len, -1); + SparseRowVector sparseVec = LibSpoofPrimitives.allocSparseVector(expLen); + + Assert.assertTrue("Vector capacity should be initialized correctly", expLen <= sparseVec.capacity()); + Assert.assertEquals("Vector size should be initialized with 0", 0, sparseVec.size()); + + LibSpoofPrimitives.cleanupSparseThreadLocalMemory(); + } + + /** tests the allocation of a vector that is reused multiple times + * @param numVectors number of vectors that should be pre-allocated + * @param len1 length of the first vector + * @param len2 length of the second vector + * @param expLen expected length of allocated vector + */ + public void testBufferReuse(int numVectors, int len1, int len2, int expLen) { + //test the reuse of the vectors in the ring buffer + LibSpoofPrimitives.setupSparseThreadLocalMemory(numVectors, len1, len2); + + //allocate first vector + SparseRowVector vec1 = LibSpoofPrimitives.allocSparseVector(expLen); + vec1.set(0, 1.0); + vec1.set(2, 2.0); + + //allocate second vector + SparseRowVector vec2 = LibSpoofPrimitives.allocSparseVector(expLen); + + Assert.assertEquals("Reused vector should be reset to size 0", 0, vec2.size()); + + for(int j = 0; j < vec2.size(); j++) { + vec2.set(vec2.indexes()[j], vec2.get(vec2.indexes()[j]) * 32); + } + + SparseRowVector vec3 = LibSpoofPrimitives.allocSparseVector(expLen); + + Assert.assertEquals("Reused vector should be reset to size 0", 0, vec3.size()); + + SparseRowVector vec4 = LibSpoofPrimitives.allocSparseVector(expLen); + + for(int j = 0; j < vec4.size(); j++) { + vec4.set(vec4.indexes()[j], vec4.get(vec3.indexes()[j]) * 32); + } + + Assert.assertEquals("Reused vector should be reset to size 0", 0, vec4.size()); + + SparseRowVector vec5 = LibSpoofPrimitives.allocSparseVector(expLen); + + for(int j = 0; j < vec5.size(); j++) { + vec2.set(vec5.indexes()[j], vec5.get(vec5.indexes()[j]) * 32); + } + + Assert.assertEquals("Reused vector should be reset to size 0", 0, vec5.size()); + + LibSpoofPrimitives.cleanupSparseThreadLocalMemory(); + } +} diff --git a/src/test/java/org/apache/sysds/test/functions/codegen/RowAggTmplTest.java b/src/test/java/org/apache/sysds/test/functions/codegen/RowAggTmplTest.java index 73dbace862..03fcb40bef 100644 --- a/src/test/java/org/apache/sysds/test/functions/codegen/RowAggTmplTest.java +++ b/src/test/java/org/apache/sysds/test/functions/codegen/RowAggTmplTest.java @@ -89,6 +89,8 @@ public class RowAggTmplTest extends AutomatedTestBase private static final String TEST_NAME46 = TEST_NAME+"46"; //conv2d(X - mean(X), F1) + conv2d(X - mean(X), F2); private static final String TEST_NAME47 = TEST_NAME+"47"; //sum(X + rowVars(X)) private static final String TEST_NAME48 = TEST_NAME+"48"; //sum(rowVars(X)) + private static final String TEST_NAME49 = TEST_NAME+"49"; //X*rowSums(K*v)*X + private static final String TEST_NAME50 = TEST_NAME+"50"; //(abs(A)*B)+(B*v) private static final String TEST_DIR = "functions/codegen/"; private static final String TEST_CLASS_DIR = TEST_DIR + RowAggTmplTest.class.getSimpleName() + "/"; @@ -100,7 +102,7 @@ public class RowAggTmplTest extends AutomatedTestBase @Override public void setUp() { TestUtils.clearAssertionInformation(); - for(int i=1; i<=48; i++) + for(int i=1; i<=50; i++) addTestConfiguration( TEST_NAME+i, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME+i, new String[] { String.valueOf(i) }) ); } @@ -829,6 +831,12 @@ public class RowAggTmplTest extends AutomatedTestBase testCodegenIntegration( TEST_NAME48, false, ExecType.SPARK ); } + @Test + public void testCodegenRowAgg49CP() {testCodegenIntegration( TEST_NAME49, false, ExecType.CP );} + + @Test + public void testCodegenRowAgg50CP() {testCodegenIntegration( TEST_NAME50, false, ExecType.CP );} + private void testCodegenIntegration( String testname, boolean rewrites, ExecType instType ) { boolean oldFlag = OptimizerUtils.ALLOW_ALGEBRAIC_SIMPLIFICATION; @@ -841,7 +849,7 @@ public class RowAggTmplTest extends AutomatedTestBase String HOME = SCRIPT_DIR + TEST_DIR; fullDMLScriptName = HOME + testname + ".dml"; - programArgs = new String[]{"-explain", "codegen", "-stats", "-args", output("S") }; + programArgs = new String[]{"-explain", "codegen", "-sparseIntermediate", "-stats", "-args", output("S") }; fullRScriptName = HOME + testname + ".R"; rCmd = getRCmd(inputDir(), expectedDir()); diff --git a/src/test/scripts/functions/codegen/rowAggPattern49.R b/src/test/scripts/functions/codegen/rowAggPattern49.R new file mode 100644 index 0000000000..06d5c63144 --- /dev/null +++ b/src/test/scripts/functions/codegen/rowAggPattern49.R @@ -0,0 +1,54 @@ +#------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +#------------------------------------------------------------- + +args<-commandArgs(TRUE) +options(digits=22) +library("Matrix") +# library("matrixStats") + +W = matrix(seq(28,29), 1, 2) +J = matrix(0, 1, 8) +Z = cbind(J, W, J) +Y = matrix(0, 10, 18) +X = rbind(Z, Y, Y, Y, Y, Y, Y, Y, Y) +v = seq(1,81) +v1 = seq(20, 37) +W = matrix(seq(13,14), 1, 2) +J = matrix(0, 1, 8) +Z= cbind(J, W, J) +Y = matrix(0, 10, 18) +K = rbind(Z, Y, Y, Y, Y, Y, Y, Y, Y) + +# S = (X < rowSums(X*K)) +# S = X*rowMins(K)*X +S = X*rowSums(K*v)*X +# S = (X*v)/rowSums(X*v) +# S = abs((X*v)/rowSums(X*v)) +# S = (X/v)+rowMeans(X-v) +# S = (X*v)+rowSums(X*v) +# S = (X*rowSums(X*v))/(X*v) + +# S = X*rowSums(X*K) +# S = rowSums((X*v)/K)*v +# S = (K*v)/(rowSums(X*v)) + + +writeMM(as(S, "CsparseMatrix"), paste(args[2], "S", sep="")); diff --git a/src/test/scripts/functions/codegen/rowAggPattern49.dml b/src/test/scripts/functions/codegen/rowAggPattern49.dml new file mode 100644 index 0000000000..8c0d1db225 --- /dev/null +++ b/src/test/scripts/functions/codegen/rowAggPattern49.dml @@ -0,0 +1,52 @@ +#------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +#------------------------------------------------------------- + +W = matrix(seq(28,29), 1, 2) +J = matrix(0, 1, 8) +Z= cbind(J, W, J) +Y = matrix(0, 10, 18) +X = rbind(Z, Y, Y, Y, Y, Y, Y, Y, Y) +v = seq(1,81) +v1 = seq(20, 37) +W = matrix(seq(13,14), 1, 2) +J = matrix(0, 1, 8) +Z= cbind(J, W, J) +Y = matrix(0, 10, 18) +K = rbind(Z, Y, Y, Y, Y, Y, Y, Y, Y) +while(FALSE) { } + +# B = X < rowSums(X*K) +# S = abs(21) * B +# S = B * rowSums(v) +# S = (X < rowSums(X*K)) +# S = X*(k>1)*X +S = X*rowSums(K*v)*X +# S = (X*v)/rowSums(X*v) +# S = abs((X*v)/rowSums(X*v)) +# S = (X/v)+rowMeans(X-v) +# S = (X*v)+rowSums(X*v) +# S = (X*rowSums(X*v))/(X*v) + +# S = X*rowSums(X*K) +# S = rowSums((X*v)/K)*v +# S = (K*v)/(rowSums(X*v)) + +write(S,$1) diff --git a/src/test/scripts/functions/codegen/rowAggPattern50.R b/src/test/scripts/functions/codegen/rowAggPattern50.R new file mode 100644 index 0000000000..af2c3301a7 --- /dev/null +++ b/src/test/scripts/functions/codegen/rowAggPattern50.R @@ -0,0 +1,43 @@ +#------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +#------------------------------------------------------------- + +args<-commandArgs(TRUE) +options(digits=22) +library("Matrix") +# library("matrixStats") + +W = matrix(seq(28,29), 1, 2) +J = matrix(0, 1, 8) +Z = cbind(J, W, J) +Y = matrix(0, 10, 18) +X = rbind(Z, Y, Y, Y, Y, Y, Y, Y, Y) +v = seq(1,81) +v1 = seq(20, 37) +W = matrix(seq(13,14), 1, 2) +J = matrix(0, 1, 8) +Z= cbind(J, W, J) +Y = matrix(0, 10, 18) +K = rbind(Z, Y, Y, Y, Y, Y, Y, Y, Y) + +S = (abs(X)*K)+rowSums(X*v) + + +writeMM(as(S, "CsparseMatrix"), paste(args[2], "S", sep="")); diff --git a/src/test/scripts/functions/codegen/rowAggPattern50.dml b/src/test/scripts/functions/codegen/rowAggPattern50.dml new file mode 100644 index 0000000000..64efe460f9 --- /dev/null +++ b/src/test/scripts/functions/codegen/rowAggPattern50.dml @@ -0,0 +1,40 @@ +#------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +#------------------------------------------------------------- + +W = matrix(seq(28,29), 1, 2) +J = matrix(0, 1, 8) +Z= cbind(J, W, J) +Y = matrix(0, 10, 18) +X = rbind(Z, Y, Y, Y, Y, Y, Y, Y, Y) +v = seq(1,81) +v1 = seq(20, 37) +W = matrix(seq(13,14), 1, 2) +J = matrix(0, 1, 8) +Z= cbind(J, W, J) +Y = matrix(0, 10, 18) +K = rbind(Z, Y, Y, Y, Y, Y, Y, Y, Y) +while(FALSE) { } + + +S = (abs(X)*K)+rowSums(X*v) + + +write(S,$1)