diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..35eb1ddfb
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/naive.boa b/examples/naive.boa
new file mode 100644
index 000000000..53d78f143
--- /dev/null
+++ b/examples/naive.boa
@@ -0,0 +1,172 @@
+p: Project = input;
+type fv = {a:int, b:int, c:int, d:int};
+type stats = {a_stat:float, b_stat:float, c_stat:float};
+type complete_stat = {avg: stats, dev: stats};
+type Data = {training: fv, testing: fv};
+splitRatio : float = 0.67;
+
+naive := function(vals : array of Data) : float {
+ train : array of fv;
+ test : array of fv;
+
+ spearated: map[int] of array of fv; # classified per value
+ summaries : map[int] of complete_stat;
+
+ # separate the training and testing datasets
+ foreach(i:int; def(vals[i])) {
+ if(def(train)) {
+ train = train + {vals[i].training};
+ } else {
+ train = {vals[i].training};
+ }
+ if(def(test)) {
+ test = test+ {vals[i].testing};
+ } else {
+ test = {vals[i].testing};
+ }
+
+ }
+
+
+ # classify training datasets
+ foreach(i:int; def(train[i])) {
+ temp : array of fv = {train[i]};
+ if(!haskey(spearated, train[i].d)) {
+ spearated[train[i].d] = temp;
+ } else {
+ spearated[train[i].d] = spearated[train[i].d] + temp;
+ }
+ }
+
+ # all the classes
+ classes : array of int = keys(spearated);
+
+ # summarize data from training dataset
+ foreach(i:int; def(classes[i])) {
+ # calculate mean
+ feature_mean : stats = {0.0, 0.0, 0.0};
+ foreach(j:int; def(spearated[classes[i]][j])) {
+ feature_mean.a_stat = feature_mean.a_stat + spearated[classes[i]][j].a;
+ feature_mean.b_stat = feature_mean.b_stat + spearated[classes[i]][j].b;
+ feature_mean.c_stat = feature_mean.c_stat + spearated[classes[i]][j].c;
+ }
+ feature_mean.a_stat = feature_mean.a_stat / len(spearated[classes[i]]);
+ feature_mean.b_stat = feature_mean.b_stat / len(spearated[classes[i]]);
+ feature_mean.c_stat = feature_mean.c_stat / len(spearated[classes[i]]);
+
+
+ # calculate sd
+ feature_sd : stats = {0.0, 0.0, 0.0};
+ foreach(j:int; def(spearated[classes[i]][j])) {
+ feature_sd.a_stat = feature_sd.a_stat + (spearated[classes[i]][j].a - feature_mean.a_stat);
+ feature_sd.b_stat = feature_sd.b_stat + (spearated[classes[i]][j].b - feature_mean.b_stat);
+ feature_sd.c_stat = feature_sd.c_stat + (spearated[classes[i]][j].c - feature_mean.c_stat);
+ }
+ feature_sd.a_stat = sqrt(feature_sd.a_stat / len(spearated[classes[i]]));
+ feature_sd.b_stat = sqrt(feature_sd.b_stat / len(spearated[classes[i]]));
+ feature_sd.c_stat = sqrt(feature_sd.c_stat / len(spearated[classes[i]]));
+
+ # summarized a class
+ summaries[classes[i]] = {feature_mean, feature_sd};
+ }
+
+
+ predictions: array of int;
+ predictions = new(predictions, len(test), -1);
+
+ # predict for each test data
+ foreach(i:int; def(test[i])) {
+ probabilities : map[int] of float;
+ foreach(j: int; def(classes[j])) {
+ probabilities[classes[j]] = 1.0;
+ mean := summaries[classes[j]].avg;
+ deviation := summaries[classes[j]].dev;
+ probabilities[classes[j]] = probabilities[classes[j]] * (1/ (sqrt(2 * 3.14) * deviation.a_stat)) * (exp(-1 * ((pow((1.0 * test[i].a) - mean.a_stat, 2))/(2 * pow(deviation.a_stat, 2)))));
+ probabilities[classes[j]] = probabilities[classes[j]] * (1/ (sqrt(2 * 3.14) * deviation.a_stat)) * (exp(-1 * ((pow((1.0 * test[i].b) - mean.b_stat, 2))/(2 * pow(deviation.b_stat, 2)))));
+ probabilities[classes[j]] = probabilities[classes[j]] * (1/ (sqrt(2 * 3.14) * deviation.a_stat)) * (exp(-1 * ((pow((1.0 * test[i].c) - mean.c_stat, 2))/(2 * pow(deviation.c_stat, 2)))));
+ }
+
+ bestProb : float = 0;
+ bestLab : int = -1;
+ foreach(j: int; def(classes[j])) {
+ if ((bestLab == -1) || (bestProb < probabilities[classes[j]])) {
+ bestProb = probabilities[classes[j]];
+ bestLab = classes[j];
+ }
+ }
+ predictions[i] = bestLab;
+ }
+
+ correct : float = 0.0;
+ foreach(i:int; def(test[i])) {
+ if(predictions[i] == test[i].d) {
+ correct = correct + 1.0;
+ }
+ }
+ return correct/len(test) * 100;
+};
+
+scale := function(ast: int, method: int, class: int) : int {
+ total : int = 0;
+ if(ast > 1000) {
+ total++;
+ } if(method > 500) {
+ total++;
+ } if(class > 50) {
+ total++;
+ }
+ return total;
+};
+
+
+naive_bayes : output naive of Data;
+
+# count ast nodes
+
+astCount := 0;
+classCount := 0;
+methodCount := 0;
+visit(p, visitor {
+ # only look at the latest snapshot
+ before n: CodeRepository -> {
+ snapshot := getsnapshot(n);
+ foreach (i: int; def(snapshot[i]))
+ visit(snapshot[i]);
+ stop;
+ }
+ before node: Declaration -> {
+ if (node.kind == TypeKind.CLASS) {
+ classCount++;
+ foreach (i: int; node.methods[i]) {
+ methodCount++;
+ }
+ }
+ }
+ # by default, count all visited nodes
+ before _ -> astCount++;
+ # these nodes are not part of the AST, so do nothing when visiting
+ before Project, ChangedFile -> ;
+});
+
+
+
+dummy : fv = {0, 0, 0, 0};
+nondummy : fv = {astCount, methodCount, classCount, scale(astCount, methodCount, classCount)};
+data1: Data = {nondummy, dummy};
+data2: Data = {dummy, nondummy};
+if(rand() > splitRatio)
+ naive_bayes << data1;
+else
+ naive_bayes << data2;
+
+
+if(rand() > splitRatio)
+ naive_bayes << data1;
+else
+ naive_bayes << data2;
+
+
+if(rand() > splitRatio)
+ naive_bayes << data1;
+else
+ naive_bayes << data2;
diff --git a/lib/gson-2.8.0.jar b/lib/gson-2.8.0.jar
new file mode 100644
index 000000000..1235f6381
Binary files /dev/null and b/lib/gson-2.8.0.jar differ
diff --git a/lib/guava-21.0.jar b/lib/guava-21.0.jar
new file mode 100644
index 000000000..061819594
Binary files /dev/null and b/lib/guava-21.0.jar differ
diff --git a/lib/jama-1.0.3.jar b/lib/jama-1.0.3.jar
new file mode 100755
index 000000000..e4013a727
Binary files /dev/null and b/lib/jama-1.0.3.jar differ
diff --git a/src/antlr/Boa.g b/src/antlr/Boa.g
index da1ef4872..f7aa74c50 100644
--- a/src/antlr/Boa.g
+++ b/src/antlr/Boa.g
@@ -179,7 +179,7 @@ outputType returns [OutputType ast]
locals [int l, int c]
@init { $l = getStartLine(); $c = getStartColumn(); }
@after { $ast.setPositions($l, $c, getEndLine(), getEndColumn()); }
- : OUTPUT (tk=SET { $ast = new OutputType(new Identifier($tk.text)); } | id=identifier { $ast = new OutputType($id.ast); }) (LPAREN el=expressionList RPAREN { $ast.setArgs($el.list); })? (LBRACKET m=component RBRACKET { $ast.addIndice($m.ast); })* OF m=component { $ast.setType($m.ast); } (WEIGHT m=component { $ast.setWeight($m.ast); })? (FORMAT LPAREN el=expressionList RPAREN)?
+ : OUTPUT (tk=SET { $ast = new OutputType(new Identifier($tk.text)); } | id=identifier { $ast = new OutputType($id.ast); }) (LPAREN vl=vardeclList RPAREN { $ast.setParams($vl.list); })? (LPAREN el=expressionList RPAREN { $ast.setArgs($el.list); })? (LBRACKET m=component RBRACKET { $ast.addIndice($m.ast); })* OF m=component { $ast.setType($m.ast); } (WEIGHT m=component { $ast.setWeight($m.ast); })? (FORMAT LPAREN el=expressionList RPAREN)?
;
functionType returns [FunctionType ast]
@@ -429,6 +429,20 @@ expressionList returns [ArrayList list]
| e=expression { $list.add($e.ast); } ({ notifyErrorListeners("error: ',' expected"); } e=expression { $list.add($e.ast); } | COMMA e=expression { $list.add($e.ast); })*
;
+
+useraggParamDeclaration returns [VarDeclStatement ast]
+ locals [int l, int c]
+ @init { $l = getStartLine(); $c = getStartColumn(); }
+ @after { $ast.setPositions($l, $c, getEndLine(), getEndColumn()); }
+ : v=forVariableDeclaration { $ast = $v.ast; }
+ ;
+
+vardeclList returns [ArrayList list]
+ @init { $list = new ArrayList(); }
+ : e=useraggParamDeclaration { $list.add($e.ast); } (COMMA e=useraggParamDeclaration { $list.add($e.ast); })*
+ | e=useraggParamDeclaration { $list.add($e.ast); } ({ notifyErrorListeners("error: ',' expected"); } e=useraggParamDeclaration { $list.add($e.ast); } | COMMA e=useraggParamDeclaration { $list.add($e.ast); })*
+ ;
+
conjunction returns [Conjunction ast]
locals [int l, int c]
@init { $l = getStartLine(); $c = getStartColumn(); }
diff --git a/src/java/boa/BoaEnumInterface.java b/src/java/boa/BoaEnumInterface.java
new file mode 100644
index 000000000..f07341a85
--- /dev/null
+++ b/src/java/boa/BoaEnumInterface.java
@@ -0,0 +1,5 @@
+package boa;
+
+public interface BoaEnumInterface {
+ Object getValue();
+}
\ No newline at end of file
diff --git a/src/java/boa/BoaTup.java b/src/java/boa/BoaTup.java
new file mode 100644
index 000000000..0f9b535fe
--- /dev/null
+++ b/src/java/boa/BoaTup.java
@@ -0,0 +1,14 @@
+package boa;
+
+import java.io.IOException;
+import java.util.Collection;
+
+
+public interface BoaTup {
+ public String[] getValues();
+ public byte[] serialize(Object o) throws IOException;
+ public Object getValue(String f);
+ public String toString();
+ public T[] asArray(T[] type);
+ public String[] getFieldNames();
+}
\ No newline at end of file
diff --git a/src/java/boa/aggregators/Aggregator.java b/src/java/boa/aggregators/Aggregator.java
index 6ad1d637b..c0e092b8c 100644
--- a/src/java/boa/aggregators/Aggregator.java
+++ b/src/java/boa/aggregators/Aggregator.java
@@ -18,10 +18,15 @@
import java.io.IOException;
+import boa.BoaTup;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer.Context;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
import boa.functions.BoaCasts;
import boa.io.EmitKey;
import boa.io.EmitValue;
@@ -38,6 +43,29 @@ public abstract class Aggregator {
private Context context;
private EmitKey key;
private boolean combining;
+ private final static Set inBuiltAggs = new HashSet();
+
+ static {
+ inBuiltAggs.add("sum");
+ inBuiltAggs.add("top");
+ inBuiltAggs.add("maximum");
+ inBuiltAggs.add("minimum");
+ inBuiltAggs.add("max");
+ inBuiltAggs.add("min");
+ inBuiltAggs.add("collection");
+ inBuiltAggs.add("mean");
+ inBuiltAggs.add("median");
+ inBuiltAggs.add("stdev");
+ inBuiltAggs.add("quantile");
+ inBuiltAggs.add("kurtosis");
+ inBuiltAggs.add("histogram");
+ inBuiltAggs.add("graphCSV");
+ inBuiltAggs.add("set");
+ inBuiltAggs.add("bottom");
+ inBuiltAggs.add("skewness");
+ inBuiltAggs.add("confidence");
+ inBuiltAggs.add("variance");
+ }
/**
* Construct an Aggregator.
@@ -93,6 +121,13 @@ public void aggregate(final double data) throws IOException, InterruptedExceptio
this.aggregate(BoaCasts.doubleToString(data), null);
}
+ public void aggregate(final BoaTup data, final String metadata) throws IOException, InterruptedException, FinishedException {
+ }
+
+ public void aggregate(final BoaTup data) throws IOException, InterruptedException, FinishedException {
+ this.aggregate(data, null);
+ }
+
@SuppressWarnings("unchecked")
protected void collect(final String data, final String metadata) throws IOException, InterruptedException {
if (this.combining)
@@ -107,6 +142,22 @@ protected void collect(final String data) throws IOException, InterruptedExcepti
this.collect(data, null);
}
+ protected void collect(final BoaTup data) throws IOException, InterruptedException {
+ this.collect(data.toString(), null);
+ }
+
+ protected void collect(final BoaTup[] data) throws IOException, InterruptedException {
+ this.collect(Arrays.toString(data), null);
+ }
+
+ protected void collect(final double[] data) throws IOException, InterruptedException {
+ this.collect(Arrays.toString(data), null);
+ }
+
+ protected void collect(final long[] data) throws IOException, InterruptedException {
+ this.collect(Arrays.toString(data), null);
+ }
+
@SuppressWarnings("unchecked")
protected void collect(final long data, final String metadata) throws IOException, InterruptedException {
this.collect(BoaCasts.longToString(data), metadata);
@@ -157,4 +208,8 @@ public void setKey(final EmitKey key) {
public EmitKey getKey() {
return this.key;
}
+
+ public final static boolean isUserDefinedAggregator(String name) {
+ return !Aggregator.inBuiltAggs.contains(name);
+ }
}
diff --git a/src/java/boa/aggregators/UserDefinedAggregator.java b/src/java/boa/aggregators/UserDefinedAggregator.java
new file mode 100644
index 000000000..240712189
--- /dev/null
+++ b/src/java/boa/aggregators/UserDefinedAggregator.java
@@ -0,0 +1,25 @@
+package boa.aggregators;
+
+
+import boa.compiler.UserDefinedAggregators;
+import boa.datagen.util.FileIO;
+import com.google.gson.Gson;
+
+import java.io.*;
+
+@AggregatorSpec(name = "UserDefinedAgg", formalParameters = { "any", "any" }, type = "UserDefined", canCombine = false)
+public abstract class UserDefinedAggregator extends Aggregator {
+
+ public void store(Object object) {
+ Gson json = new Gson();
+ File output = new File(UserDefinedAggregators.getFileName());
+ final String dest= output.getAbsolutePath() + "/";
+ output.mkdir();
+ writeAsJSON(object, dest + UserDefinedAggregators.getFileName() + ".model");
+ }
+
+ private void writeAsJSON(Object object, String path) {
+ Gson writer = new Gson();
+ FileIO.writeFileContents(new File(path), writer.toJson(object));
+ }
+}
\ No newline at end of file
diff --git a/src/java/boa/compiler/BoaCompiler.java b/src/java/boa/compiler/BoaCompiler.java
index 2140234d0..34a74599d 100644
--- a/src/java/boa/compiler/BoaCompiler.java
+++ b/src/java/boa/compiler/BoaCompiler.java
@@ -155,6 +155,8 @@ public void syntaxError(Recognizer, ?> recognizer, Object offendingSymbol, int
try {
if (!parserErrorListener.hasError) {
+ UserDefinedAggregators.setFileName(f.getName());
+ UserDefinedAggregators.setJobName("Job" + jobName);
new TypeCheckingVisitor().start(p, new SymbolTable());
final TaskClassifyingVisitor simpleVisitor = new TaskClassifyingVisitor();
@@ -241,6 +243,7 @@ public void syntaxError(Recognizer, ?> recognizer, Object offendingSymbol, int
st.add("jobs", jobs);
st.add("jobnames", jobnames);
st.add("combineTables", CodeGeneratingVisitor.combineAggregatorStrings);
+ st.add("userDeclAgg", CodeGeneratingVisitor.userAggregatorDeclStrings);
st.add("reduceTables", CodeGeneratingVisitor.reduceAggregatorStrings);
st.add("splitsize", isSimple ? 64 * 1024 * 1024 : 10 * 1024 * 1024);
if(DefaultProperties.localDataPath != null) {
diff --git a/src/java/boa/compiler/SymbolTable.java b/src/java/boa/compiler/SymbolTable.java
index 9fb315fa5..49274068f 100644
--- a/src/java/boa/compiler/SymbolTable.java
+++ b/src/java/boa/compiler/SymbolTable.java
@@ -22,6 +22,7 @@
import java.util.*;
import java.util.Map.Entry;
+import boa.aggregators.UserDefinedAggregator;
import org.scannotation.AnnotationDB;
import boa.aggregators.AggregatorSpec;
@@ -42,7 +43,7 @@ public class SymbolTable {
private static final Map, BoaType> protomap;
private static Map idmap;
private static final Map globals;
- private static FunctionTrie globalFunctions;
+ private static FunctionTrie globalFunctions;
private FunctionTrie functions;
private Map locals;
@@ -90,6 +91,7 @@ public class SymbolTable {
idmap.put("float", new BoaFloat());
idmap.put("time", new BoaTime());
idmap.put("string", new BoaString());
+ idmap.put("tuple", new BoaTuple(new ArrayList()));
final BoaProtoTuple[] dslTupleTypes = {
new ASTRootProtoTuple(),
@@ -435,15 +437,28 @@ else if (aggregators.containsKey(name))
}
public List> getAggregators(final String name, final BoaType type) {
- final List> aggregators = new ArrayList>();
-
- if (type instanceof BoaTuple)
- for (final BoaType subType : ((BoaTuple) type).getTypes())
- aggregators.add(this.getAggregator(name, subType));
- else
- aggregators.add(this.getAggregator(name, type));
+ final List> searchResult = new ArrayList>();
+ if (possibleInBuiltAgg(name)) {
+ if (type instanceof BoaTuple)
+ searchResult.add(this.getAggregator(name, type));
+ else if (type instanceof BoaArray)
+ searchResult.add(this.getAggregator(name, ((BoaArray)type).getType()));
+ else
+ searchResult.add(this.getAggregator(name, type));
+ } else if (this.functions.hasFunction(name)) {
+ searchResult.add(UserDefinedAggregator.class);
+ }
+ return searchResult;
+ }
- return aggregators;
+ private boolean possibleInBuiltAgg(String name) {
+ Set names = aggregators.keySet();
+ for (final String entry: names) {
+ if(entry.contains(name)) {
+ return true;
+ }
+ }
+ return false;
}
private static void importFunction(final Method m) {
@@ -495,7 +510,9 @@ private static void importLibs(final List urls) throws IOException {
boa.functions.BoaSortIntrinsics.class,
boa.functions.BoaSpecialIntrinsics.class,
boa.functions.BoaStringIntrinsics.class,
- boa.functions.BoaTimeIntrinsics.class
+ boa.functions.BoaTimeIntrinsics.class,
+ boa.functions.BoaMatrixIntrinsics.class,
+ boa.functions.BoaMLIntrinsics.class
};
for (final Class> c : builtinFuncs)
importFunctions(c);
diff --git a/src/java/boa/compiler/UserDefinedAgg.java b/src/java/boa/compiler/UserDefinedAgg.java
new file mode 100644
index 000000000..1eb7d32f4
--- /dev/null
+++ b/src/java/boa/compiler/UserDefinedAgg.java
@@ -0,0 +1,319 @@
+package boa.compiler;
+
+
+import boa.compiler.ast.statements.VarDeclStatement;
+import boa.compiler.ast.types.AbstractType;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class UserDefinedAgg {
+ private final String userGivenName;
+ private final String code;
+
+ public String getCode() {
+ return code;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private UserDefinedAgg(String name, String code) {
+ this.userGivenName = name;
+ this.code = code;
+ }
+
+ public String getAggClassName() {
+ return "UserDefined$" + this.userGivenName;
+ }
+
+ public static class Builder {
+ private String funcVarName;
+ private String lambdaName;
+ private String lambdaType;
+ private String lambdaInit;
+ private String lambdaInterface;
+ private String userGivenFuncArg = null; // user given param names
+ private String funcArgType = null; // funcVarName of the compiler generated userGivenParams
+ private String returnType;
+ private boolean isAggregator = false;
+ private List aggregatorOptionParamId = new ArrayList();
+ private List aggregatorOptionParamInitializer = new ArrayList();
+ private List aggregatorOutputParamTypes = new ArrayList();
+ private List userAggOptionVariables = new ArrayList();;
+
+
+ public List getAggregatorOptionParamId() {
+ return aggregatorOptionParamId;
+ }
+
+ public boolean addAggregatorOptionParamId(String code, int index) {
+ return this.aggregatorOptionParamId.add(aggregatorOutputParamTypes.get(index).type.toJavaType() + " " + code + ";\n");
+ }
+
+ public boolean addAggregatorOptionParamInitializer(String initializer) {
+ return this.aggregatorOptionParamInitializer.add(initializer);
+ }
+
+ public void setAggregatorOptionParamType(List params) {
+ for(VarDeclStatement stmt: params) {
+ this.aggregatorOutputParamTypes.add(stmt.getType());
+ }
+ }
+
+ public UserDefinedAgg build(){
+ return new UserDefinedAgg(this.funcVarName, this.generateCode());
+ }
+
+ public Builder userGivenName(String name) {
+ this.funcVarName = name;
+ return this;
+ }
+
+ public Builder setLambdaNameAndType(String name) {
+ String[] details = name.split(" ");
+ this.lambdaType = details[0];
+ this.lambdaName = details[1].substring(0, details[1].length()- 2);
+ return this;
+ }
+
+ public Builder lambdaInit(String init) {
+ this.lambdaInit = getInterfaceInitCode(init);
+ return this;
+ }
+
+ public Builder returnType(String type) {
+ this.returnType = type;
+ return this;
+ }
+
+ public boolean isAggregator() {
+ return this.isAggregator;
+ }
+
+ public boolean isAggregator(boolean flag) {
+ this.isAggregator = flag;
+ return this.isAggregator;
+ }
+
+ public Builder lambdaInterface(String decl) {
+ this.lambdaInterface = updatedInterDeclAndGetOptionVars(decl);
+ return this;
+ }
+
+ //FIXME: This currently just handles only one argument in the user defined aggregators
+ public Builder argTypeName(String param) {
+ if(this.funcArgType == null) {
+ StringBuffer typeNameBuilder = new StringBuffer(param.substring(0, param.length() - 2));
+ typeNameBuilder.setCharAt(0, Character.toUpperCase(typeNameBuilder.charAt(0)));
+ this.funcArgType = typeNameBuilder.toString();
+ }
+ return this;
+ }
+
+ //FIXME: This currently just handles only one argument in the user defined aggregators
+ public Builder userGivenFuncArg(String param) {
+ if(this.userGivenFuncArg == null) {
+ this.userGivenFuncArg = param;
+ }
+ return this;
+ }
+
+ public boolean isParam(String name) {
+ return this.funcArgType.equals(name) || this.funcArgType.equals(name + "[]");
+ }
+
+ public String getFuncVarName() {
+ return this.funcVarName;
+ }
+
+ public String getLambdaType() {
+ return lambdaType;
+ }
+
+ private String getOverridingMethds() {
+ String parser = typeParser(funcArgType.toString());
+ STGroup stg = new STGroupFile("templates/UserAggregatorClass.stg");
+ final ST st = stg.getInstanceOf("OverridenMethods");
+
+ st.add("name", this.lambdaName);
+ st.add("type", funcArgType.toString());
+ st.add("returnType", this.returnType);
+ if(parser.isEmpty()){
+ st.add("nonPrimitive", true);
+ }else {
+ st.add("parser", parser);
+ st.add("javaPrimitiveType", funcArgType.toLowerCase());
+ }
+ return st.render();
+ }
+
+ private String generateCode() {
+ STGroup stg = new STGroupFile("templates/UserAggregatorClass.stg");
+ final ST st = stg.getInstanceOf("AggregatorClass");
+
+ st.add("funcName", this.getFuncVarName());
+ st.add("methods", fulQualifiedNameGne(this.getOverridingMethds()));
+ st.add("lambdaInit", fulQualifiedNameGne(this.lambdaInit));
+ st.add("lambdaType", this.lambdaType);
+ st.add("lambdaName", this.lambdaName);
+ st.add("interface", fulQualifiedNameGne(this.lambdaInterface));
+ st.add("aggParams", removeFinal());
+ if(this.funcArgType != null) {
+ st.add("funcArg", fulQualifiedNameGne(funcArgType));
+ }else {
+ st.add("funcArg", this.userGivenFuncArg);
+ }
+
+ String constructor = getAggregatorOptionalVarInit(userAggOptionVariables);
+ if(!constructor.isEmpty())
+ st.add("constcode", constructor);
+
+ return st.render();
+ }
+
+
+ private String fulQualifiedNameGne(String str) {
+ StringBuffer qualifiedName = new StringBuffer();
+ qualifiedName
+ .append("boa.")
+ .append(UserDefinedAggregators.getFileName())
+ .append(".")
+ .append(UserDefinedAggregators.getFileName())
+ .append("BoaMapper")
+ .append(".")
+ .append(UserDefinedAggregators.getJobName())
+ .append(".BoaTup_");
+ return str.replace("BoaTup_", qualifiedName.toString());
+ }
+
+ private boolean isPrimitive(String typeName) {
+ return "long".equalsIgnoreCase(typeName)
+ || "int".equalsIgnoreCase(typeName)
+ || "long[]".equalsIgnoreCase(typeName)
+ || "int[]".equalsIgnoreCase(typeName)
+ || "integer[]".equalsIgnoreCase(typeName)
+ || "integer".equalsIgnoreCase(typeName)
+ || "float".equalsIgnoreCase(typeName)
+ || "double".equalsIgnoreCase(typeName)
+ || "float[]".equalsIgnoreCase(typeName)
+ || "double[]".equalsIgnoreCase(typeName)
+ || "boolean".equalsIgnoreCase(typeName)
+ || "boolean[]".equalsIgnoreCase(typeName)
+ || "bool".equalsIgnoreCase(typeName)
+ || "bool[]".equalsIgnoreCase(typeName)
+ || "String[]".equalsIgnoreCase(typeName)
+ || "String".equalsIgnoreCase(typeName)
+ || "byte".equalsIgnoreCase(typeName)
+ || "byte[]".equalsIgnoreCase(typeName)
+ || "char[]".equalsIgnoreCase(typeName)
+ || "char".equalsIgnoreCase(typeName);
+ }
+
+ private String typeParser(String typeName) {
+ String result = "";
+ if ("long".equalsIgnoreCase(typeName)
+ || "int".equalsIgnoreCase(typeName)
+ || "long[]".equalsIgnoreCase(typeName)
+ || "int[]".equalsIgnoreCase(typeName)
+ || "integer[]".equalsIgnoreCase(typeName)
+ || "integer".equalsIgnoreCase(typeName)) {
+ result = "Long.parseLong";
+ } else if("float".equalsIgnoreCase(typeName)
+ || "double".equalsIgnoreCase(typeName)
+ || "float[]".equalsIgnoreCase(typeName)
+ || "double[]".equalsIgnoreCase(typeName)) {
+ result = "Double.parseDouble";
+ } else if("boolean".equalsIgnoreCase(typeName)
+ || "boolean[]".equalsIgnoreCase(typeName)
+ || "bool".equalsIgnoreCase(typeName)
+ || "bool[]".equalsIgnoreCase(typeName)) {
+ result = "Boolean.valueOf";
+ }
+ return result;
+ }
+
+ private String updatedInterDeclAndGetOptionVars(String lambdaInterfaceDecl) {
+ final int startindex = lambdaInterfaceDecl.indexOf('(');
+ final int endIndex = lambdaInterfaceDecl.indexOf(')');
+ String allVargs = lambdaInterfaceDecl.substring(startindex + 1, endIndex);
+ String vars[] = allVargs.split(",");
+ if(vars.length > 0) {
+ if(!isArrayArgument(vars[0])) {
+ throw new RuntimeException("First argument of userDefinedAggregator must be array of values");
+ }
+ // update the interface declaration code with removing all of the arguments with just one
+ if(userAggOptionVariables.size() <= 0) {
+ String tmp = vars.length > 1 ? flattenArrayWithSeperator(Arrays.copyOfRange(vars, 1, vars.length), ',') : "";
+ Collections.addAll(userAggOptionVariables, tmp.split(","));
+ }
+ return lambdaInterfaceDecl.replace(allVargs, vars[0]);
+ } else {
+ throw new RuntimeException("Userdefined aggregators must have atleast one argument, which is array of values");
+ }
+ }
+
+ private boolean isArrayArgument(String arg) {
+ return arg.matches("final\\s+.*\\[]\\s+_*.*");
+ }
+
+ private String flattenArrayWithSeperator(final String[] vars, final char seperator) {
+ final StringBuffer flattened = new StringBuffer();
+ for(final String s: vars) {
+ if(s.startsWith("final")) {
+ flattened.append(s.substring(5)).append(seperator);
+ } else {
+ flattened.append(s).append(seperator);
+ }
+ }
+ flattened.deleteCharAt(flattened.length() - 1);
+ return flattened.toString();
+ }
+
+ private String getInterfaceInitCode(String lambdaInterfaceDecl) {
+ final StringBuffer codegenerator = new StringBuffer(lambdaInterfaceDecl);
+ //FIXME: this is an hack in the generated code
+ final int startindex = lambdaInterfaceDecl.indexOf("invoke") + "invoke".length();
+ final int endIndex = lambdaInterfaceDecl.indexOf(" throws"); // space is important here
+ String allVargs = lambdaInterfaceDecl.substring(startindex + 1, endIndex - 1);
+ System.out.println(allVargs);
+ String vars[] = allVargs.split(",");
+ if(vars.length > 0) {
+ return lambdaInterfaceDecl.replace(allVargs, vars[0]);
+ } else {
+ throw new RuntimeException("Userdefined aggregators must have atleast one argument, which is array of values");
+ }
+ }
+
+ private String getAggregatorOptionalVarInit(final List args) {
+ if(args.size() <= 0) {
+ return "";
+ }
+ StringBuffer code = new StringBuffer();
+ StringBuffer param = new StringBuffer();
+ param.append("( ");
+ for(String s: args) {
+ String[] tmp = s.split(" ");
+ code.append("\t\tthis.").append(tmp[tmp.length - 1]).append(" = ").append(tmp[tmp.length - 1]).append(";\n");
+ param.append(s).append(", ");
+ }
+ param.deleteCharAt(param.length() - 2);
+ param.append(" ) {").append("\n\t").append("this();\n\t").append(code.toString()).append("\n}");
+ return param.toString();
+ }
+
+ private List removeFinal() {
+ for(int i = 0; i < userAggOptionVariables.size(); i++) {
+ userAggOptionVariables.set(i, userAggOptionVariables.get(i).substring(7));
+ }
+ return userAggOptionVariables;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/java/boa/compiler/UserDefinedAggregators.java b/src/java/boa/compiler/UserDefinedAggregators.java
new file mode 100644
index 000000000..acf4ce304
--- /dev/null
+++ b/src/java/boa/compiler/UserDefinedAggregators.java
@@ -0,0 +1,69 @@
+package boa.compiler;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import boa.compiler.UserDefinedAgg.Builder;
+
+public class UserDefinedAggregators {
+ private final static List allFunctions = new ArrayList();
+ private static String jobName;
+ private static String fileName;
+
+ public static void setJobName(String jobName) {
+ UserDefinedAggregators.jobName = jobName;
+ }
+
+ public static void filterAggregatorFunctions() {
+ for(int i = 0; i < allFunctions.size(); i++) {
+ if(!allFunctions.get(i).isAggregator()) {
+ allFunctions.remove(i);
+ }
+ }
+ }
+
+ public static void setFileName(String fileName) {
+ fileName = fileName.substring(0, fileName.indexOf('.'));
+ fileName = fileName.substring(0, 1).toUpperCase() + fileName.substring(1);
+ UserDefinedAggregators.fileName = fileName.substring(0, 1).toUpperCase() + fileName.substring(1);;
+ }
+
+ public static Iterator iterator() {
+ return allFunctions.iterator();
+ }
+
+ public static boolean addNewUserFunction(Builder function) {
+ return allFunctions.add(function);
+ }
+
+ public static List getAllFunctions() {
+ return allFunctions;
+ }
+
+ public static Builder findByUserGivenName(String name) {
+ for(Builder function : allFunctions) {
+ if(function.getFuncVarName().equals(name)) {
+ return function;
+ }
+ }
+ return null;
+ }
+
+ public static Builder findByLambdaType(String name) {
+ for(Builder function : allFunctions) {
+ if(function.getLambdaType().equals(name)) {
+ return function;
+ }
+ }
+ return null;
+ }
+
+ public static String getJobName() {
+ return jobName;
+ }
+
+ public static String getFileName() {
+ return fileName;
+ }
+}
\ No newline at end of file
diff --git a/src/java/boa/compiler/ast/types/OutputType.java b/src/java/boa/compiler/ast/types/OutputType.java
index a3e04f766..849c56f9e 100644
--- a/src/java/boa/compiler/ast/types/OutputType.java
+++ b/src/java/boa/compiler/ast/types/OutputType.java
@@ -22,6 +22,7 @@
import boa.compiler.ast.Component;
import boa.compiler.ast.Identifier;
import boa.compiler.ast.expressions.Expression;
+import boa.compiler.ast.statements.VarDeclStatement;
import boa.compiler.visitors.AbstractVisitor;
import boa.compiler.visitors.AbstractVisitorNoArg;
import boa.compiler.visitors.AbstractVisitorNoReturn;
@@ -35,6 +36,7 @@ public class OutputType extends AbstractType {
protected Identifier id;
protected final List args = new ArrayList();
protected final List indices = new ArrayList();
+ protected final List params = new ArrayList();
protected Component t;
protected Component weight;
@@ -72,6 +74,18 @@ public void setArgs(final List args) {
}
}
+ public void setParams(final List params) {
+ this.params.clear();
+ for (final VarDeclStatement e : params) {
+ e.setParent(this);
+ this.params.add(e);
+ }
+ }
+
+ public List getParams() {
+ return params;
+ }
+
public List getIndices() {
return indices;
}
diff --git a/src/java/boa/compiler/visitors/CodeGeneratingVisitor.java b/src/java/boa/compiler/visitors/CodeGeneratingVisitor.java
index f365b6043..ba22d6593 100644
--- a/src/java/boa/compiler/visitors/CodeGeneratingVisitor.java
+++ b/src/java/boa/compiler/visitors/CodeGeneratingVisitor.java
@@ -24,11 +24,14 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import boa.compiler.UserDefinedAgg;
import org.stringtemplate.v4.ST;
+import boa.aggregators.Aggregator;
import boa.aggregators.AggregatorSpec;
import boa.compiler.SymbolTable;
import boa.compiler.TypeCheckException;
+import boa.compiler.UserDefinedAggregators;
import boa.compiler.ast.*;
import boa.compiler.ast.expressions.*;
import boa.compiler.ast.literals.*;
@@ -175,8 +178,15 @@ public void visit(final FixPExpression n) {
/** {@inheritDoc} */
@Override
public void visit(final VarDeclStatement n) {
- if (n.type instanceof BoaTable)
+ if (n.type instanceof BoaTable) {
+ UserDefinedAgg.Builder function = UserDefinedAggregators.findByUserGivenName(((OutputType)n.getType()).getId().getToken());
+ if(function != null) {
+ function.isAggregator(true);
+ function.setAggregatorOptionParamType(((OutputType)n.getType()).getParams());
+ }
return;
+ }
+
final ST st = stg.getInstanceOf("VarDecl");
@@ -187,6 +197,13 @@ public void visit(final VarDeclStatement n) {
st.add("isstatic", true);
code.add(st.render());
+
+ if(n.type instanceof BoaFunction) {
+ UserDefinedAgg.Builder funcTionBuilder = UserDefinedAgg.builder();
+ funcTionBuilder.userGivenName(n.getId().getToken()).setLambdaNameAndType(st.render());
+ funcTionBuilder.returnType(((BoaFunction)n.type).getType().toJavaType());
+ UserDefinedAggregators.addNewUserFunction(funcTionBuilder);
+ }
}
}
@@ -220,9 +237,15 @@ public void visit(final FunctionType n) {
final List args = new ArrayList();
final List types = new ArrayList();
+ UserDefinedAgg.Builder functionBuilder = UserDefinedAggregators.findByLambdaType(name);
+
for (final Component c : params) {
args.add(c.getIdentifier().getToken());
types.add(c.getType().type.toJavaType());
+ if(functionBuilder != null && functionBuilder.isAggregator()) {
+ functionBuilder.argTypeName(c.getType().type.toJavaType());
+ functionBuilder.userGivenFuncArg(c.getIdentifier().getToken());
+ }
}
st.add("name", funcType.toJavaType());
@@ -233,6 +256,10 @@ public void visit(final FunctionType n) {
st.add("args", args);
st.add("types", types);
+ if(functionBuilder != null) {
+ functionBuilder.lambdaInterface(st.render());
+ }
+
code.add(st.render());
}
}
@@ -280,7 +307,6 @@ public void visit(final TupleType n) {
st.add("name", tupType.toJavaType());
st.add("fields", fields);
st.add("types", types);
-
code.add(st.render());
}
}
@@ -505,6 +531,7 @@ public void visit(final Call n) {
final public static List combineAggregatorStrings = new ArrayList();
final public static List reduceAggregatorStrings = new ArrayList();
+ final public static Set userAggregatorDeclStrings = new HashSet();
public CodeGeneratingVisitor(final String name) throws IOException {
this.name = name;
@@ -524,6 +551,7 @@ public void visit(final Program n) {
st.add("name", this.name);
this.varDecl.start(n);
+ UserDefinedAggregators.filterAggregatorFunctions();
this.functionDeclarator.start(n);
this.tupleDeclarator.start(n);
this.enumDeclarator.start(n);
@@ -579,9 +607,30 @@ public void visit(final Program n) {
throw new TypeCheckException(n, e.getMessage(), e);
}
}
+
+ if(Aggregator.isUserDefinedAggregator(entry.getValue().getAggregator())) {
+ UserDefinedAgg function = UserDefinedAggregators
+ .findByUserGivenName(entry.getValue().getAggregator())
+ .build();
+ String gencode = function.getCode();
+ if(!userAggregatorDeclStrings.contains(gencode)) {
+ userAggregatorDeclStrings.add(gencode);
+ }
+ StringBuffer params = new StringBuffer();
+ for(String param: entry.getValue().getParameters()) {
+ params.append(param).append(", ");
+ }
+ params.deleteCharAt(params.length() - 2);
+
+ reduceAggregatorStrings.add("this.aggregators.put(\"" + prefix + "::" + id + "\", new " + function.getAggClassName() + "(" + params.toString() + "));");
+ combines = false;
+ } else {
+ reduceAggregatorStrings.add("this.aggregators.put(\"" + prefix + "::" + id + "\", " + src.toString().substring(2) + ");");
+ }
+
if (combines)
combineAggregatorStrings.add("this.aggregators.put(\"" + prefix + "::" + id + "\", " + src.toString().substring(2) + ");");
- reduceAggregatorStrings.add("this.aggregators.put(\"" + prefix + "::" + id + "\", " + src.toString().substring(2) + ");");
+
}
code.add(st.render());
@@ -798,6 +847,7 @@ public void visit(final Factor n) {
String accept = "";
abortGeneration = false;
+ n.env.setOperandType(n.getOperand().type);
if (!(n.getOp(0) instanceof Call)) {
n.getOperand().accept(this);
n.env.setOperandType(n.getOperand().type);
@@ -1324,6 +1374,23 @@ public void visit(final VarDeclStatement n) {
}
if (type instanceof BoaTable) {
+ UserDefinedAgg.Builder function = UserDefinedAggregators.findByUserGivenName(n.getId().getToken());
+ if(function != null) {
+ n.getInitializer().accept(this);
+ function.lambdaInit(code.removeLast());
+ }
+ if(n.getType() instanceof OutputType) {
+ function = UserDefinedAggregators.findByUserGivenName(((OutputType) n.getType()).getId().getToken());
+ if(function != null) {
+ int counter = 0;
+ for(VarDeclStatement stmt: ((OutputType) n.getType()).getParams()) {
+ stmt.accept(this);
+ String[] argCode = code.removeLast().split("=");
+ function.addAggregatorOptionParamId(argCode[0], counter++);
+ function.addAggregatorOptionParamInitializer(argCode[1]);
+ }
+ }
+ }
code.add("");
return;
}
@@ -1358,6 +1425,13 @@ public void visit(final VarDeclStatement n) {
n.getInitializer().accept(this);
String src = code.removeLast();
+ if(t instanceof BoaFunction) {
+ UserDefinedAgg.Builder functionDetails = UserDefinedAggregators.findByUserGivenName(n.getId().getToken());
+ if(functionDetails != null) {
+ functionDetails.lambdaInterface(src);
+ }
+ }
+
if(lhsType instanceof BoaTuple && t instanceof BoaArray) {
Operand op = n.getInitializer().getLhs().getLhs().getLhs().getLhs().getLhs().getOperand();
if(op instanceof Composite) {
@@ -1858,8 +1932,12 @@ public void visit(final OutputType n) {
final BoaTable t = (BoaTable) n.env.get(id);
if (n.getArgsSize() > 0) {
- n.getArg(0).accept(this);
- this.aggregators.put(id, new AggregatorDescription(aggregator, t.getType(), Arrays.asList(code.removeLast())));
+ List codegen = new ArrayList();
+ for(Expression e: n.getArgs()) {
+ e.accept(this);
+ codegen.add(code.removeLast());
+ }
+ this.aggregators.put(id, new AggregatorDescription(aggregator, t.getType(), codegen));
} else {
this.aggregators.put(id, new AggregatorDescription(aggregator, t.getType()));
}
diff --git a/src/java/boa/compiler/visitors/TypeCheckingVisitor.java b/src/java/boa/compiler/visitors/TypeCheckingVisitor.java
index c12c28126..f630dc882 100644
--- a/src/java/boa/compiler/visitors/TypeCheckingVisitor.java
+++ b/src/java/boa/compiler/visitors/TypeCheckingVisitor.java
@@ -391,9 +391,9 @@ else if (n.getExprsSize() > 0) {
if(!(checkTupleArray(types) == true)) {
final BoaType t = types.get(0);
- if (!(t instanceof BoaScalar))
- if (!(t instanceof BoaTuple))
- throw new TypeCheckException(n.getExprs(), "non-scalar/non-tuple type '" + t + "' can not be used in arrays");
+// if (!(t instanceof BoaScalar))
+// if (!(t instanceof BoaTuple))
+// throw new TypeCheckException(n.getExprs(), "non-scalar/non-tuple type '" + t + "' can not be used in arrays");
n.type = new BoaArray(t);
}
else
@@ -1314,9 +1314,9 @@ public void visit(final ArrayType n, final SymbolTable env) {
n.env = env;
n.getValue().accept(this, env);
final BoaType t = n.getValue().type;
- if (!(t instanceof BoaScalar))
- if (!(t instanceof BoaTuple))
- throw new TypeCheckException(n.getValue(), "non-scalar/non-tuple type '" + t + "' can not be used in arrays");
+// if (!(t instanceof BoaScalar))
+// if (!(t instanceof BoaTuple))
+// throw new TypeCheckException(n.getValue(), "non-scalar/non-tuple type '" + t + "' can not be used in arrays");
n.type = new BoaArray(t);
}
@@ -1400,6 +1400,10 @@ public void visit(final OutputType n, final SymbolTable env) {
if (n.getArgsSize() > 0 && annotation.formalParameters().length == 0)
throw new TypeCheckException(n.getArgs(), "output aggregator '" + n.getId().getToken() + "' takes no arguments");
+ for(VarDeclStatement stmt: n.getParams()) {
+ stmt.accept(this, env);
+ }
+
n.type = new BoaTable(type, indexTypes, tweight, annotation.canOmitWeight());
env.set(n.getId().getToken(), n.type);
n.getId().accept(this, env);
diff --git a/src/java/boa/datagen/forges/github/GetGithubRepoByUser.java b/src/java/boa/datagen/forges/github/GetGithubRepoByUser.java
index 6f4f30954..905386cee 100644
--- a/src/java/boa/datagen/forges/github/GetGithubRepoByUser.java
+++ b/src/java/boa/datagen/forges/github/GetGithubRepoByUser.java
@@ -33,7 +33,7 @@ public static void main(String[] args) {
// Arrays.sort(files, new Comparator() {
// @Override
// public int compare(File f1, File f2) {
-// int n1 = getNumber(f1.getName()), n2 = getNumber(f2.getName());
+// int n1 = getNumber(f1.getFuncVarName()), n2 = getNumber(f2.getFuncVarName());
// return n1 - n2;
// }
//
diff --git a/src/java/boa/functions/BoaAstIntrinsics.java b/src/java/boa/functions/BoaAstIntrinsics.java
index acd13cfe4..13026f4c2 100644
--- a/src/java/boa/functions/BoaAstIntrinsics.java
+++ b/src/java/boa/functions/BoaAstIntrinsics.java
@@ -469,9 +469,9 @@ protected boolean preVisit(Type node) {
// FIXME
/*
try {
- parseGenericType(BoaAstIntrinsics.type_name(node.getName()).trim(), map);
+ parseGenericType(BoaAstIntrinsics.type_name(node.getFuncVarName()).trim(), map);
} catch (final StackOverflowError e) {
- System.err.println("STACK ERR: " + node.getName() + " -> " + BoaAstIntrinsics.type_name(node.getName()).trim());
+ System.err.println("STACK ERR: " + node.getFuncVarName() + " -> " + BoaAstIntrinsics.type_name(node.getFuncVarName()).trim());
}
*/
return true;
diff --git a/src/java/boa/functions/BoaMLIntrinsics.java b/src/java/boa/functions/BoaMLIntrinsics.java
new file mode 100644
index 000000000..047df1fad
--- /dev/null
+++ b/src/java/boa/functions/BoaMLIntrinsics.java
@@ -0,0 +1,35 @@
+package boa.functions;
+
+import boa.BoaTup;
+import boa.datagen.util.FileIO;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import javax.lang.model.element.Modifier;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLConnection;
+
+/**
+ * Machine learning utility function
+ * @author: nmtiwari
+ */
+public class BoaMLIntrinsics {
+ /**
+ * Return a random floating point number x in the range 0.0 < x < 1.0.
+ *
+ * @return A random floating point number x in the range 0.0 < x < 1.0
+ */
+ @FunctionSpec(name = "load", returnType = "tuple", formalParameters = { "string", "any"})
+ public static T load(String path, T type) {
+ Gson obj = new GsonBuilder().excludeFieldsWithModifiers(org.eclipse.jdt.core.dom.Modifier.TRANSIENT).serializeNulls().create();
+ String json = FileIO.readFileContents(new File(path));
+ T model = (T)obj.fromJson(json,type.getClass());
+ return model;
+ }
+}
diff --git a/src/java/boa/functions/BoaMatrixIntrinsics.java b/src/java/boa/functions/BoaMatrixIntrinsics.java
new file mode 100644
index 000000000..5e0275f75
--- /dev/null
+++ b/src/java/boa/functions/BoaMatrixIntrinsics.java
@@ -0,0 +1,1003 @@
+package boa.functions;
+
+import Jama.Matrix;
+import boa.BoaTup;
+
+import com.google.common.primitives.Doubles;
+import com.google.common.primitives.Longs;
+import org.apache.commons.lang.ArrayUtils;
+
+
+import java.lang.reflect.Array;
+import java.util.*;
+
+/**
+ * Created by nmtiwari on 2/11/17.
+ */
+public class BoaMatrixIntrinsics {
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "matrix", returnType = "array of array of int", formalParameters = { "array of int", "int" })
+ public static long[][] matrix(final long[] a, final long colsize) {
+ final int cols = (int)colsize;
+ final int rows = a.length/cols;
+ final long[][] result = new long[rows][cols];
+ for(int i = 0; i< rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ result[i][j] = a[i * cols + j];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "matrix", returnType = "array of array of string", formalParameters = { "array of string", "int" })
+ public static String[][] matrix(final String[] a, final long colsize) {
+ final int cols = (int)colsize;
+ final int rows = a.length/cols;
+ final String[][] result = new String[rows][cols];
+ for(int i = 0; i< rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ result[i][j] = a[i * cols + j];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "matrix", returnType = "array of array of float", formalParameters = { "array of float", "int" })
+ public static float[][] matrix(final float[] a, final long colsize) {
+ final int cols = (int)colsize;
+ final int rows = a.length/cols;
+ final float[][] result = new float[rows][cols];
+ for(int i = 0; i< rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ result[i][j] = a[i * cols + j];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "matrix", returnType = "array of array of tuple", formalParameters = { "array of tuple", "int" })
+ public static BoaTup[][] matrix(final BoaTup[] a, final long colsize) {
+ final int cols = (int)colsize;
+ final int rows = a.length/cols;
+ final BoaTup[][] result = new BoaTup[rows][cols];
+ for(int i = 0; i< rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ result[i][j] = a[i * cols + j];
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of array of int", formalParameters = { "array of array of int", "array of array of int" })
+ public static long[][] multiply(final long[][] a, final long[][] b) {
+ double[][] a_double = new double[a.length][];
+ double[][] b_double = new double[b.length][];
+
+ for(int i = 0; i< a.length; i++){
+ a_double[i] = Doubles.toArray(Longs.asList(a[i]));
+ }
+
+ for(int i = 0; i< b.length; i++){
+ b_double[i] = Doubles.toArray(Longs.asList(b[i]));
+ }
+ Matrix a_matrix = new Matrix(a_double);
+ Matrix b_matrix = new Matrix(b_double);
+ double[][] result = a_matrix.times(b_matrix).getArray();
+ long[][]result_long = new long[result.length][];
+ for(int i = 0; i< result.length; i++){
+ result_long[i] = Longs.toArray(Doubles.asList(result[i]));
+ }
+ return result_long;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of array of int", formalParameters = { "array of array of int", "int" })
+ public static long[][] multiply(final long[][] a, final long b) {
+ double[][] a_double = new double[a.length][];
+
+ for(int i = 0; i< a.length; i++){
+ a_double[i] = Doubles.toArray(Longs.asList(a[i]));
+ }
+
+ Matrix a_matrix = new Matrix(a_double);
+ double[][] result = a_matrix.times(b).getArray();
+ long[][]result_long = new long[result.length][];
+ for(int i = 0; i< result.length; i++){
+ result_long[i] = Longs.toArray(Doubles.asList(result[i]));
+ }
+ return result_long;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of array of int", formalParameters = { "array of array of int", "float" })
+ public static double[][] multiply(final long[][] a, final float b) {
+ double[][] a_double = new double[a.length][];
+
+ for(int i = 0; i< a.length; i++){
+ a_double[i] = Doubles.toArray(Longs.asList(a[i]));
+ }
+
+ Matrix a_matrix = new Matrix(a_double);
+ return a_matrix.times(b).getArray();
+ }
+
+
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "matrixsum", returnType = "array of array of int", formalParameters = { "array of array of int", "array of array of int" })
+ public static long[][] matrixsum(final long[][] a, final long[][] b) {
+ double[][] a_double = new double[a.length][];
+ double[][] b_double = new double[b.length][];
+
+ for(int i = 0; i< a.length; i++){
+ a_double[i] = Doubles.toArray(Longs.asList(a[i]));
+ }
+
+ for(int i = 0; i< b.length; i++){
+ b_double[i] = Doubles.toArray(Longs.asList(b[i]));
+ }
+ Matrix a_matrix = new Matrix(a_double);
+ Matrix b_matrix = new Matrix(b_double);
+ double[][] result = a_matrix.plus(b_matrix).getArray();
+ long[][]result_long = new long[result.length][];
+ for(int i = 0; i< result.length; i++){
+ result_long[i] = Longs.toArray(Doubles.asList(result[i]));
+ }
+ return result_long;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "matrixsubstract", returnType = "array of array of int", formalParameters = { "array of array of int", "array of array of int" })
+ public static long[][] matrixsubstract(final long[][] a, final long[][] b) {
+ double[][] a_double = new double[a.length][];
+ double[][] b_double = new double[b.length][];
+
+ for(int i = 0; i< a.length; i++){
+ a_double[i] = Doubles.toArray(Longs.asList(a[i]));
+ }
+
+ for(int i = 0; i< b.length; i++){
+ b_double[i] = Doubles.toArray(Longs.asList(b[i]));
+ }
+ Matrix a_matrix = new Matrix(a_double);
+ Matrix b_matrix = new Matrix(b_double);
+ double[][] result = a_matrix.minus(b_matrix).getArray();
+ long[][]result_long = new long[result.length][];
+ for(int i = 0; i< result.length; i++){
+ result_long[i] = Longs.toArray(Doubles.asList(result[i]));
+ }
+ return result_long;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of array of float", formalParameters = { "array of array of float", "array of array of float" })
+ public static double[][] multiply(final double[][] a, final double[][] b) {
+ Matrix a_matrix = new Matrix(a);
+ Matrix b_matrix = new Matrix(b);
+ return a_matrix.times(b_matrix).getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of array of float", formalParameters = { "array of array of float", "float" })
+ public static double[][] multiply(final double[][] a, final double b) {
+ Matrix a_matrix = new Matrix(a);
+ return a_matrix.times(b).getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of array of float", formalParameters = { "array of array of float", "int" })
+ public static double[][] multiply(final double[][] a, final long b) {
+ Matrix a_matrix = new Matrix(a);
+ return a_matrix.times(b).getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of array of float", formalParameters = { "array of float", "array of array of float" })
+ public static double[][] multiply(final double[] a, final double[][] b) {
+ Matrix a_matrix = new Matrix(a, 1);
+ Matrix b_matrix = new Matrix(b);
+ return a_matrix.times(b_matrix).getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of float", formalParameters = { "array of float", "float" })
+ public static double[] multiply(final double[] a, final double b) {
+ Matrix a_matrix = new Matrix(a, a.length);
+ return a_matrix.times(b).getArray()[0];
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of float", formalParameters = { "array of float", "int" })
+ public static double[] multiply(final double[] a, final long b) {
+ Matrix a_matrix = new Matrix(a, 1);
+ double[][] temp = a_matrix.times(b).getArray();;
+ return temp[0];
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "multiply", returnType = "array of array of float", formalParameters = { "array of array of float", "array of float" })
+ public static double[][] multiply(final double[][] a, final double[] b) {
+ Matrix a_matrix = new Matrix(a);
+ Matrix b_matrix = new Matrix(b, 1);
+ return a_matrix.times(b_matrix).getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "matrixsum", returnType = "array of array of float", formalParameters = { "array of array of float", "array of array of float" })
+ public static double[][] matrixsum(final double[][] a, final double[][] b) {
+ Matrix a_matrix = new Matrix(a);
+ Matrix b_matrix = new Matrix(b);
+ return a_matrix.plus(b_matrix).getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "matrixsum", returnType = "array of float", formalParameters = { "array of float", "array of float" })
+ public static double[] matrixsum(final double[] a, final double[] b) {
+ if(a.length != b.length) {
+ throw new IllegalArgumentException("Argument lengths are not equal");
+ }
+ double[] result = new double[a.length];
+ for(int i =0 ; i < a.length; i++) {
+ result[i] = a[i] + b[i];
+ }
+ return result;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "matrixsubstract", returnType = "array of array of float", formalParameters = { "array of array of float", "array of array of float" })
+ public static double[][] matrixsubstract(final double[][] a, final double[][] b) {
+ Matrix a_matrix = new Matrix(a);
+ Matrix b_matrix = new Matrix(b);
+ return a_matrix.minus(b_matrix).getArray();
+ }
+
+
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "flatten", returnType = "array of float", formalParameters = { "array of array of float" })
+ public static double[] flatten(final double[][] a) {
+ final double[] flattenedTuples = new double[a.length * a[0].length];
+ int counter = 0;
+ for(int i = 0; i< a.length; i++) {
+ for (int j = 0; j < a[i].length; j++) {
+ flattenedTuples[counter++] = a[i][j];
+ }
+ }
+ return flattenedTuples;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "flatten", returnType = "array of tuple", formalParameters = { "array of array of tuple" })
+ public static BoaTup[] flatten(final BoaTup[][] a) {
+ final BoaTup[] flattenedTuples = new BoaTup[a.length * a[0].length];
+ int counter = 0;
+ for(int i = 0; i< a.length; i++) {
+ for (int j = 0; j < a[i].length; j++) {
+ flattenedTuples[counter++] = a[i][j];
+ }
+ }
+ return flattenedTuples;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "flatten", returnType = "array of float", formalParameters = { "tuple" })
+ public static double[] flatten(final BoaTup a) {
+ final int size = tupleLength(a);
+ final double[] results = new double[size];
+ int i = 0;
+ for(Double ele: a.asArray(new Double[1])){
+ results[i] = ele;
+ }
+ return results;
+ }
+
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "flattenedMatrix", returnType = "array of array of float", formalParameters = { "array of tuple", "int" })
+ public static double[][] flattenedMatrix(final BoaTup[] a, final long colsize) {
+ final List flattenedTuples = new ArrayList();
+ for(int i = 0; i< a.length; i++) {
+ for(Double ele: a[i].asArray(new Double[1])){
+ flattenedTuples.add(ele);
+ }
+ }
+
+ final int cols = (int)colsize;
+ final int rows = flattenedTuples.size()/cols;
+ final double[][] result = new double[rows][cols];
+
+ for(int i = 0; i< rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ result[i][j] = flattenedTuples.get(i * cols + j);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "tupleLength", returnType = "int", formalParameters = { "tuple" })
+ public static int tupleLength(final BoaTup a) {
+ final int sizeOfTuple = a.asArray(new Double[1]).length;
+ return sizeOfTuple;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "means", returnType = "array of float", formalParameters = { "array of tuple"})
+ public static double[] means(final BoaTup[] a) {
+ final int sizeOfTuple = a[0].asArray(new Double[1]).length;
+ final double[] means = new double[sizeOfTuple];
+
+ for(int i = 0; i< a.length; i++) {
+ Double[] tupAsArr = a[i].asArray(new Double[1]);
+ for (int index = 0; index < sizeOfTuple; index++) {
+ means[index] = means[index] + tupAsArr[index];
+ }
+ }
+
+ for (int index = 0; index < sizeOfTuple; index++) {
+ means[index] = means[index] / a.length;
+ }
+ return means;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "sum", returnType = "array of float", formalParameters = { "array of tuple"})
+ public static double[] sum(final BoaTup[] a) {
+ final int sizeOfTuple = a[0].asArray(new Double[1]).length;
+ final double[] sum = new double[sizeOfTuple];
+
+ for(int i = 0; i< a.length; i++) {
+ Double[] tupAsArr = a[i].asArray(new Double[1]);
+ for (int index = 0; index < sizeOfTuple; index++) {
+ sum[index] = sum[index] + tupAsArr[index];
+ }
+ }
+
+ return sum;
+ }
+
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "sum", returnType = "array of float", formalParameters = { "tuple", "tuple"})
+ public static double[] sum(final BoaTup a, final BoaTup b) {
+ final int sizeOfTupleA = a.asArray(new Double[1]).length;
+ final int sizeOfTupleB = b.asArray(new Double[1]).length;
+ if(sizeOfTupleA != sizeOfTupleB) {
+ throw new IllegalArgumentException("Dissimilar sttributes in Tuples");
+ }
+ final double[] sum = new double[sizeOfTupleA];
+ for(int i = 0; i< sizeOfTupleA; i++) {
+ Double[] tupAsArrA = a.asArray(new Double[1]);
+ Double[] tupAsArrB = a.asArray(new Double[1]);
+ for (int index = 0; index < sizeOfTupleA; index++) {
+ sum[index] = tupAsArrB[index] + tupAsArrA[index];
+ }
+ }
+ return sum;
+ }
+
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "flatten", returnType = "array of int", formalParameters = { "array of array of int" })
+ public static long[] flatten(final long[][] a) {
+ final long[] flattenedTuples = new long[a.length * a[0].length];
+ int counter = 0;
+ for(int i = 0; i< a.length; i++) {
+ for (int j = 0; j < a[i].length; j++) {
+ flattenedTuples[counter++] = a[i][j];
+ }
+ }
+ return flattenedTuples;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "transpose", returnType = "array of array of float", formalParameters = { "array of array of float" })
+ public static double[][] transpose(final double[][] a) {
+ Matrix matrix = new Matrix(a);
+ matrix = matrix.transpose();
+ return matrix.getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "transpose", returnType = "array of array of float", formalParameters = { "array of float" })
+ public static double[][] transpose(final double[] a) {
+ double[][] data = new double[a.length][];
+ for(int i = 0; i < a.length; i++){
+ double[] __temp = {a[i]};
+ data[i] = __temp;
+ }
+ return data;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "eigenvalsReal", returnType = "array of float", formalParameters = { "array of array of float" })
+ public static double[] eigenvalsReal(final double[][] a) {
+ Matrix matrix = new Matrix(a);
+ double[] temp = matrix.eig().getRealEigenvalues();
+ return matrix.eig().getRealEigenvalues();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "eigenvalsImg", returnType = "array of float", formalParameters = { "array of array of float" })
+ public static double[] eigenvalsImg(final double[][] a) {
+ Matrix matrix = new Matrix(a);
+ return matrix.eig().getImagEigenvalues();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "eigenvectors", returnType = "array of array of float", formalParameters = { "array of array of float" })
+ public static double[][] eigenvectors(final double[][] a) {
+ Matrix matrix = new Matrix(a);
+ return matrix.eig().getV().getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "vector", returnType = "array of array of float", formalParameters = { "array of float" })
+ public static double[][] vector(final double[] a) {
+ double[][] data = new double[a.length][];
+ for(int i = 0; i < a.length; i++){
+ double[] __temp = {a[i]};
+ data[i] = __temp;
+ }
+ return data;
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "inverse", returnType = "array of array of float", formalParameters = { "array of array of float" })
+ public static double[][] inverse(final double[][] a) {
+ Matrix matrix = new Matrix(a);
+ matrix = matrix.inverse();
+ return matrix.getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "inverse", returnType = "array of array of float", formalParameters = { "array of array of int" })
+ public static double[][] inverse(final long[][] a) {
+ double[][] data = new double[a.length][];
+ for(int i = 0; i< data.length; i++){
+ data[i] = Doubles.toArray(Longs.asList(a[i]));
+ }
+ Matrix matrix = new Matrix(data);
+ matrix = matrix.inverse();
+ return matrix.getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array.
+ *
+ * @param a
+ * An array of array of int
+ *
+ * @return A sub matrix from Matrix a
+ */
+ @FunctionSpec(name = "submatrix", returnType = "array of array of int", formalParameters = { "array of array of int", "int", "int", "int", "int" })
+ public static long[][] submatrix(final long[][] a, final long r_start, final long r_end, final long c_start, final long c_end) {
+ double[][] data = new double[a.length][];
+ for(int i = 0; i< data.length; i++){
+ data[i] = Doubles.toArray(Longs.asList(a[i]));
+ }
+ Matrix matrix = new Matrix(data);
+ matrix = matrix.getMatrix((int)r_start, (int)r_end, (int)c_start, (int)c_end);
+ data = matrix.getArray();
+ long[][] result = new long[a.length][];
+ for(int i = 0; i< data.length; i++){
+ result[i] = Longs.toArray(Doubles.asList(data[i]));
+ }
+ return result;
+ }
+
+ /**
+ * Returns the matrix version of an array.
+ *
+ * @param a
+ * An array of array of int
+ *
+ * @return A sub matrix from Matrix a
+ */
+ @FunctionSpec(name = "submatrix", returnType = "array of array of float", formalParameters = { "array of array of float", "int", "int", "int", "int" })
+ public static double[][] submatrix(final double[][] a, final long r_start, final long r_end, final long c_start, final long c_end) {
+ Matrix matrix = new Matrix(a);
+ matrix = matrix.getMatrix((int)r_start, (int)r_end, (int)c_start, (int)c_end);
+ return matrix.getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array.
+ *
+ * @param a
+ * An array of array of int
+ *
+ * @return A sub matrix from Matrix a
+ */
+ @FunctionSpec(name = "identity", returnType = "array of array of float", formalParameters = { "int", "int" })
+ public static double[][] identity(final int row, final int col) {
+ Matrix matrix = Matrix.identity(row, col);
+ return matrix.getArray();
+ }
+
+ /**
+ * Returns the matrix version of an array.
+ *
+ * @param a
+ * An array of array of int
+ *
+ * @return A sub matrix from Matrix a
+ */
+ @FunctionSpec(name = "getCol", returnType = "array of float", formalParameters = { "array of array of float", "int" })
+ public static double[] getCol(final double[][] data, final long col) {
+ double[] result = new double[data.length];
+ for(int i = 0; i < result.length; i++ ) {
+ result[i] = data[i][(int)col];
+ }
+ return result;
+ }
+
+ /**
+ * Returns the matrix version of an array.
+ *
+ * @param a
+ * An array of array of int
+ *
+ * @return A sub matrix from Matrix a
+ */
+ @FunctionSpec(name = "unique", returnType = "array of float", formalParameters = { "array of float" })
+ public static double[] unique(final double[] data) {
+ Set set = new HashSet(Doubles.asList(data));
+ final double[] result = new double[set.size()];
+ int i = 0;
+ for(Double d: set) {
+ result[i++] = d;
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns the matrix version of an array.
+ *
+ * @param a
+ * An array of array of int
+ *
+ * @return A sub matrix from Matrix a
+ */
+ @FunctionSpec(name = "unique", returnType = "array of int", formalParameters = { "array of int" })
+ public static long[] unique(final long[] data) {
+ Set set = new HashSet(Longs.asList(data));
+ final Long[] result = set.toArray(new Long[data.length]);
+ return ArrayUtils.toPrimitive(result);
+ }
+
+ /**
+ * Returns the matrix version of an array.
+ *
+ * @param a
+ * An array of array of int
+ *
+ * @return A sub matrix from Matrix a
+ */
+ @FunctionSpec(name = "getRow", returnType = "array of float", formalParameters = { "array of array of float", "int" })
+ public static double[] getRow(final double[][] data, final long row) {
+ return data[(int)row];
+ }
+
+ /**
+ * Returns the matrix version of an array.
+ *
+ * @param a
+ * An array of array of int
+ *
+ * @return A sub matrix from Matrix a
+ */
+ @FunctionSpec(name = "getCol", returnType = "array of int", formalParameters = { "array of array of int", "int" })
+ public static long[] getCol(final long[][] data, final long col) {
+ long[] result = new long[data[0].length];
+ for(int i = 0; i < data[0].length; i++ ) {
+ result[i] = data[i][(int)col];
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns the matrix version of an array.
+ *
+ * @param a
+ * An array of array of int
+ *
+ * @return A sub matrix from Matrix a
+ */
+ @FunctionSpec(name = "getRow", returnType = "array of int", formalParameters = { "array of array of int", "int" })
+ public static long[] getRow(final long[][] data, final int row) {
+ return data[row];
+ }
+
+
+ /**
+ * Returns the matrix version of an array. Only scalar values can be sorted.
+ * Values will be arranged in increasing order. (An optional comparison
+ * function, which takes two elements and returns int {-,0,+}, is accepted
+ * as a second argument, but it is curently ignored.)
+ *
+ * @param a
+ * An array of long
+ *
+ * @return A sorted copy of a
+ */
+ @FunctionSpec(name = "meanScaling", returnType = "array of array of float", formalParameters = { "array of array of float", "array of float" })
+ public static double[][] meanScaling(final double[][] a, final double[] b) {
+ for(int i = 0; i < a.length; i++) {
+ for(int j = 0; j < a[i].length; j++) {
+ a[i][j] = a[i][j] - b[j];
+ }
+ }
+ Matrix a_matrix = new Matrix(a);
+ return a_matrix.getArray();
+ }
+
+
+
+}
diff --git a/src/java/boa/functions/BoaSpecialIntrinsics.java b/src/java/boa/functions/BoaSpecialIntrinsics.java
index 87f92f541..2ecf01933 100644
--- a/src/java/boa/functions/BoaSpecialIntrinsics.java
+++ b/src/java/boa/functions/BoaSpecialIntrinsics.java
@@ -16,6 +16,8 @@
*/
package boa.functions;
+import boa.BoaTup;
+
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
@@ -141,6 +143,45 @@ public static String[] newBoolean(String[] a, long size, String val) {
return arr;
}
+ @FunctionSpec(name = "new", returnType = "array of array of float", formalParameters = { "array of array of float", "int", "array of float" })
+ public static double[][] newTuple(double[][] a, long size, double[] val) {
+ double[][] arr = new double[(int)size][];
+ for (int i = 0; i < size; i++)
+ arr[i] = val;
+ return arr;
+ }
+
+ @FunctionSpec(name = "new", returnType = "array of tuple", formalParameters = { "array of tuple", "int" })
+ public static T[] newTuple(T[] a, long size) {
+ Object[] arr = new Object[(int)size];
+ for (int i = 0; i < size; i++)
+ arr[i] = null;
+ return (T[]) arr;
+ }
+
+ @FunctionSpec(name = "new", returnType = "array of array of array of float", formalParameters = { "array of array of array of float", "int", "array of array of float" })
+ public static double[][][] newTuple(double[][][] a, long size, double[][] val) {
+ double[][][] arr = new double[(int)size][][];
+ for (int i = 0; i < size; i++)
+ arr[i] = val;
+ return arr;
+ }
+
+
+ @FunctionSpec(name = "print", returnType = "bool", formalParameters = { "any"})
+ public static boolean print(HashMap a) {
+ for (Object k: a.keySet()) {
+ System.out.println(k);
+ }
+ return true;
+ }
+
+ @FunctionSpec(name = "printany", returnType = "int", formalParameters = { "any"})
+ public static boolean print(Object a) {
+ System.out.println("nitin: " + a);
+ return true;
+ }
+
public static String regex(final String type, final long base) {
if (BoaSpecialIntrinsics.regexMap.containsKey(type + "," + base))
return BoaSpecialIntrinsics.regexMap.get(type + "," + base);
@@ -154,4 +195,18 @@ public static String regex(final String type) {
else
throw new RuntimeException("unimplemented");
}
+
+ @FunctionSpec(name = "convertFloatArrayToInt", returnType = "array of int", formalParameters = { "array of float" })
+ public static long[] convertFloatArrayToInt(final double[] inp) {
+ long[] converted = new long[inp.length];
+ for(int i = 0; i < inp.length; i++) {
+ converted[i] = Math.round(inp[i]);
+ }
+ return converted;
+ }
+
+ @FunctionSpec(name = "roundToLong", returnType = "int", formalParameters = { "float" })
+ public static long roundToLong(final double inp) {
+ return Math.round(inp);
+ }
}
diff --git a/src/java/boa/io/EmitValue.java b/src/java/boa/io/EmitValue.java
index 8f324ded4..148dce6f6 100644
--- a/src/java/boa/io/EmitValue.java
+++ b/src/java/boa/io/EmitValue.java
@@ -19,12 +19,15 @@
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.io.ObjectInputStream;
import java.util.Arrays;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import boa.functions.BoaCasts;
+import boa.BoaTup;
/**
* A {@link Writable} that contains a datum and an optional metadatum to be
@@ -36,6 +39,8 @@
public class EmitValue implements Writable {
private String[] data;
private String metadata;
+ private String[] odata;
+ private BoaTup tdata;
/**
* Construct an EmitValue.
@@ -233,6 +238,85 @@ public EmitValue(final double data, final double metadata) {
this(new String[] { BoaCasts.doubleToString(data) }, BoaCasts.doubleToString(metadata));
}
+ /**
+ * Construct an EmitValue.
+ *
+ * @param data
+ * A {@link BoaTup} containing the data to be emitted
+ * @param metadata
+ * A {@link String} containing the metadata to be emitted
+ */
+ public EmitValue(final BoaTup data, final String metadata) {
+ this.tdata = data;
+ }
+
+ /**
+ * Construct an EmitValue.
+ *
+ * @param data
+ * A {@link BoaTup} containing the data to be emitted
+ */
+ public EmitValue(final BoaTup data) {
+ this(data, null);
+ }
+
+
+ /**
+ * Construct an EmitValue.
+ *
+ * @param data
+ * An array of {@link double} containing the data to be emitted
+ * @param metadata
+ * A {@link String} containing the metadata to be emitted
+ */
+ public EmitValue(final double[] data, final String metadata) {
+ final String[] strings = new String[data.length];
+
+ for (int i = 0; i < data.length; i++)
+ strings[i] = String.valueOf(data[i]);
+
+ this.data = strings;
+ this.metadata = metadata;
+ }
+
+ /**
+ * Construct an EmitValue.
+ *
+ * @param data
+ * An array of {@link double} containing the data to be emitted
+ */
+ public EmitValue(final double[] data) {
+ this(data, null);
+ }
+
+ /**
+ * Construct an EmitValue.
+ *
+ * @param data
+ * An array of {@link long} containing the data to be emitted
+ * @param metadata
+ * A {@link String} containing the metadata to be emitted
+ */
+ public EmitValue(final long[] data, final String metadata) {
+ final String[] strings = new String[data.length];
+
+ for (int i = 0; i < data.length; i++)
+ strings[i] = String.valueOf(data[i]);
+
+ this.data = strings;
+ this.metadata = metadata;
+ }
+
+ /**
+ * Construct an EmitValue.
+ *
+ * @param data
+ * An array of {@link long} containing the data to be emitted
+ */
+ public EmitValue(final long[] data) {
+ this(data, null);
+ }
+
/** {@inheritDoc} */
@Override
public void readFields(final DataInput in) throws IOException {
@@ -247,20 +331,46 @@ public void readFields(final DataInput in) throws IOException {
this.metadata = null;
else
this.metadata = metadata;
+
+ final int length = in.readInt();
+ if(length > 0) {
+ byte[] bytes = new byte[length];
+ in.readFully(bytes, 0, length);
+ ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
+ ObjectInputStream dataIn = new ObjectInputStream(bin);
+ Object o = null;
+ try {
+ o = dataIn.readObject();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ this.tdata = (BoaTup)o;
+ }
}
/** {@inheritDoc} */
@Override
public void write(final DataOutput out) throws IOException {
- out.writeInt(this.data.length);
-
- for (final String d : this.data)
- Text.writeString(out, d);
+ if(this.data == null)
+ out.writeInt(0);
+ else {
+ out.writeInt(this.data.length);
+ for (final String d : this.data)
+ Text.writeString(out, d);
+ }
if (this.metadata == null)
Text.writeString(out, "");
else
Text.writeString(out, this.metadata);
+
+ if (this.tdata == null)
+ out.writeInt(0);
+ else {
+ byte[] serializedObject = this.tdata.serialize(this.tdata);
+ out.writeInt(serializedObject.length);
+ out.write(serializedObject);
+ }
}
/**
@@ -285,6 +395,10 @@ public String getMetadata() {
return this.metadata;
}
+ public BoaTup getTuple() {
+ return this.tdata;
+ }
+
/**
* @param metadata
* the metadatum to set
diff --git a/src/java/boa/runtime/BoaCombiner.java b/src/java/boa/runtime/BoaCombiner.java
index 81d131e10..e7d6c30ea 100644
--- a/src/java/boa/runtime/BoaCombiner.java
+++ b/src/java/boa/runtime/BoaCombiner.java
@@ -95,8 +95,12 @@ protected void reduce(final EmitKey key, final Iterable values, final
for (final EmitValue value : values)
try {
- for (final String s : value.getData())
- a.aggregate(s, value.getMetadata());
+ if(value.getTuple() != null) {
+ a.aggregate(value.getTuple(), value.getMetadata());
+ } else {
+ for (final String s : value.getData())
+ a.aggregate(s, value.getMetadata());
+ }
} catch (final FinishedException e) {
// we are done
return;
diff --git a/src/java/boa/runtime/BoaReducer.java b/src/java/boa/runtime/BoaReducer.java
index 103249343..efa192cad 100644
--- a/src/java/boa/runtime/BoaReducer.java
+++ b/src/java/boa/runtime/BoaReducer.java
@@ -87,8 +87,13 @@ protected void reduce(final EmitKey key, final Iterable values, final
for (final EmitValue value : values)
try {
- for (final String s : value.getData())
- a.aggregate(s, value.getMetadata());
+ if(value.getTuple() != null) {
+ a.aggregate(value.getTuple(), value.getMetadata());
+ }else{
+ for (final String s : value.getData())
+ a.aggregate(s, value.getMetadata());
+ }
+
} catch (final FinishedException e) {
// we are done
return;
diff --git a/src/test/boa/test/compiler/TestTraversalBad.java b/src/test/boa/test/compiler/TestTraversalBad.java
index 1696db43a..36c62b31e 100644
--- a/src/test/boa/test/compiler/TestTraversalBad.java
+++ b/src/test/boa/test/compiler/TestTraversalBad.java
@@ -37,6 +37,6 @@ public void traversalWithStop() throws IOException {
@Test
public void traversalWithNoReturn() throws IOException {
- codegen(load(badDir + "traverse-with-no-return-statement.boa"), "Error on line 134: missing return statement");
+ codegen(load(badDir + "traverse-with-no-return-statement.boa"), "Error on line 135: missing return statement");
}
}
diff --git a/src/test/boa/test/compiler/TestTypecheckBad.java b/src/test/boa/test/compiler/TestTypecheckBad.java
index ae81e894d..adfa9acfe 100644
--- a/src/test/boa/test/compiler/TestTypecheckBad.java
+++ b/src/test/boa/test/compiler/TestTypecheckBad.java
@@ -88,16 +88,16 @@ public void currentBadType() throws IOException {
@Test
public void complexArray1() throws IOException {
- typecheck(load(badDir + "complex-arrays.boa"), "non-scalar/non-tuple type 'set of int' can not be used in arrays");
+ typecheck(load(badDir + "complex-arrays.boa"), "No emit statements detected - there will be no output generated");
}
@Test
public void complexArray2() throws IOException {
- typecheck(load(badDir + "complex-arrays2.boa"), "non-scalar/non-tuple type 'stack of int' can not be used in arrays");
+ typecheck(load(badDir + "complex-arrays2.boa"), "No emit statements detected - there will be no output generated");
}
@Test
public void complexArray3() throws IOException {
- typecheck(load(badDir + "complex-arrays3.boa"), "non-scalar/non-tuple type 'map[string] of int' can not be used in arrays");
+ typecheck(load(badDir + "complex-arrays3.boa"), "No emit statements detected - there will be no output generated");
}
}
diff --git a/templates/BoaJava.stg b/templates/BoaJava.stg
index 3dd98c3e6..2834831db 100644
--- a/templates/BoaJava.stg
+++ b/templates/BoaJava.stg
@@ -124,25 +124,83 @@ new ()
>>
TupleType(name, fields, types) ::= <<
-private class
+ static class implements boa.BoaTup, java.io.Serializable
{
___}; separator="; ">;
( ___}; separator=", "> ){
- = new (___)}; separator="; ">;
+ = (___)}; separator="; ">;
}
( tmp){
- = new (tmp.___)}; separator="; ">;
+ = (tmp.___)}; separator="; ">;
}
public clone() {
return new (this);
}
+
+ public byte[] serialize(Object o) throws java.io.IOException {
+ java.io.ByteArrayOutputStream byteOutStream = new java.io.ByteArrayOutputStream();
+ java.io.ObjectOutputStream objectOut = new java.io.ObjectOutputStream(byteOutStream);
+ objectOut.writeObject(o);
+ objectOut.close();
+ return byteOutStream.toByteArray();
+ }
+
+ public static deSerialize(String serializedObject) throws java.io.IOException {
+ obj = null;
+ try {
+ byte b[] = serializedObject.getBytes();
+ java.io.ByteArrayInputStream bi = new java.io.ByteArrayInputStream(b);
+ java.io.ObjectInputStream si = new java.io.ObjectInputStream(bi);
+ obj = () si.readObject();
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ return obj;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ result.append("{");
+ for(String str: getValues()) {
+ result.append(str).append(", ");
+ }
+ result.deleteCharAt(result.length() - 1);
+ result.deleteCharAt(result.length() - 1);
+ result.append("}");
+ return result.toString();
+ }
+
+ public String[] getValues() {
+ return new String[] {)}; separator=", "> };
+ }
+
+ public String[] getFieldNames() {
+ return new String[] {"}; separator=", "> };
+ }
+
+ public Object getValue(String f) {
+ "))
+ return ___;
+ }; separator=" ">
+ return "empty";
+ }
+
+ @Override
+ public \ T[] asArray(T[] type) {
+ java.util.List\ _temp = new java.util.ArrayList\();
+ );}; separator="\n">
+ return _temp.toArray(type);
+ }
+
}<\n>
>>
Tuple(name, exprlist) ::= "new () <\n>"
EnumType(ename, fields, values, fname) ::= <<
-private enum
+private enum implements boa.BoaEnumInterface
{
()}; separator=", ">;
diff --git a/templates/BoaJavaHadoop.stg b/templates/BoaJavaHadoop.stg
index 156e8fa20..ea983f342 100644
--- a/templates/BoaJavaHadoop.stg
+++ b/templates/BoaJavaHadoop.stg
@@ -1,6 +1,8 @@
-Program(name, numreducers, jobs, jobnames, combineTables, reduceTables, splitsize, isLocal) ::= <<
+Program(name, numreducers, jobs, jobnames, combineTables, reduceTables, splitsize, isLocal, userDeclAgg) ::= <<
package boa;
+<\n>}>
+
public class extends boa.runtime.BoaRunner {
/** {@inheritDoc} */
@Override
@@ -171,14 +173,14 @@ public class extends boa.runtime.BoaRunner {
static class BoaCombiner extends boa.runtime.BoaCombiner {
public BoaCombiner() {
super();
-
+ <\n>}>
<\n>}> }
}
static class BoaReducer extends boa.runtime.BoaReducer {
public BoaReducer() {
super();
-
+ <\n>}>
<\n>}> }
}
@@ -200,7 +202,7 @@ public class extends boa.runtime.BoaRunner {
>>
Job(name, staticDeclarations, staticStatements, statements) ::= <<
-private static class Job implements BoaJob {
+ static class Job implements BoaJob {
{
diff --git a/templates/UserAggregatorClass.stg b/templates/UserAggregatorClass.stg
new file mode 100644
index 000000000..228d2eef4
--- /dev/null
+++ b/templates/UserAggregatorClass.stg
@@ -0,0 +1,74 @@
+AggregatorClass(funcName, funcArg, lambdaType, lambdaName, interface, lambdaInit, methods, aggParams, constcode) ::= <<
+class UserDefined$ extends boa.aggregators.UserDefinedAggregator {
+ java.util.List\<\> _$values;
+ <";">}>
+ ;
+
+
+
+ private
+
+ public
+
+ UserDefined$() {
+ = ;
+ }
+
+
+ public UserDefined$
+
+
+}
+>>
+
+OverridenMethods(name, type, nonPrimitive, parser, javaPrimitiveType, returnType) ::= <<
+ @Override
+ public void aggregate(String data, String metadata) throws java.io.IOException,java.lang.InterruptedException, boa.aggregators.FinishedException {
+
+ this._$values.add(.deSerialize(data));
+
+ this._$values.add((data));
+
+ }
+
+
+
+ @Override
+ public void aggregate( data, String metadata) throws java.io.IOException,java.lang.InterruptedException, boa.aggregators.FinishedException {
+ this._$values.add((data));
+ }
+
+ @Override
+ public void aggregate( data) throws java.io.IOException,java.lang.InterruptedException, boa.aggregators.FinishedException {
+ aggregate(data);
+ }
+
+
+ @Override
+ public void finish() throws java.io.IOException, java.lang.InterruptedException {
+ try{
+
+ result = .invoke(this._$values.toArray(new [this._$values.size()]));
+
+ result = .invoke(org.apache.commons.lang.ArrayUtils.toPrimitive(this._$values.toArray(new [this._$values.size()])));
+
+ this.collect(result);
+ super.store(result);
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void start(final boa.io.EmitKey key) {
+ _$values = new java.util.ArrayList\<\>();
+ super.start(key);
+ }
+
+
+ @Override
+ public void aggregate(BoaTup data, String metadata) throws java.io.IOException, java.lang.InterruptedException, boa.aggregators.FinishedException {
+ this._$values.add(()data);
+ }
+
+>>
\ No newline at end of file
diff --git a/test/datagen/datagen.iml b/test/datagen/datagen.iml
new file mode 100644
index 000000000..60c83f1fd
--- /dev/null
+++ b/test/datagen/datagen.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/lda.boa b/test/lda.boa
new file mode 100644
index 000000000..270f92e3f
--- /dev/null
+++ b/test/lda.boa
@@ -0,0 +1,152 @@
+# Counting the 10 most used programming languages
+p: Project = input;
+counts: output top(10) of string weight int;
+astCount: int = 0;
+type fv = {a:float, b:float, c:float, d:float};
+type sol = {eigenvals: array of float, eigenvectors: array of array of float};
+
+
+lda:= function(vals: array of fv): array of float {
+ dataset : array of array of float = submatrix(flattenedMatrix(vals, 4), 0, len(vals) -1, 0, 2);
+ labels: array of float = getCol(flattenedMatrix(vals, 4), 3);
+ uniqueLables: array of int = convertFloatArrayToInt(unique(labels));
+
+
+ dummy: array of array of float = {{0.0, 0.0, 0.0}};
+ classified: array of array of array of float; #
+ classified = new(classified, len(uniqueLables), dummy);
+ foreach(i:int; abs(uniqueLables[i])) {
+ if(def(classified) && def(classified[roundToLong(labels[i])])) {
+ classified[roundToLong(labels[i])] = classified[roundToLong(labels[i])] + {dataset[i]};
+ } else if(def(classified)) {
+ classified[roundToLong(labels[i])] = {dataset[i]};
+ }
+ }
+
+
+ # calculate group mean
+ groupmeans : array of array of float;
+ groupmeans = new(groupmeans, len(uniqueLables), {0.0, 0.0, 0.0});
+ foreach(i: int; groupmeans[i]) {
+ foreach(j:int; def(classified[i][j])) {
+ groupmeans[i][0] = classified[i][j][0];
+ groupmeans[i][1] = classified[i][j][1];
+ groupmeans[i][2] = classified[i][j][2];
+ }
+ size : int = len(classified[i]);;
+ groupmeans[i][0] = groupmeans[i][0] / size;
+ groupmeans[i][1] = groupmeans[i][1] / size;
+ groupmeans[i][2] = groupmeans[i][2] / size;
+ }
+
+ # calculate global means
+ globalMean : array of float;
+ globalMean = new(globalMean, 3, 0.0);
+ foreach(j : int; dataset[j]) {
+ globalMean[0] = globalMean[0] + dataset[j][0];
+ globalMean[1] = globalMean[1] + dataset[j][1];
+ globalMean[2] = globalMean[2] + dataset[j][2];
+ }
+
+ globalMean[0] = globalMean[0] / len(dataset);
+ globalMean[1] = globalMean[1] / len(dataset);
+ globalMean[2] = globalMean[2] / len(dataset);
+
+
+ # correct subset data
+ foreach(i:int; def(classified[i])) {
+ foreach(j:int; classified[i][j]) {
+ classified[i][j][0] = classified[i][j][0] - globalMean[0];
+ classified[i][j][1] = classified[i][j][1] - globalMean[1];
+ classified[i][j][2] = classified[i][j][2] - globalMean[2];
+ }
+ }
+
+ # calculate covariance
+ covariance : array of array of array of float;
+ covariance = new(covariance, len(uniqueLables), {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}});
+ foreach(i:int; uniqueLables[i]) {
+ foreach(j:int; covariance[i][j]) {
+ foreach(l:int; classified[l]) {
+ covariance[i][j][0] = covariance[i][j][0] + classified[i][l][j] * classified[i][l][0];
+ covariance[i][j][1] = covariance[i][j][1] + classified[i][l][j] * classified[i][l][1];
+ covariance[i][j][2] = covariance[i][j][2] + classified[i][l][j] * classified[i][l][2];
+ }
+ covariance[i][j][0] = covariance[i][j][0] / len(classified[i]);
+ covariance[i][j][1] = covariance[i][j][1] / len(classified[i]);
+ covariance[i][j][2] = covariance[i][j][2] / len(classified[i]);
+ }
+ }
+
+ # calculate pooled within group covariance matrix and invert it
+ pooledInverseCovariance : array of array of float;
+ pooledInverseCovariance = new(pooledInverseCovariance, len(uniqueLables), {0.0,0.0,0.0});
+ totalData: int = len(dataset);
+ foreach(j:int; pooledInverseCovariance[j]){
+ foreach(l:int; uniqueLables[l]) {
+ pooledInverseCovariance[j][0] = pooledInverseCovariance[j][0] + len(classified[l]) / totalData * covariance[l][j][0];
+ pooledInverseCovariance[j][1] = pooledInverseCovariance[j][1] + len(classified[l]) / totalData * covariance[l][j][1];
+ pooledInverseCovariance[j][2] = pooledInverseCovariance[j][2] + len(classified[l]) / totalData * covariance[l][j][2];
+ }
+ }
+
+ #TODO inverse the pooledInverseCovariance
+
+ probability: array of float;
+ probability = new(probability, len(uniqueLables), 0.0);
+
+ return probability;
+};
+
+ldaAgg: output lda of fv;
+
+visit(p, visitor {
+ # only look at the latest snapshot
+ before n: CodeRepository -> {
+ snapshot := getsnapshot(n);
+ foreach (i: int; def(snapshot[i]))
+ visit(snapshot[i]);
+ stop;
+ }
+ before node: Declaration -> {
+ if (node.kind == TypeKind.CLASS) {
+ public_ele : float = 0.0;
+ protected_ele : float = 0.0;
+ private_ele : float = 0.0;
+ other: float = 0.0;
+ foreach (i: int; def(node.methods[i])) {
+ if(has_modifier_public(node.methods[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.methods[i])) {
+ private_ele = private_ele + 1;
+ } else if(has_modifier_protected(node.methods[i])) {
+ protected_ele = protected_ele + 1;
+ } else {
+ other = other + 1;
+ }
+ }
+
+ foreach (i: int; def(node.fields[i])) {
+ if(has_modifier_public(node.fields[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.fields[i])) {
+ private_ele = private_ele + 1;
+ } else if(has_modifier_protected(node.fields[i])) {
+ protected_ele = protected_ele + 1;
+ }else {
+ other = other + 1;
+ }
+ }
+
+ feature1 : fv = {public_ele, private_ele, protected_ele, other};
+ ldaAgg << feature1;
+ ldaAgg << feature1;
+ ldaAgg << feature1;
+ ldaAgg << feature1;
+ ldaAgg << feature1;
+ ldaAgg << feature1;
+ ldaAgg << feature1;
+ ldaAgg << feature1;
+ }
+ }
+});
\ No newline at end of file
diff --git a/test/ml/demo_neural/neural.boa b/test/ml/demo_neural/neural.boa
new file mode 100644
index 000000000..662981499
--- /dev/null
+++ b/test/ml/demo_neural/neural.boa
@@ -0,0 +1,231 @@
+p: Project = input;
+testing : output sum of int;
+
+type Connection = {cweight : float, prevDeltaWeight : float, deltaWeight : float, leftNeuron : int, rightNeuron : int};
+type Neuron = {id: int, bias : float , outputVal : float, biasConnection : Connection, inConnection : array of Connection};
+type emitvals = {inp:array of float, expected: array of float};
+
+type Model = {inputL: array of Neuron, hiddenL: array of Neuron, outputL: array of Neuron, neuronMap : map[int] of Neuron};
+
+nueralNetworks := function(vals : array of emitvals, test123: float, test56: float) : Model {
+ runs : int = 500;
+ id_counter : int = 0;
+
+ dummyConnection: Connection = {-1.0, -1.0, -1.0, -1, -1};
+ dummyConnArray : array of Connection = {dummyConnection};
+
+ biasNeuron : Neuron = {id_counter, 0.0, 0.0, dummyConnection, dummyConnArray};
+ dummyArray : array of float = {0.0};
+ resultOutputs: array of array of float;
+ resultOutputs = new(resultOutputs, len(vals), dummyArray);
+
+ learningRate : float = 0.9;
+ momentum : float = 0.7;
+ layers : array of int = {2, 4, 1};
+ totalLayers := len(layers); # intputLayer = 0, hiddenLayer = 1; outputLayer = 2
+
+
+ inputLayer : array of Neuron = {biasNeuron, biasNeuron};
+ hiddenLayer : array of Neuron = {biasNeuron, biasNeuron, biasNeuron, biasNeuron};
+ outputLayer : array of Neuron = {biasNeuron};
+ neuronRecorder : map[int] of Neuron;
+
+ neuronRecorder[id_counter] = biasNeuron;
+ id_counter = id_counter + 1;
+ epsilon : float = 0.00000000001;
+
+
+ for(i :int = 1; i < totalLayers; i++) {
+ # input layer
+ if(i == 0) {
+ for(s :int = 0; s < layers[i]; s++) {
+ inputLayer[s] = {id_counter, 0.0, 0.0, dummyConnection, dummyConnArray};
+ neuronRecorder[id_counter] = inputLayer[s];
+ id_counter = id_counter + 1;
+ }
+ }
+ # hidden layer
+ if(i == 1) {
+ for(z :int = 0; z < layers[i]; z++) {
+ cons : array of Connection = {dummyConnection, dummyConnection};
+ #cons = new(cons, layers[0], dummyConnection);
+ node : Neuron = {id_counter, 0.0, 0.0, dummyConnection, cons};
+
+ # add connections
+ foreach(k: int; def(inputLayer[k])) {
+ localConnection: Connection = {rand(), 0.0, 0.0, inputLayer[k].id, node.id}; # assigns random connweight to the connection
+ node.inConnection[k] = localConnection;
+ }
+ neuronRecorder[id_counter] = node;
+ id_counter++;
+
+ #addInConnection(node, inputLayer);
+ hiddenLayer[z] = node;
+ }
+ }
+ # output layer
+ if(i == 2) {
+ for(j :int = 0; j < layers[i]; j++) {
+ cons1 : array of Connection = {dummyConnection, dummyConnection, dummyConnection, dummyConnection};
+ #cons1 = new(cons1, layers[1]);
+ node1 : Neuron = {id_counter, 0.0, 0.0, dummyConnection, cons1};
+
+ # add connections
+ foreach(k: int; def(hiddenLayer[k])) {
+ con1 : Connection = {rand(), 0.0, 0.0, hiddenLayer[k].id, node1.id}; # assigns random connweight to the connection
+ node1.inConnection[k] = con1;
+ }
+
+ neuronRecorder[id_counter] = node1;
+ id_counter++;
+ #addInConnection(node, hiddenLayer);
+ outputLayer[j] = node1;
+ }
+ }
+
+ }
+
+
+ error : float = 1.0;
+ for(m: int = 0; m < runs; m++) {
+ error = 0;
+ foreach(n : int; def(vals[n])) {
+ valueEmitted: emitvals = vals[n];
+ # set the input variables for jth value from values
+ foreach(k: int; def(inputLayer[k])) {
+ # there is one to one mapping in input neurons and number of features in each value
+ d: float = vals[n].inp[k];
+ inputLayer[k].outputVal = d;
+ }
+
+ # activate the neurons for the forward propagation
+ # calculate the output of each hiddenLayer Neuron
+ foreach(k : int; def(hiddenLayer[k])) {
+ node2: Neuron = hiddenLayer[k];
+ intermediateResult : float = 0.0;
+ connections :array of Connection = node2.inConnection;
+ foreach(l: int; def(connections[l])) {
+ left: Neuron = neuronRecorder[connections[l].leftNeuron];
+ connweight : float = connections[l].cweight;
+ intermediateResult = intermediateResult + (connweight * left.outputVal);
+ }
+ intermediateResult = intermediateResult + (node2.biasConnection.cweight * node2.bias);
+ node2.outputVal = 1.0 / (1.0 + exp(intermediateResult));
+ #calculateOutput(hiddenLayer[i]);
+ }
+ # calculate the output of each outputLayer Neuron
+ foreach(k : int; def(outputLayer[k])) {
+ node3:Neuron = outputLayer[k];
+ intermediateResult1 : float = 0.0;
+ connections1 :array of Connection = node3.inConnection;
+ foreach(l: int; def(connections1[l])) {
+ left1: Neuron = neuronRecorder[connections1[l].leftNeuron];
+ connweight1 : float = connections1[l].cweight;
+ intermediateResult1 = intermediateResult1 + (connweight1 * left1.outputVal);
+ }
+ intermediateResult1 = intermediateResult1 + (node3.biasConnection.cweight * node3.bias);
+ node3.outputVal = 1.0 / (1.0 + exp(intermediateResult1));
+ #calculateOutput(outputLayer[i]);
+ }
+
+ # output results of each loop
+ outputR : array of float;
+ outputR = new(outputR, len(outputLayer), 0);
+ foreach(l: int; def(outputLayer[l])) {
+ outputR[l] = outputLayer[l].outputVal;
+ }
+
+ resultOutputs[n] = outputR;
+
+ #calculate error
+ expectations :array of float = vals[n].expected;
+ foreach(l: int; def(expectations[l])) {
+ err : float = pow(outputR[l]- vals[n].expected[l], 2);
+ error = error + err;
+ }
+
+ # back propogration fpr expectations
+ #update output layer
+ outNodeCounter : int = 0;
+ foreach(o: int; def(outputLayer[o])) {
+ foreach(connNo: int; def(outputLayer[o].inConnection[connNo])) {
+ nodeConnection : Connection = outputLayer[o].inConnection[connNo];
+ ak: float = outputLayer[o].outputVal;
+ temp : Neuron = neuronRecorder[nodeConnection.leftNeuron];
+ ai: float = temp.outputVal;
+ desiredOut: float = expectations[outNodeCounter];
+ partialDerivative : float = (-1 * ak) * (1 - ak) * ai * (desiredOut - ak);
+ deltaWeightNew : float = (-1 * learningRate) * partialDerivative;
+ newWeight: float = nodeConnection.cweight + deltaWeightNew;
+ nodeConnection.deltaWeight = deltaWeightNew;
+ nodeConnection.cweight = newWeight + momentum * nodeConnection.prevDeltaWeight;
+ }
+ outNodeCounter = outNodeCounter + 1;
+ }
+
+
+ #update hidden layer
+ foreach(h: int; def(hiddenLayer[h])) {
+ hiddenconnections : array of Connection = hiddenLayer[h].inConnection;
+ foreach(connNo: int; def(hiddenconnections[connNo])) {
+ aj: float = hiddenLayer[h].outputVal;
+ targetNeuron : Neuron = neuronRecorder[hiddenconnections[connNo].leftNeuron];
+ aih: float = targetNeuron.outputVal;
+ sumKoutputs : float = 0.0;
+ jindex : int = 0;
+ foreach(o: int; def(outputLayer[o])) {
+ wjk : float = 0.0;
+ allInConns: array of Connection = outputLayer[o].inConnection;
+ foreach(conid: int; def(allInConns[conid])) {
+ if(allInConns[conid].leftNeuron == hiddenLayer[h].id) {
+ wjk = allInConns[conid].cweight;
+ }
+ }
+ desiredOutput: float = expectations[jindex];
+ akh:float = outputLayer[o].outputVal;
+ jindex = jindex + 1;
+ sumKoutputs = sumKoutputs + (-1 * (desiredOutput - akh) * akh * (1 - akh) * wjk);
+ }
+ partialDerivative_: float = aj * (1 - aj) * aih * sumKoutputs;
+ dWeight: float = (-1 * learningRate) * partialDerivative_;
+ newWeight1: float = hiddenconnections[connNo].cweight + dWeight;
+ hiddenconnections[connNo].deltaWeight = dWeight;
+ hiddenconnections[connNo].cweight = newWeight1+ momentum * hiddenconnections[connNo].prevDeltaWeight;
+ }
+ outNodeCounter = outNodeCounter + 1;
+ }
+
+ }
+ }
+ #return outputLayer[0].outputVal;
+ model : Model = {inputLayer, hiddenLayer, outputLayer, neuronRecorder};
+ return model;
+ };
+
+
+neuralNetwork : output nueralNetworks(0.001, 0.99) of emitvals;
+
+inps: array of float = {1.0, 1.0};
+out: array of float = {0.0};
+
+result: emitvals = {inps, out};
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
diff --git a/test/ml/demo_neural/neuralTest.boa b/test/ml/demo_neural/neuralTest.boa
new file mode 100644
index 000000000..a8e35ca0e
--- /dev/null
+++ b/test/ml/demo_neural/neuralTest.boa
@@ -0,0 +1,76 @@
+# What are the 5 largest projects, in terms of AST nodes?
+# Output is in Millions of AST nodes.
+p: Project = input;
+counter: output sum of int;
+
+
+type Connection = {cweight : float, prevDeltaWeight : float, deltaWeight : float, leftNeuron : int, rightNeuron : int};
+type Neuron = {id: int, bias : float , outputVal : float, biasConnection : Connection, inConnection : array of Connection};
+type emitvals = {inp:array of float, expected: array of float};
+type Model = {inputL: array of Neuron, hiddenL: array of Neuron, outputL: array of Neuron, neuronMap : map[int] of Neuron};
+
+
+############### dummy information about the model ###################
+
+dummyConnection: Connection = {-1.0, -1.0, -1.0, -1, -1};
+dummyConnArray : array of Connection = {dummyConnection};
+dummyNeuron : Neuron = {0, 0.0, 0.0, dummyConnection, dummyConnArray};
+dummyLayer : array of Neuron = {dummyNeuron};
+dummyMap: map[int] of Neuron;
+dummyModel : Model = {dummyLayer, dummyLayer, dummyLayer, dummyMap};
+
+############### dummy information ends ##############################
+
+results: output collection[string] of float;
+
+
+#loadedModel: Model = load("Neural.model", dummyModel);
+loadedModel: Model = load("./Neural/Neural.model", dummyModel);
+
+classification := function(model: Model, vals: array of float): float {
+ neuronRecorder : map[int] of Neuron = model.neuronMap;
+ # set the input variables for jth value from values
+ inputLayer := model.inputL;
+ outputLayer := model.outputL;
+ hiddenLayer := model.hiddenL;
+ foreach(k: int; def(inputLayer[k])) {
+ d: float = vals[k];
+ inputLayer[k].outputVal = d;
+ }
+
+# activate the neurons for the forward propagation
+ # calculate the output of each hiddenLayer Neuron
+ foreach(k : int; hiddenLayer[k]) {
+ node2: Neuron = hiddenLayer[k];
+ intermediateResult : float = 0.0;
+ connections :array of Connection = node2.inConnection;
+ foreach(l: int; def(connections[l])) {
+ left: Neuron = neuronRecorder[connections[l].leftNeuron];
+ connweight : float = connections[l].cweight;
+ intermediateResult = intermediateResult + (connweight * left.outputVal);
+ }
+ intermediateResult = intermediateResult + (node2.biasConnection.cweight * node2.bias);
+ node2.outputVal = 1.0 / (1.0 + exp(intermediateResult));
+ #calculateOutput(hiddenL[i]);
+ }
+ # calculate the output of each outputLayer Neuron
+ foreach(k : int; outputLayer[k]) {
+ node3:Neuron = outputLayer[k];
+ intermediateResult1 : float = 0.0;
+ connections1 :array of Connection = node3.inConnection;
+ foreach(l: int; def(connections1[l])) {
+ left1: Neuron = neuronRecorder[connections1[l].leftNeuron];
+ connweight1 : float = connections1[l].cweight;
+ intermediateResult1 = intermediateResult1 + (connweight1 * left1.outputVal);
+ }
+ intermediateResult1 = intermediateResult1 + (node3.biasConnection.cweight * node3.bias);
+ node3.outputVal = 1.0 / (1.0 + exp(intermediateResult1));
+ #calculateOutput(outputL[i]);
+ }
+ return outputLayer[0].outputVal;
+};
+
+#testInput : emitVals = {{0.0}, {1.1}};
+
+#results[p.id] << classification(loadedModel, testInput);
+results[p.id] << classification(loadedModel, {3.0, 0.3});
\ No newline at end of file
diff --git a/test/ml/lr.boa b/test/ml/lr.boa
new file mode 100644
index 000000000..8eddd728e
--- /dev/null
+++ b/test/ml/lr.boa
@@ -0,0 +1,93 @@
+# What are the 5 largest projects, in terms of AST nodes?
+# Output is in Millions of AST nodes.
+p: Project = input;
+counter: output sum[string][int] of int;
+collect3: output sum[int][int] of float;
+collect2: output sum[int][int] of float;
+collect4: output sum[int][int] of float;
+
+
+type fv = {pub:float, pri:float, pro:float, total:float};
+type sol = {pub_coff:float, pri_coff:float, pro_coff:float};
+
+
+
+lr := function(vals: array of fv): sol {
+ dataset : array of array of float = flattenedMatrix(vals, 4);
+ X : array of array of float = submatrix(dataset, 0, len(dataset)-1, 0, 2);
+ Y : array of array of float = transpose(getCol(dataset, 3));
+ X_trans : array of array of float = transpose(X);
+ A := inverse(multiply(X_trans, X));
+ B := multiply(X_trans, Y);
+ calculated : array of float = flatten(transpose(multiply(A, B)));
+ result : sol = {calculated[0], calculated[1], calculated[2]};
+ #result : sol = {len(X_trans)+0.0, len(X_trans[0])+ 0.0, len(Y) + 0.0};
+ return result;
+};
+
+lr_agg : output lr of fv;
+
+
+visit(p, visitor {
+ # only look at the latest snapshot
+ before n: CodeRepository -> {
+ snapshot := getsnapshot(n);
+ foreach (i: int; def(snapshot[i]))
+ visit(snapshot[i]);
+ stop;
+ }
+ before node: Declaration -> {
+ if (node.kind == TypeKind.CLASS) {
+ public_ele : int = 0;
+ protected_ele : int = 0;
+ private_ele : int = 0;
+ foreach (i: int; def(node.methods[i])) {
+ if(has_modifier_public(node.methods[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.methods[i])) {
+ private_ele = public_ele + 1;
+ } else {
+ protected_ele = protected_ele + 1;
+ }
+ }
+
+ foreach (i: int; def(node.fields[i])) {
+ if(has_modifier_public(node.fields[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.fields[i])) {
+ private_ele = public_ele + 1;
+ } else {
+ protected_ele = protected_ele + 1;
+ }
+ }
+
+ feature1 : fv = {public_ele + 0.0, private_ele + 0.0, protected_ele + 0.0, (public_ele + 0.0 + private_ele + protected_ele)};
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ lr_agg << feature1;
+ }
+ }
+});
+
diff --git a/test/ml/lrOptimized.boa b/test/ml/lrOptimized.boa
new file mode 100644
index 000000000..96891be2b
--- /dev/null
+++ b/test/ml/lrOptimized.boa
@@ -0,0 +1,86 @@
+# What are the 5 largest projects, in terms of AST nodes?
+# Output is in Millions of AST nodes.
+p: Project = input;
+counter: output sum of int;
+
+
+type fv = {pub:float, pri:float, pro:float};
+type mapped = {a: array of array of float, b: array of array of float};
+type sol = {pub_coff:float, pri_coff:float, pro_coff:float};
+
+
+
+lr := function(vals: array of mapped): sol {
+ result : sol;
+ #if (len(vals) > 0) {
+ vals_a :array of array of float = vals[0].a;
+ vals_b :array of array of float = vals[0].b;
+ foreach(i: int; def(vals[i])) {
+ vals_a = matrixsum(vals[i].a, vals_a);
+ vals_b = matrixsum(vals[i].b, vals_b);
+ }
+ vals_a = matrixsubstract(vals_a, vals[0].a);
+ vals_b = matrixsubstract(vals_b, vals[0].b);
+ calculated : array of float = flatten(transpose(multiply(inverse(vals_a), vals_b)));
+ result = {calculated[0], calculated[1], calculated[2]};
+ #}
+ return result;
+};
+
+lr_agg : output lr of fv;
+
+
+visit(p, visitor {
+ # only look at the latest snapshot
+ before n: CodeRepository -> {
+ snapshot := getsnapshot(n);
+ foreach (i: int; def(snapshot[i]))
+ visit(snapshot[i]);
+ stop;
+ }
+ before node: Declaration -> {
+ if (node.kind == TypeKind.CLASS) {
+ public_ele : int = 0;
+ protected_ele : int = 0;
+ private_ele : int = 0;
+ foreach (i: int; def(node.methods[i])) {
+ if(has_modifier_public(node.methods[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.methods[i])) {
+ private_ele = public_ele + 1;
+ } else {
+ protected_ele = protected_ele + 1;
+ }
+ }
+
+ foreach (i: int; def(node.fields[i])) {
+ if(has_modifier_public(node.fields[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.fields[i])) {
+ private_ele = public_ele + 1;
+ } else {
+ protected_ele = protected_ele + 1;
+ }
+ }
+
+ #feature1 : fv = {public_ele + 0.0, private_ele + 0.0, protected_ele + 0.0, (public_ele + 0.0 + private_ele + protected_ele)};
+ features : array of float = {public_ele + 0.0, private_ele + 0.0, protected_ele + 0.0};
+ label : array of float = {public_ele + 0.0 + private_ele + protected_ele};
+ X := {features};
+ Y := {label};
+ XTp := transpose(X);
+ cal1 : array of array of float = multiply(XTp, X);
+ cal2 : array of array of float = multiply(XTp, Y);
+ toEmit : mapped = {cal1, cal2};
+ count := 40;
+ while(count > 0) {
+ toEmit.a = matrixsum(toEmit.a, cal1);
+ toEmit.b = matrixsum(toEmit.b, cal2);
+ count = count - 1;
+ }
+ lr_agg << toEmit;
+ counter << 1;
+ }
+ }
+});
+
diff --git a/test/ml/naive.boa b/test/ml/naive.boa
new file mode 100644
index 000000000..53d78f143
--- /dev/null
+++ b/test/ml/naive.boa
@@ -0,0 +1,172 @@
+p: Project = input;
+type fv = {a:int, b:int, c:int, d:int};
+type stats = {a_stat:float, b_stat:float, c_stat:float};
+type complete_stat = {avg: stats, dev: stats};
+type Data = {training: fv, testing: fv};
+splitRatio : float = 0.67;
+
+naive := function(vals : array of Data) : float {
+ train : array of fv;
+ test : array of fv;
+
+ spearated: map[int] of array of fv; # classified per value
+ summaries : map[int] of complete_stat;
+
+ # separate the training and testing datasets
+ foreach(i:int; def(vals[i])) {
+ if(def(train)) {
+ train = train + {vals[i].training};
+ } else {
+ train = {vals[i].training};
+ }
+ if(def(test)) {
+ test = test+ {vals[i].testing};
+ } else {
+ test = {vals[i].testing};
+ }
+
+ }
+
+
+ # classify training datasets
+ foreach(i:int; def(train[i])) {
+ temp : array of fv = {train[i]};
+ if(!haskey(spearated, train[i].d)) {
+ spearated[train[i].d] = temp;
+ } else {
+ spearated[train[i].d] = spearated[train[i].d] + temp;
+ }
+ }
+
+ # all the classes
+ classes : array of int = keys(spearated);
+
+ # summarize data from training dataset
+ foreach(i:int; def(classes[i])) {
+ # calculate mean
+ feature_mean : stats = {0.0, 0.0, 0.0};
+ foreach(j:int; def(spearated[classes[i]][j])) {
+ feature_mean.a_stat = feature_mean.a_stat + spearated[classes[i]][j].a;
+ feature_mean.b_stat = feature_mean.b_stat + spearated[classes[i]][j].b;
+ feature_mean.c_stat = feature_mean.c_stat + spearated[classes[i]][j].c;
+ }
+ feature_mean.a_stat = feature_mean.a_stat / len(spearated[classes[i]]);
+ feature_mean.b_stat = feature_mean.b_stat / len(spearated[classes[i]]);
+ feature_mean.c_stat = feature_mean.c_stat / len(spearated[classes[i]]);
+
+
+ # calculate sd
+ feature_sd : stats = {0.0, 0.0, 0.0};
+ foreach(j:int; def(spearated[classes[i]][j])) {
+ feature_sd.a_stat = feature_sd.a_stat + (spearated[classes[i]][j].a - feature_mean.a_stat);
+ feature_sd.b_stat = feature_sd.b_stat + (spearated[classes[i]][j].b - feature_mean.b_stat);
+ feature_sd.c_stat = feature_sd.c_stat + (spearated[classes[i]][j].c - feature_mean.c_stat);
+ }
+ feature_sd.a_stat = sqrt(feature_sd.a_stat / len(spearated[classes[i]]));
+ feature_sd.b_stat = sqrt(feature_sd.b_stat / len(spearated[classes[i]]));
+ feature_sd.c_stat = sqrt(feature_sd.c_stat / len(spearated[classes[i]]));
+
+ # summarized a class
+ summaries[classes[i]] = {feature_mean, feature_sd};
+ }
+
+
+ predictions: array of int;
+ predictions = new(predictions, len(test), -1);
+
+ # predict for each test data
+ foreach(i:int; def(test[i])) {
+ probabilities : map[int] of float;
+ foreach(j: int; def(classes[j])) {
+ probabilities[classes[j]] = 1.0;
+ mean := summaries[classes[j]].avg;
+ deviation := summaries[classes[j]].dev;
+ probabilities[classes[j]] = probabilities[classes[j]] * (1/ (sqrt(2 * 3.14) * deviation.a_stat)) * (exp(-1 * ((pow((1.0 * test[i].a) - mean.a_stat, 2))/(2 * pow(deviation.a_stat, 2)))));
+ probabilities[classes[j]] = probabilities[classes[j]] * (1/ (sqrt(2 * 3.14) * deviation.a_stat)) * (exp(-1 * ((pow((1.0 * test[i].b) - mean.b_stat, 2))/(2 * pow(deviation.b_stat, 2)))));
+ probabilities[classes[j]] = probabilities[classes[j]] * (1/ (sqrt(2 * 3.14) * deviation.a_stat)) * (exp(-1 * ((pow((1.0 * test[i].c) - mean.c_stat, 2))/(2 * pow(deviation.c_stat, 2)))));
+ }
+
+ bestProb : float = 0;
+ bestLab : int = -1;
+ foreach(j: int; def(classes[j])) {
+ if ((bestLab == -1) || (bestProb < probabilities[classes[j]])) {
+ bestProb = probabilities[classes[j]];
+ bestLab = classes[j];
+ }
+ }
+ predictions[i] = bestLab;
+ }
+
+ correct : float = 0.0;
+ foreach(i:int; def(test[i])) {
+ if(predictions[i] == test[i].d) {
+ correct = correct + 1.0;
+ }
+ }
+ return correct/len(test) * 100;
+};
+
+scale := function(ast: int, method: int, class: int) : int {
+ total : int = 0;
+ if(ast > 1000) {
+ total++;
+ } if(method > 500) {
+ total++;
+ } if(class > 50) {
+ total++;
+ }
+ return total;
+};
+
+
+naive_bayes : output naive of Data;
+
+# count ast nodes
+
+astCount := 0;
+classCount := 0;
+methodCount := 0;
+visit(p, visitor {
+ # only look at the latest snapshot
+ before n: CodeRepository -> {
+ snapshot := getsnapshot(n);
+ foreach (i: int; def(snapshot[i]))
+ visit(snapshot[i]);
+ stop;
+ }
+ before node: Declaration -> {
+ if (node.kind == TypeKind.CLASS) {
+ classCount++;
+ foreach (i: int; node.methods[i]) {
+ methodCount++;
+ }
+ }
+ }
+ # by default, count all visited nodes
+ before _ -> astCount++;
+ # these nodes are not part of the AST, so do nothing when visiting
+ before Project, ChangedFile -> ;
+});
+
+
+
+dummy : fv = {0, 0, 0, 0};
+nondummy : fv = {astCount, methodCount, classCount, scale(astCount, methodCount, classCount)};
+data1: Data = {nondummy, dummy};
+data2: Data = {dummy, nondummy};
+if(rand() > splitRatio)
+ naive_bayes << data1;
+else
+ naive_bayes << data2;
+
+
+if(rand() > splitRatio)
+ naive_bayes << data1;
+else
+ naive_bayes << data2;
+
+
+if(rand() > splitRatio)
+ naive_bayes << data1;
+else
+ naive_bayes << data2;
diff --git a/test/ml/neural.boa b/test/ml/neural.boa
new file mode 100644
index 000000000..b68d0b8a4
--- /dev/null
+++ b/test/ml/neural.boa
@@ -0,0 +1,232 @@
+p: Project = input;
+testing : output sum of int;
+
+type Connection = {cweight : float, prevDeltaWeight : float, deltaWeight : float, leftNeuron : int, rightNeuron : int};
+type Neuron = {id: int, bias : float , outputVal : float, biasConnection : Connection, inConnection : array of Connection};
+type emitvals = {inp:array of float, expected: array of float};
+testing << 1;
+
+nueralNetworks := function(vals : array of emitvals) :float {
+ runs : int = 500;
+ thresholdError := 0.001;
+ id_counter : int = 0;
+
+ dummyConnection: Connection = {-1.0, -1.0, -1.0, -1, -1};
+ dummyConnArray : array of Connection = {dummyConnection};
+
+ biasNeuron : Neuron = {id_counter, 0.0, 0.0, dummyConnection, dummyConnArray};
+ dummyArray : array of float = {0.0};
+ resultOutputs: array of array of float;
+ resultOutputs = new(resultOutputs, len(vals), dummyArray);
+
+ learningRate : float = 0.9;
+ momentum : float = 0.7;
+ layers : array of int = {2, 4, 1};
+ totalLayers := len(layers); # intputLayer = 0, hiddenLayer = 1; outputLayer = 2
+
+
+ inputLayer : array of Neuron = {biasNeuron, biasNeuron};
+ hiddenLayer : array of Neuron = {biasNeuron, biasNeuron, biasNeuron, biasNeuron};
+ outputLayer : array of Neuron = {biasNeuron};
+ neuronRecorder : map[int] of Neuron;
+
+ neuronRecorder[id_counter] = biasNeuron;
+ id_counter = id_counter + 1;
+ epsilon : float = 0.00000000001;
+
+
+ for(i :int = 1; i < totalLayers; i++) {
+ # input layer
+ if(i == 0) {
+ for(s :int = 0; s < layers[i]; s++) {
+ inputLayer[s] = {id_counter, 0.0, 0.0, dummyConnection, dummyConnArray};
+ neuronRecorder[id_counter] = inputLayer[s];
+ id_counter = id_counter + 1;
+ }
+ }
+ # hidden layer
+ if(i == 1) {
+ for(z :int = 0; z < layers[i]; z++) {
+ cons : array of Connection = {dummyConnection, dummyConnection};
+ #cons = new(cons, layers[0], dummyConnection);
+ node : Neuron = {id_counter, 0.0, 0.0, dummyConnection, cons};
+
+ # add connections
+ foreach(k: int; def(inputLayer[k])) {
+ localConnection: Connection = {rand(), 0.0, 0.0, inputLayer[k].id, node.id}; # assigns random connweight to the connection
+ node.inConnection[k] = localConnection;
+ }
+ neuronRecorder[id_counter] = node;
+ id_counter++;
+
+ #addInConnection(node, inputLayer);
+ hiddenLayer[z] = node;
+ }
+ }
+ # output layer
+ if(i == 2) {
+ for(j :int = 0; j < layers[i]; j++) {
+ cons1 : array of Connection = {dummyConnection, dummyConnection, dummyConnection, dummyConnection};
+ #cons1 = new(cons1, layers[1]);
+ node1 : Neuron = {id_counter, 0.0, 0.0, dummyConnection, cons1};
+
+ # add connections
+ foreach(k: int; def(hiddenLayer[k])) {
+ con1 : Connection = {rand(), 0.0, 0.0, hiddenLayer[k].id, node1.id}; # assigns random connweight to the connection
+ node1.inConnection[k] = con1;
+ }
+
+ neuronRecorder[id_counter] = node1;
+ id_counter++;
+ #addInConnection(node, hiddenLayer);
+ outputLayer[j] = node1;
+ }
+ }
+
+ }
+
+
+ error : float = 1.0;
+ for(m: int = 0; m < runs; m++) {
+ error = 0;
+ foreach(n : int; def(vals[n])) {
+ valueEmitted: emitvals = vals[n];
+ # set the input variables for jth value from values
+ foreach(k: int; def(inputLayer[k])) {
+ # there is one to one mapping in input neurons and number of features in each value
+ print("m");
+ print(m); print("k");print(k);
+ d: float = vals[n].inp[k];
+ inputLayer[k].outputVal = d;
+ }
+
+ # activate the neurons for the forward propagation
+ # calculate the output of each hiddenLayer Neuron
+ foreach(k : int; def(hiddenLayer[k])) {
+ node2: Neuron = hiddenLayer[k];
+ intermediateResult : float = 0.0;
+ connections :array of Connection = node2.inConnection;
+ foreach(l: int; def(connections[l])) {
+ print(neuronRecorder);
+ printany(connections[l].leftNeuron);
+ left: Neuron = neuronRecorder[connections[l].leftNeuron];
+ connweight : float = connections[l].cweight;
+ intermediateResult = intermediateResult + (connweight * left.outputVal);
+ }
+ intermediateResult = intermediateResult + (node2.biasConnection.cweight * node2.bias);
+ node2.outputVal = 1.0 / (1.0 + exp(intermediateResult));
+ #calculateOutput(hiddenLayer[i]);
+ }
+ # calculate the output of each outputLayer Neuron
+ foreach(k : int; def(outputLayer[k])) {
+ node3:Neuron = outputLayer[k];
+ intermediateResult1 : float = 0.0;
+ connections1 :array of Connection = node3.inConnection;
+ foreach(l: int; def(connections1[l])) {
+ left1: Neuron = neuronRecorder[connections1[l].leftNeuron];
+ connweight1 : float = connections1[l].cweight;
+ intermediateResult1 = intermediateResult1 + (connweight1 * left1.outputVal);
+ }
+ intermediateResult1 = intermediateResult1 + (node3.biasConnection.cweight * node3.bias);
+ node3.outputVal = 1.0 / (1.0 + exp(intermediateResult1));
+ #calculateOutput(outputLayer[i]);
+ }
+
+ # output results of each loop
+ outputR : array of float;
+ outputR = new(outputR, len(outputLayer), 0);
+ foreach(l: int; def(outputLayer[l])) {
+ outputR[l] = outputLayer[l].outputVal;
+ }
+
+ resultOutputs[n] = outputR;
+
+ #calculate error
+ expectations :array of float = vals[n].expected;
+ foreach(l: int; def(expectations[l])) {
+ err : float = pow(outputR[l]- vals[n].expected[l], 2);
+ error = error + err;
+ }
+
+ # back propogration fpr expectations
+ #update output layer
+ outNodeCounter : int = 0;
+ foreach(o: int; def(outputLayer[o])) {
+ foreach(connNo: int; def(outputLayer[o].inConnection[connNo])) {
+ nodeConnection : Connection = outputLayer[o].inConnection[connNo];
+ ak: float = outputLayer[o].outputVal;
+ temp : Neuron = neuronRecorder[nodeConnection.leftNeuron];
+ ai: float = temp.outputVal;
+ desiredOut: float = expectations[outNodeCounter];
+ partialDerivative : float = (-1 * ak) * (1 - ak) * ai * (desiredOut - ak);
+ deltaWeightNew : float = (-1 * learningRate) * partialDerivative;
+ newWeight: float = nodeConnection.cweight + deltaWeightNew;
+ nodeConnection.deltaWeight = deltaWeightNew;
+ nodeConnection.cweight = newWeight + momentum * nodeConnection.prevDeltaWeight;
+ }
+ outNodeCounter = outNodeCounter + 1;
+ }
+
+
+ #update hidden layer
+ foreach(h: int; def(hiddenLayer[h])) {
+ hiddenconnections : array of Connection = hiddenLayer[h].inConnection;
+ foreach(connNo: int; def(hiddenconnections[connNo])) {
+ aj: float = hiddenLayer[h].outputVal;
+ targetNeuron : Neuron = neuronRecorder[hiddenconnections[connNo].leftNeuron];
+ aih: float = targetNeuron.outputVal;
+ sumKoutputs : float = 0.0;
+ jindex : int = 0;
+ foreach(o: int; def(outputLayer[o])) {
+ wjk : float = 0.0;
+ allInConns: array of Connection = outputLayer[o].inConnection;
+ foreach(conid: int; def(allInConns[conid])) {
+ if(allInConns[conid].leftNeuron == hiddenLayer[h].id) {
+ wjk = allInConns[conid].cweight;
+ }
+ }
+ desiredOutput: float = expectations[jindex];
+ akh:float = outputLayer[o].outputVal;
+ jindex = jindex + 1;
+ sumKoutputs = sumKoutputs + (-1 * (desiredOutput - akh) * akh * (1 - akh) * wjk);
+ }
+ partialDerivative_: float = aj * (1 - aj) * aih * sumKoutputs;
+ dWeight: float = (-1 * learningRate) * partialDerivative_;
+ newWeight1: float = hiddenconnections[connNo].cweight + dWeight;
+ hiddenconnections[connNo].deltaWeight = dWeight;
+ hiddenconnections[connNo].cweight = newWeight1+ momentum * hiddenconnections[connNo].prevDeltaWeight;
+ }
+ outNodeCounter = outNodeCounter + 1;
+ }
+
+ }
+ }
+ return outputLayer[0].outputVal;
+ };
+
+
+neuralNetwork : output nueralNetworks of emitvals;
+
+inps: array of float = {1.0, 1.0};
+out: array of float = {0.0};
+
+result: emitvals = {inps, out};
+neuralNetwork << result;
+
+inps = {1.0, 0.0};
+out = {1.0};
+
+result= {inps, out};
+neuralNetwork << result;
+
+inps = {0.0, 1.0};
+out = {1.0};
+
+result = {inps, out};
+neuralNetwork << result;
+
+inps = {0.0, 0.0};
+out = {0.0};
+
+result = {inps, out};
+neuralNetwork << result;
diff --git a/test/ml/neural_networks_training_testing/neural_networks_testing.boa b/test/ml/neural_networks_training_testing/neural_networks_testing.boa
new file mode 100644
index 000000000..0d6cdf370
--- /dev/null
+++ b/test/ml/neural_networks_training_testing/neural_networks_testing.boa
@@ -0,0 +1,37 @@
+# What are the 5 largest projects, in terms of AST nodes?
+# Output is in Millions of AST nodes.
+p: Project = input;
+counter: output sum of int;
+
+
+type Connection = {cweight : float, prevDeltaWeight : float, deltaWeight : float, leftNeuron : int, rightNeuron : int};
+type Neuron = {id: int, bias : float , outputVal : float, biasConnection : Connection, inConnection : array of Connection};
+type emitvals = {inp:array of float, expected: array of float};
+type Model = {inputL: array of Neuron, hiddenL: array of Neuron, outputL: array of Neuron};
+
+
+############### dummy information about the model ###################
+
+dummyConnection: Connection = {-1.0, -1.0, -1.0, -1, -1};
+dummyConnArray : array of Connection = {dummyConnection};
+dummyNeuron : Neuron = {0, 0.0, 0.0, dummyConnection, dummyConnArray};
+dummyLayer : array of Neuron = {dummyNeuron};
+dummyModel : Model = {dummyLayer, dummyLayer, dummyLayer};
+
+############### dummy information ends ##############################
+
+results: output collection[string] of float;
+
+
+#loadedModel: Model = load("Neural.model", dummyModel);
+loadedModel: Model = load("./Neural/Neural.model", dummyModel);
+
+classification := function(model: Model, testData: array of float): float {
+ outNeuron: Neuron = model.outputL[0];
+ return outNeuron.outputVal;
+};
+
+#testInput : emitVals = {{0.0}, {1.1}};
+
+#results[p.id] << classification(loadedModel, testInput);
+results[p.id] << classification(loadedModel, {0.0, 0.0});
\ No newline at end of file
diff --git a/test/ml/neural_networks_training_testing/neural_networks_train.boa b/test/ml/neural_networks_training_testing/neural_networks_train.boa
new file mode 100644
index 000000000..a8decbd6b
--- /dev/null
+++ b/test/ml/neural_networks_training_testing/neural_networks_train.boa
@@ -0,0 +1,231 @@
+p: Project = input;
+testing : output sum of int;
+
+type Connection = {cweight : float, prevDeltaWeight : float, deltaWeight : float, leftNeuron : int, rightNeuron : int};
+type Neuron = {id: int, bias : float , outputVal : float, biasConnection : Connection, inConnection : array of Connection};
+type emitvals = {inp:array of float, expected: array of float};
+
+type Model = {inputL: array of Neuron, hiddenL: array of Neuron, outputL: array of Neuron};
+
+nueralNetworks := function(vals : array of emitvals) : Model {
+ runs : int = 500;
+ id_counter : int = 0;
+
+ dummyConnection: Connection = {-1.0, -1.0, -1.0, -1, -1};
+ dummyConnArray : array of Connection = {dummyConnection};
+
+ biasNeuron : Neuron = {id_counter, 0.0, 0.0, dummyConnection, dummyConnArray};
+ dummyArray : array of float = {0.0};
+ resultOutputs: array of array of float;
+ resultOutputs = new(resultOutputs, len(vals), dummyArray);
+
+ learningRate : float = 0.9;
+ momentum : float = 0.7;
+ layers : array of int = {2, 4, 1};
+ totalLayers := len(layers); # intputLayer = 0, hiddenLayer = 1; outputLayer = 2
+
+
+ inputLayer : array of Neuron = {biasNeuron, biasNeuron};
+ hiddenLayer : array of Neuron = {biasNeuron, biasNeuron, biasNeuron, biasNeuron};
+ outputLayer : array of Neuron = {biasNeuron};
+ neuronRecorder : map[int] of Neuron;
+
+ neuronRecorder[id_counter] = biasNeuron;
+ id_counter = id_counter + 1;
+ epsilon : float = 0.00000000001;
+
+
+ for(i :int = 1; i < totalLayers; i++) {
+ # input layer
+ if(i == 0) {
+ for(s :int = 0; s < layers[i]; s++) {
+ inputLayer[s] = {id_counter, 0.0, 0.0, dummyConnection, dummyConnArray};
+ neuronRecorder[id_counter] = inputLayer[s];
+ id_counter = id_counter + 1;
+ }
+ }
+ # hidden layer
+ if(i == 1) {
+ for(z :int = 0; z < layers[i]; z++) {
+ cons : array of Connection = {dummyConnection, dummyConnection};
+ #cons = new(cons, layers[0], dummyConnection);
+ node : Neuron = {id_counter, 0.0, 0.0, dummyConnection, cons};
+
+ # add connections
+ foreach(k: int; def(inputLayer[k])) {
+ localConnection: Connection = {rand(), 0.0, 0.0, inputLayer[k].id, node.id}; # assigns random connweight to the connection
+ node.inConnection[k] = localConnection;
+ }
+ neuronRecorder[id_counter] = node;
+ id_counter++;
+
+ #addInConnection(node, inputLayer);
+ hiddenLayer[z] = node;
+ }
+ }
+ # output layer
+ if(i == 2) {
+ for(j :int = 0; j < layers[i]; j++) {
+ cons1 : array of Connection = {dummyConnection, dummyConnection, dummyConnection, dummyConnection};
+ #cons1 = new(cons1, layers[1]);
+ node1 : Neuron = {id_counter, 0.0, 0.0, dummyConnection, cons1};
+
+ # add connections
+ foreach(k: int; def(hiddenLayer[k])) {
+ con1 : Connection = {rand(), 0.0, 0.0, hiddenLayer[k].id, node1.id}; # assigns random connweight to the connection
+ node1.inConnection[k] = con1;
+ }
+
+ neuronRecorder[id_counter] = node1;
+ id_counter++;
+ #addInConnection(node, hiddenLayer);
+ outputLayer[j] = node1;
+ }
+ }
+
+ }
+
+
+ error : float = 1.0;
+ for(m: int = 0; m < runs; m++) {
+ error = 0;
+ foreach(n : int; def(vals[n])) {
+ valueEmitted: emitvals = vals[n];
+ # set the input variables for jth value from values
+ foreach(k: int; def(inputLayer[k])) {
+ # there is one to one mapping in input neurons and number of features in each value
+ d: float = vals[n].inp[k];
+ inputLayer[k].outputVal = d;
+ }
+
+ # activate the neurons for the forward propagation
+ # calculate the output of each hiddenLayer Neuron
+ foreach(k : int; def(hiddenLayer[k])) {
+ node2: Neuron = hiddenLayer[k];
+ intermediateResult : float = 0.0;
+ connections :array of Connection = node2.inConnection;
+ foreach(l: int; def(connections[l])) {
+ left: Neuron = neuronRecorder[connections[l].leftNeuron];
+ connweight : float = connections[l].cweight;
+ intermediateResult = intermediateResult + (connweight * left.outputVal);
+ }
+ intermediateResult = intermediateResult + (node2.biasConnection.cweight * node2.bias);
+ node2.outputVal = 1.0 / (1.0 + exp(intermediateResult));
+ #calculateOutput(hiddenLayer[i]);
+ }
+ # calculate the output of each outputLayer Neuron
+ foreach(k : int; def(outputLayer[k])) {
+ node3:Neuron = outputLayer[k];
+ intermediateResult1 : float = 0.0;
+ connections1 :array of Connection = node3.inConnection;
+ foreach(l: int; def(connections1[l])) {
+ left1: Neuron = neuronRecorder[connections1[l].leftNeuron];
+ connweight1 : float = connections1[l].cweight;
+ intermediateResult1 = intermediateResult1 + (connweight1 * left1.outputVal);
+ }
+ intermediateResult1 = intermediateResult1 + (node3.biasConnection.cweight * node3.bias);
+ node3.outputVal = 1.0 / (1.0 + exp(intermediateResult1));
+ #calculateOutput(outputLayer[i]);
+ }
+
+ # output results of each loop
+ outputR : array of float;
+ outputR = new(outputR, len(outputLayer), 0);
+ foreach(l: int; def(outputLayer[l])) {
+ outputR[l] = outputLayer[l].outputVal;
+ }
+
+ resultOutputs[n] = outputR;
+
+ #calculate error
+ expectations :array of float = vals[n].expected;
+ foreach(l: int; def(expectations[l])) {
+ err : float = pow(outputR[l]- vals[n].expected[l], 2);
+ error = error + err;
+ }
+
+ # back propogration fpr expectations
+ #update output layer
+ outNodeCounter : int = 0;
+ foreach(o: int; def(outputLayer[o])) {
+ foreach(connNo: int; def(outputLayer[o].inConnection[connNo])) {
+ nodeConnection : Connection = outputLayer[o].inConnection[connNo];
+ ak: float = outputLayer[o].outputVal;
+ temp : Neuron = neuronRecorder[nodeConnection.leftNeuron];
+ ai: float = temp.outputVal;
+ desiredOut: float = expectations[outNodeCounter];
+ partialDerivative : float = (-1 * ak) * (1 - ak) * ai * (desiredOut - ak);
+ deltaWeightNew : float = (-1 * learningRate) * partialDerivative;
+ newWeight: float = nodeConnection.cweight + deltaWeightNew;
+ nodeConnection.deltaWeight = deltaWeightNew;
+ nodeConnection.cweight = newWeight + momentum * nodeConnection.prevDeltaWeight;
+ }
+ outNodeCounter = outNodeCounter + 1;
+ }
+
+
+ #update hidden layer
+ foreach(h: int; def(hiddenLayer[h])) {
+ hiddenconnections : array of Connection = hiddenLayer[h].inConnection;
+ foreach(connNo: int; def(hiddenconnections[connNo])) {
+ aj: float = hiddenLayer[h].outputVal;
+ targetNeuron : Neuron = neuronRecorder[hiddenconnections[connNo].leftNeuron];
+ aih: float = targetNeuron.outputVal;
+ sumKoutputs : float = 0.0;
+ jindex : int = 0;
+ foreach(o: int; def(outputLayer[o])) {
+ wjk : float = 0.0;
+ allInConns: array of Connection = outputLayer[o].inConnection;
+ foreach(conid: int; def(allInConns[conid])) {
+ if(allInConns[conid].leftNeuron == hiddenLayer[h].id) {
+ wjk = allInConns[conid].cweight;
+ }
+ }
+ desiredOutput: float = expectations[jindex];
+ akh:float = outputLayer[o].outputVal;
+ jindex = jindex + 1;
+ sumKoutputs = sumKoutputs + (-1 * (desiredOutput - akh) * akh * (1 - akh) * wjk);
+ }
+ partialDerivative_: float = aj * (1 - aj) * aih * sumKoutputs;
+ dWeight: float = (-1 * learningRate) * partialDerivative_;
+ newWeight1: float = hiddenconnections[connNo].cweight + dWeight;
+ hiddenconnections[connNo].deltaWeight = dWeight;
+ hiddenconnections[connNo].cweight = newWeight1+ momentum * hiddenconnections[connNo].prevDeltaWeight;
+ }
+ outNodeCounter = outNodeCounter + 1;
+ }
+
+ }
+ }
+ #return outputLayer[0].outputVal;
+ model : Model = {inputLayer, hiddenLayer, outputLayer};
+ return model;
+ };
+
+
+neuralNetwork : output nueralNetworks(thresholdError : float = 0.001) of emitvals;
+
+inps: array of float = {1.0, 1.0};
+out: array of float = {0.0};
+
+result: emitvals = {inps, out};
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
+neuralNetwork << result;
diff --git a/test/ml/pca.boa b/test/ml/pca.boa
new file mode 100644
index 000000000..e92b70a21
--- /dev/null
+++ b/test/ml/pca.boa
@@ -0,0 +1,71 @@
+# Counting the 10 most used programming languages
+p: Project = input;
+counts: output top(10) of string weight int;
+astCount: int = 0;
+type fv = {a:float, b:float, c:float, d:float};
+
+
+pca:= function(vals: array of fv): fv {
+ meanarray: array of float = means(vals);
+ dataset : array of array of float = meanScaling(flattenedMatrix(vals, 4), meanarray);
+ meanvector: array of array of float = vector(meanarray);
+ parta := multiply(transpose(dataset), dataset);
+ meansResults := multiply(meanvector, meanarray);
+ cov := matrixsubstract(parta, meansResults);
+ eigens: array of float = eigenvalsReal(cov);
+ result : fv = {eigens[0], eigens[1], eigens[2], eigens[3]};
+ return result;
+};
+
+pcsAgg: output pca of fv;
+
+visit(p, visitor {
+ # only look at the latest snapshot
+ before n: CodeRepository -> {
+ snapshot := getsnapshot(n);
+ foreach (i: int; def(snapshot[i]))
+ visit(snapshot[i]);
+ stop;
+ }
+ before node: Declaration -> {
+ if (node.kind == TypeKind.CLASS) {
+ public_ele : float = 0.0;
+ protected_ele : float = 0.0;
+ private_ele : float = 0.0;
+ other: float = 0.0;
+ foreach (i: int; def(node.methods[i])) {
+ if(has_modifier_public(node.methods[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.methods[i])) {
+ private_ele = private_ele + 1;
+ } else if(has_modifier_protected(node.methods[i])) {
+ protected_ele = protected_ele + 1;
+ } else {
+ other = other + 1;
+ }
+ }
+
+ foreach (i: int; def(node.fields[i])) {
+ if(has_modifier_public(node.fields[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.fields[i])) {
+ private_ele = private_ele + 1;
+ } else if(has_modifier_protected(node.fields[i])) {
+ protected_ele = protected_ele + 1;
+ }else {
+ other = other + 1;
+ }
+ }
+
+ feature1 : fv = {public_ele, private_ele, protected_ele, other};
+ pcsAgg << feature1;
+ pcsAgg << feature1;
+ pcsAgg << feature1;
+ pcsAgg << feature1;
+ pcsAgg << feature1;
+ pcsAgg << feature1;
+ pcsAgg << feature1;
+ pcsAgg << feature1;
+ }
+ }
+});
\ No newline at end of file
diff --git a/test/ml/pcaOptimize.boa b/test/ml/pcaOptimize.boa
new file mode 100644
index 000000000..41b77ac44
--- /dev/null
+++ b/test/ml/pcaOptimize.boa
@@ -0,0 +1,100 @@
+# Counting the 10 most used programming languages
+p: Project = input;
+counts: output top(10) of string weight int;
+astCount: int = 0;
+type sol = {eigenvals: array of float, eigenvectors: array of array of float};
+type optimizedfv = {vectormult: array of array of float, featureMeans: array of float, totalInstances: int};
+
+mapperLocalTotal: array of float;
+mapperLocalTotal = new(mapperLocalTotal, 4, 0.0);
+mapperLocalFeature : array of array of float;
+mapperLocalFeature = new(mapperLocalFeature, 4, mapperLocalTotal);
+mapperLocalCounter: int = 0;
+
+
+pca:= function(vals: array of optimizedfv): sol {
+ parta :array of array of float = vals[0].vectormult;
+ meansOfFeature: array of float = multiply(vals[0].featureMeans, vals[0].totalInstances);
+ accumultedInstances: int = vals[0].totalInstances;
+
+ for(i:int = 1; i < len(vals); i++) {
+ parta = matrixsum(parta, vals[i].vectormult);
+ tempFeatures: array of float = multiply(vals[i].featureMeans, vals[i].totalInstances);
+ meansOfFeature = matrixsum(meansOfFeature, tempFeatures);
+ accumultedInstances = accumultedInstances + vals[i].totalInstances;
+ }
+
+ # adjust means now
+ meansOfFeature[0] = meansOfFeature[0] / accumultedInstances;
+ meansOfFeature[1] = meansOfFeature[1] / accumultedInstances;
+ meansOfFeature[2] = meansOfFeature[2] / accumultedInstances;
+ meansOfFeature[3] = meansOfFeature[3] / accumultedInstances;
+
+ partb : array of array of float = multiply(vector(meansOfFeature), meansOfFeature);
+
+ cov := matrixsubstract(parta, partb);
+ eigens: array of float = eigenvalsReal(cov);
+ #result : fv = {eigens[0], eigens[1], eigens[2], eigens[3]};
+ result : sol = {eigens, eigenvectors(cov)};
+ return result;
+};
+
+
+pcsAgg: output pca of optimizedfv;
+
+visit(p, visitor {
+ # only look at the latest snapshot
+ before n: CodeRepository -> {
+ snapshot := getsnapshot(n);
+ foreach (i: int; def(snapshot[i]))
+ visit(snapshot[i]);
+ stop;
+ }
+ before node: Declaration -> {
+ if (node.kind == TypeKind.CLASS) {
+ public_ele : float = 0.0;
+ protected_ele : float = 0.0;
+ private_ele : float = 0.0;
+ other: float = 0.0;
+ foreach (i: int; def(node.methods[i])) {
+ if(has_modifier_public(node.methods[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.methods[i])) {
+ private_ele = private_ele + 1;
+ } else if(has_modifier_protected(node.methods[i])) {
+ protected_ele = protected_ele + 1;
+ } else {
+ other = other + 1;
+ }
+ }
+
+ foreach (i: int; def(node.fields[i])) {
+ if(has_modifier_public(node.fields[i])) {
+ public_ele = public_ele + 1;
+ } else if(has_modifier_private(node.fields[i])) {
+ private_ele = private_ele + 1;
+ } else if(has_modifier_protected(node.fields[i])) {
+ protected_ele = protected_ele + 1;
+ }else {
+ other = other + 1;
+ }
+ }
+
+ meanPart : array of float = {public_ele, private_ele, protected_ele, other};
+ mapperLocalFeature = matrixsum(mapperLocalFeature, multiply(vector(meanPart), meanPart));
+ mapperLocalTotal[0] = mapperLocalTotal[0] + public_ele;
+ mapperLocalTotal[1] = mapperLocalTotal[1] + private_ele;
+ mapperLocalTotal[2] = mapperLocalTotal[2] + protected_ele;
+ mapperLocalTotal[3] = mapperLocalTotal[3] + other;
+ mapperLocalCounter = mapperLocalCounter + 1;
+ }
+ }
+});
+
+mapperLocalTotal[0] = mapperLocalTotal[0] / mapperLocalCounter;
+mapperLocalTotal[1] = mapperLocalTotal[1] / mapperLocalCounter;
+mapperLocalTotal[2] = mapperLocalTotal[2] / mapperLocalCounter;
+mapperLocalTotal[3] = mapperLocalTotal[3] / mapperLocalCounter;
+
+feature1: optimizedfv = {mapperLocalFeature, mapperLocalTotal, mapperLocalCounter};
+pcsAgg << feature1;
\ No newline at end of file