[SYSTEMML-2430] Codegen support for rowMeans in row templates

This patch adds codegen support for unary aggregate rowMeans to the
codegen row templates. In detail, this includes extended compiler
support for the necessary dense/sparse vector primitives. Furthermore,
this also cleans up some convenience methods for full aggregates on
matrix blocks.


Project: http://git-wip-us.apache.org/repos/asf/systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/d065c3d1
Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/d065c3d1
Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/d065c3d1

Branch: refs/heads/master
Commit: d065c3d13c15f8a8bb4c5e882856e6b0d648675d
Parents: b429551
Author: Matthias Boehm <[email protected]>
Authored: Thu Jul 12 17:11:14 2018 -0700
Committer: Matthias Boehm <[email protected]>
Committed: Thu Jul 12 17:11:14 2018 -0700

----------------------------------------------------------------------
 .../sysml/hops/codegen/SpoofCompiler.java       |  2 +-
 .../sysml/hops/codegen/cplan/CNodeUnary.java    |  6 +-
 .../hops/codegen/template/TemplateRow.java      |  2 +-
 .../runtime/codegen/LibSpoofPrimitives.java     |  8 ++
 .../sysml/runtime/matrix/data/MatrixBlock.java  | 27 ++++--
 .../codegen/CPlanVectorPrimitivesTest.java      | 20 +++-
 .../functions/codegen/RowAggTmplTest.java       | 18 +++-
 .../scripts/functions/codegen/rowAggPattern44.R | 99 ++++++++++++++++++++
 .../functions/codegen/rowAggPattern44.dml       | 35 +++++++
 9 files changed, 199 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/systemml/blob/d065c3d1/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java 
b/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java
index fd012ec..8302eca 100644
--- a/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java
+++ b/src/main/java/org/apache/sysml/hops/codegen/SpoofCompiler.java
@@ -102,7 +102,7 @@ public class SpoofCompiler
        private static final Log LOG = 
LogFactory.getLog(SpoofCompiler.class.getName());
        
        //internal configuration flags
-       public static final boolean LDEBUG                 = false;
+       public static final boolean LDEBUG                 = true;
        public static CompilerType JAVA_COMPILER           = 
CompilerType.JANINO; 
        public static PlanSelector PLAN_SEL_POLICY         = 
PlanSelector.FUSE_COST_BASED_V2; 
        public static final IntegrationType INTEGRATION    = 
IntegrationType.RUNTIME;

http://git-wip-us.apache.org/repos/asf/systemml/blob/d065c3d1/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java 
b/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java
index b269139..ba41fad 100644
--- a/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java
+++ b/src/main/java/org/apache/sysml/hops/codegen/cplan/CNodeUnary.java
@@ -32,7 +32,8 @@ public class CNodeUnary extends CNode
 {
        public enum UnaryType {
                LOOKUP_R, LOOKUP_C, LOOKUP_RC, LOOKUP0, //codegen specific
-               ROW_SUMS, ROW_SUMSQS, ROW_MINS, ROW_MAXS, ROW_COUNTNNZS, 
//codegen specific
+               ROW_SUMS, ROW_SUMSQS, ROW_COUNTNNZS, //codegen specific
+               ROW_MEANS, ROW_MINS, ROW_MAXS,
                VECT_EXP, VECT_POW2, VECT_MULT2, VECT_SQRT, VECT_LOG,
                VECT_ABS, VECT_ROUND, VECT_CEIL, VECT_FLOOR, VECT_SIGN, 
                VECT_SIN, VECT_COS, VECT_TAN, VECT_ASIN, VECT_ACOS, VECT_ATAN, 
@@ -54,6 +55,7 @@ public class CNodeUnary extends CNode
                                case ROW_SUMSQS:
                                case ROW_MINS:
                                case ROW_MAXS:
+                               case ROW_MEANS:
                                case ROW_COUNTNNZS: {
                                        String vectName = 
StringUtils.capitalize(name().substring(4, name().length()-1).toLowerCase());
                                        return sparse ? "    double %TMP% = 
LibSpoofPrimitives.vect"+vectName+"(%IN1v%, %IN1i%, %POS1%, alen, len);\n": 
@@ -249,6 +251,7 @@ public class CNodeUnary extends CNode
                        case ROW_SUMSQS: return "u(Rsq+)";
                        case ROW_MINS:   return "u(Rmin)";
                        case ROW_MAXS:   return "u(Rmax)";
+                       case ROW_MEANS:  return "u(Rmean)";
                        case ROW_COUNTNNZS: return "u(Rnnz)";
                        case VECT_EXP:
                        case VECT_POW2:
@@ -319,6 +322,7 @@ public class CNodeUnary extends CNode
                        case ROW_SUMSQS:
                        case ROW_MINS:
                        case ROW_MAXS:
+                       case ROW_MEANS:
                        case ROW_COUNTNNZS:
                        case EXP:
                        case LOOKUP_R:

http://git-wip-us.apache.org/repos/asf/systemml/blob/d065c3d1/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java 
b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java
index 15bec59..9df67d0 100644
--- a/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java
+++ b/src/main/java/org/apache/sysml/hops/codegen/template/TemplateRow.java
@@ -67,7 +67,7 @@ import org.apache.sysml.runtime.matrix.data.Pair;
 
 public class TemplateRow extends TemplateBase 
 {
-       private static final Hop.AggOp[] SUPPORTED_ROW_AGG = new 
AggOp[]{AggOp.SUM, AggOp.MIN, AggOp.MAX};
+       private static final Hop.AggOp[] SUPPORTED_ROW_AGG = new 
AggOp[]{AggOp.SUM, AggOp.MIN, AggOp.MAX, AggOp.MEAN};
        private static final Hop.OpOp1[] SUPPORTED_VECT_UNARY = new OpOp1[]{
                        OpOp1.EXP, OpOp1.SQRT, OpOp1.LOG, OpOp1.ABS, 
OpOp1.ROUND, OpOp1.CEIL, OpOp1.FLOOR, OpOp1.SIGN,
                        OpOp1.SIN, OpOp1.COS, OpOp1.TAN, OpOp1.ASIN, 
OpOp1.ACOS, OpOp1.ATAN, OpOp1.SINH, OpOp1.COSH, OpOp1.TANH,

http://git-wip-us.apache.org/repos/asf/systemml/blob/d065c3d1/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java 
b/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java
index 42d61d3..fc0c1d2 100644
--- a/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java
+++ b/src/main/java/org/apache/sysml/runtime/codegen/LibSpoofPrimitives.java
@@ -340,6 +340,14 @@ public class LibSpoofPrimitives
                return alen;
        }
        
+       public static double vectMean(double[] a, int ai, int len) {
+               return vectSum(a, ai, len) / len;
+       } 
+       
+       public static double vectMean(double[] avals, int[] aix, int ai, int 
alen, int len) {
+               return vectSum(avals, aix, ai, alen, len) / len;
+       }
+       
        //custom vector div
        
        public static void vectDivAdd(double[] a, double bval, double[] c, int 
ai, int ci, int len) {

http://git-wip-us.apache.org/repos/asf/systemml/blob/d065c3d1/src/main/java/org/apache/sysml/runtime/matrix/data/MatrixBlock.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/sysml/runtime/matrix/data/MatrixBlock.java 
b/src/main/java/org/apache/sysml/runtime/matrix/data/MatrixBlock.java
index 4bb0c5c..5c50326 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/MatrixBlock.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/MatrixBlock.java
@@ -64,6 +64,7 @@ import org.apache.sysml.runtime.functionobjects.RevIndex;
 import org.apache.sysml.runtime.functionobjects.SortIndex;
 import org.apache.sysml.runtime.functionobjects.SwapIndex;
 import 
org.apache.sysml.runtime.functionobjects.TernaryValueFunction.ValueFunctionWithConstant;
+import org.apache.sysml.runtime.instructions.InstructionUtils;
 import org.apache.sysml.runtime.instructions.cp.CM_COV_Object;
 import org.apache.sysml.runtime.instructions.cp.KahanObject;
 import org.apache.sysml.runtime.instructions.cp.ScalarObject;
@@ -793,17 +794,26 @@ public class MatrixBlock extends MatrixValue implements 
CacheBlock, Externalizab
        }
        
        /**
+        * Wrapper method for reduceall-mean of a matrix.
+        * 
+        * @return ?
+        */
+       public double mean() {
+               MatrixBlock out = new MatrixBlock(1, 3, false);
+               LibMatrixAgg.aggregateUnaryMatrix(this, out,
+                       
InstructionUtils.parseBasicAggregateUnaryOperator("uamean", 1));
+               return out.quickGetValue(0, 0);
+       }
+       
+       /**
         * Wrapper method for reduceall-min of a matrix.
         * 
         * @return ?
         */
        public double min() {
-               //construct operator
-               AggregateOperator aop = new 
AggregateOperator(Double.POSITIVE_INFINITY, Builtin.getBuiltinFnObject("min"));
-               AggregateUnaryOperator auop = new AggregateUnaryOperator( aop, 
ReduceAll.getReduceAllFnObject());
-               //execute operation
                MatrixBlock out = new MatrixBlock(1, 1, false);
-               LibMatrixAgg.aggregateUnaryMatrix(this, out, auop);
+               LibMatrixAgg.aggregateUnaryMatrix(this, out,
+                       
InstructionUtils.parseBasicAggregateUnaryOperator("uamin", 1));
                return out.quickGetValue(0, 0);
        }
        
@@ -813,12 +823,9 @@ public class MatrixBlock extends MatrixValue implements 
CacheBlock, Externalizab
         * @return ?
         */
        public double max() {
-               //construct operator
-               AggregateOperator aop = new 
AggregateOperator(Double.NEGATIVE_INFINITY, Builtin.getBuiltinFnObject("max"));
-               AggregateUnaryOperator auop = new AggregateUnaryOperator( aop, 
ReduceAll.getReduceAllFnObject());
-               //execute operation
                MatrixBlock out = new MatrixBlock(1, 1, false);
-               LibMatrixAgg.aggregateUnaryMatrix(this, out, auop);
+               LibMatrixAgg.aggregateUnaryMatrix(this, out,
+                       
InstructionUtils.parseBasicAggregateUnaryOperator("uamax", 1));
                return out.quickGetValue(0, 0);
        }
        

http://git-wip-us.apache.org/repos/asf/systemml/blob/d065c3d1/src/test/java/org/apache/sysml/test/integration/functions/codegen/CPlanVectorPrimitivesTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/sysml/test/integration/functions/codegen/CPlanVectorPrimitivesTest.java
 
b/src/test/java/org/apache/sysml/test/integration/functions/codegen/CPlanVectorPrimitivesTest.java
index 23dd6fb..562005e 100644
--- 
a/src/test/java/org/apache/sysml/test/integration/functions/codegen/CPlanVectorPrimitivesTest.java
+++ 
b/src/test/java/org/apache/sysml/test/integration/functions/codegen/CPlanVectorPrimitivesTest.java
@@ -89,6 +89,16 @@ public class CPlanVectorPrimitivesTest extends 
AutomatedTestBase
                testVectorAggPrimitive(UnaryType.ROW_MAXS, 
InputType.VECTOR_SPARSE);
        }
        
+       @Test
+       public void testVectorMeansDense() {
+               testVectorAggPrimitive(UnaryType.ROW_MEANS, 
InputType.VECTOR_DENSE);
+       }
+       
+       @Test
+       public void testVectorMeansSparse() {
+               testVectorAggPrimitive(UnaryType.ROW_MEANS, 
InputType.VECTOR_SPARSE);
+       }
+       
        //support unary vector primitives (pow2/mult2 current excluded because 
not unary)
        
        @Test
@@ -716,7 +726,8 @@ public class CPlanVectorPrimitivesTest extends 
AutomatedTestBase
                        MatrixBlock in = MatrixBlock.randOperations(m, n, 
sparsity, -1, 1, "uniform", 7);
                        
                        //get vector primitive via reflection
-                       String meName = 
"vect"+StringUtils.camelize(aggtype.name().split("_")[1].substring(0, 3));
+                       String tmp = 
StringUtils.camelize(aggtype.name().split("_")[1]);
+                       String meName = "vect"+tmp.substring(0, tmp.length()-1);
                        Method me = (type1 == InputType.VECTOR_DENSE) ? 
                                LibSpoofPrimitives.class.getMethod(meName, new 
Class[]{double[].class, int.class, int.class}) : 
                                LibSpoofPrimitives.class.getMethod(meName, new 
Class[]{double[].class, int[].class, int.class, int.class, int.class});
@@ -732,9 +743,10 @@ public class CPlanVectorPrimitivesTest extends 
AutomatedTestBase
                                MatrixBlock in2 = in.slice(i, i, 0, n-1, new 
MatrixBlock());
                                Double ret2 = -1d;
                                switch( aggtype ) {
-                                       case ROW_SUMS: ret2 = in2.sum(); break;
-                                       case ROW_MAXS: ret2 = in2.max(); break;
-                                       case ROW_MINS: ret2 = in2.min(); break; 
+                                       case ROW_SUMS:  ret2 = in2.sum(); break;
+                                       case ROW_MAXS:  ret2 = in2.max(); break;
+                                       case ROW_MINS:  ret2 = in2.min(); break;
+                                       case ROW_MEANS: ret2 = in2.mean(); 
break;
                                }
                                
                                //compare results

http://git-wip-us.apache.org/repos/asf/systemml/blob/d065c3d1/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java
 
b/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java
index bec9be2..04891d0 100644
--- 
a/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java
+++ 
b/src/test/java/org/apache/sysml/test/integration/functions/codegen/RowAggTmplTest.java
@@ -80,6 +80,7 @@ public class RowAggTmplTest extends AutomatedTestBase
        private static final String TEST_NAME41 = TEST_NAME+"41"; 
//X*rowSums(X/seq(1,N)+t(seq(M,1)))
        private static final String TEST_NAME42 = TEST_NAME+"42"; 
//X/rowSums(min(X, Y, Z))
        private static final String TEST_NAME43 = TEST_NAME+"43"; 
//bias_add(X,B) + bias_mult(X,B)
+       private static final String TEST_NAME44 = TEST_NAME+"44"; //maxpool(X - 
mean(X));
        
        private static final String TEST_DIR = "functions/codegen/";
        private static final String TEST_CLASS_DIR = TEST_DIR + 
RowAggTmplTest.class.getSimpleName() + "/";
@@ -91,7 +92,7 @@ public class RowAggTmplTest extends AutomatedTestBase
        @Override
        public void setUp() {
                TestUtils.clearAssertionInformation();
-               for(int i=1; i<=43; i++)
+               for(int i=1; i<=44; i++)
                        addTestConfiguration( TEST_NAME+i, new 
TestConfiguration(TEST_CLASS_DIR, TEST_NAME+i, new String[] { String.valueOf(i) 
}) );
        }
        
@@ -739,6 +740,21 @@ public class RowAggTmplTest extends AutomatedTestBase
        public void testCodegenRowAgg43SP() {
                testCodegenIntegration( TEST_NAME43, false, ExecType.SPARK );
        }
+       
+       @Test
+       public void testCodegenRowAggRewrite44CP() {
+               testCodegenIntegration( TEST_NAME44, true, ExecType.CP );
+       }
+
+       @Test
+       public void testCodegenRowAgg44CP() {
+               testCodegenIntegration( TEST_NAME44, false, ExecType.CP );
+       }
+
+       @Test
+       public void testCodegenRowAgg44SP() {
+               testCodegenIntegration( TEST_NAME44, false, ExecType.SPARK );
+       }
 
        private void testCodegenIntegration( String testname, boolean rewrites, 
ExecType instType )
        {

http://git-wip-us.apache.org/repos/asf/systemml/blob/d065c3d1/src/test/scripts/functions/codegen/rowAggPattern44.R
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/codegen/rowAggPattern44.R 
b/src/test/scripts/functions/codegen/rowAggPattern44.R
new file mode 100644
index 0000000..99ba0b0
--- /dev/null
+++ b/src/test/scripts/functions/codegen/rowAggPattern44.R
@@ -0,0 +1,99 @@
+#-------------------------------------------------------------
+#
+# 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)
+library("Matrix")
+library("matrixStats") 
+
+imgSize=8
+numImg=16
+numChannels=4
+poolSize1=imgSize*imgSize
+poolSize2=1
+stride=1
+pad=0
+
+X = matrix(seq(1, numImg*numChannels*imgSize*imgSize), numImg, 
numChannels*imgSize*imgSize, byrow=TRUE)
+X = X - rowMeans(X)
+
+pad_image <- function(img, Hin, Win, padh, padw){
+  C = nrow(img)
+  img_padded = matrix(0, C, (Hin+2*padh)*(Win+2*padw))  # zeros
+  for (c in 1:C) {
+    img_slice = matrix(img[c,], Hin, Win, byrow=TRUE)  # depth slice C reshaped
+    img_padded_slice = matrix(0, Hin+2*padh, Win+2*padw)
+    img_padded_slice[(padh+1):(padh+Hin), (padw+1):(padw+Win)] = img_slice
+    img_padded[c,] = matrix(t(img_padded_slice), 1, (Hin+2*padh)*(Win+2*padw)) 
 # reshape
+  }
+  img_padded
+}
+
+im2col <- function(img, Hin, Win, Hf, Wf, strideh, stridew) {
+  C = nrow(img)
+  Hout = as.integer((Hin - Hf) / strideh + 1)
+  Wout = as.integer((Win - Wf) / stridew + 1)
+
+  img_cols = matrix(0, C*Hf*Wf, Hout*Wout, byrow=TRUE)  # zeros
+  for (hout in 1:Hout) {  # all output rows
+    hin = (hout-1) * strideh + 1
+    for (wout in 1:Wout) {  # all output columns
+      win = (wout-1) * stridew + 1
+      # Extract a local patch of the input image corresponding spatially to 
the filter sizes.
+      img_patch = matrix(0, C, Hf*Wf, byrow=TRUE)  # zeros
+      for (c in 1:C) {  # all channels
+        img_slice = matrix(img[c,], Hin, Win, byrow=TRUE)  # reshape
+        img_patch[c,] = matrix(t(img_slice[hin:(hin+Hf-1), win:(win+Wf-1)]), 
1, Hf*Wf)
+      }
+      img_cols[,(hout-1)*Wout + wout] = matrix(t(img_patch), C*Hf*Wf, 1)  # 
reshape
+    }
+  }
+  img_cols
+}
+
+max_pool <- function(X, N, C, Hin, Win, Hf, Wf,
+                   strideh, stridew) {
+  Hout = as.integer((Hin - Hf) / strideh + 1)
+  Wout = as.integer((Win - Wf) / stridew + 1)
+
+  # Create output volume
+  out = matrix(0, N, C*Hout*Wout, byrow=TRUE)
+
+  # Max pooling - im2col implementation
+  for (n in 1:N) {  # all examples
+    img = matrix(X[n,], C, Hin*Win, byrow=TRUE)  # reshape
+    img_maxes = matrix(0, C, Hout*Wout, byrow=TRUE)  # zeros
+
+    for (c in 1:C) {  # all channels
+      # Extract local image slice patches into columns with im2col, of shape 
(Hf*Wf, Hout*Wout)
+      img_slice_cols = im2col(matrix(t(img[c,]), 1, Hin*Win) , Hin, Win, Hf, 
Wf, strideh, stridew)
+
+      # Max pooling on patches
+      img_maxes[c,] = colMaxs(img_slice_cols)
+    }
+
+    out[n,] = matrix(t(img_maxes), 1, C*Hout*Wout)
+  }
+  
+  out
+}
+
+R = max_pool(X, numImg, numChannels, imgSize*imgSize, 1, poolSize1, poolSize2, 
stride, stride)
+
+writeMM(as(R,"CsparseMatrix"), paste(args[2], "S", sep=""))

http://git-wip-us.apache.org/repos/asf/systemml/blob/d065c3d1/src/test/scripts/functions/codegen/rowAggPattern44.dml
----------------------------------------------------------------------
diff --git a/src/test/scripts/functions/codegen/rowAggPattern44.dml 
b/src/test/scripts/functions/codegen/rowAggPattern44.dml
new file mode 100644
index 0000000..f236451
--- /dev/null
+++ b/src/test/scripts/functions/codegen/rowAggPattern44.dml
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------
+#
+# 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.
+# 
+#-------------------------------------------------------------
+imgSize=8
+numImg=16
+numChannels=4
+poolSize1=imgSize*imgSize
+poolSize2=1
+stride=1
+pad=0
+
+X = matrix(seq(1, numImg*numChannels*imgSize*imgSize), rows=numImg, 
cols=numChannels*imgSize*imgSize);
+while(FALSE){}
+
+X = X - rowMeans(X);
+R = max_pool(X, stride=[stride, stride], padding=[pad, pad], 
input_shape=[numImg, numChannels, imgSize*imgSize, 1], pool_size=[poolSize1, 
poolSize2]);
+
+write(R, $1, format="text");

Reply via email to