Commit 997c8052 authored by Thomas Michael Timmermanns's avatar Thomas Michael Timmermanns
Browse files

Complete rework.

Added method definitions.
Added math expressions.
Added serial and parallel argument sequences.
parent 8ae82aeb
package de.monticore.lang.monticar;
grammar CNNArch extends de.monticore.lang.monticar.Common2 {
grammar CNNArch extends de.monticore.lang.math.Math {
symbol scope CNNArchCompilationUnit = "architecture" Name& "{" Architecture "}";
CNNArchCompilationUnit = Architecture;
Architecture = defs:VarDef* inputStructure:InputStructure elements:ArchitectureElement*;
interface VarDef;
symbol InputDef implements VarDef = "def" "input" Name& (ArrayDeclaration)?;
symbol OutputDef implements VarDef = "def" "output" Name& (ArrayDeclaration)?;
symbol scope Architecture = "architecture"
name:Name& "{"
defs:ArchDeclaration*
body:ArchBody "}";
interface ArchDeclaration;
interface ArchitectureElement;
interface GroupElement;
interface Method;
interface GroupMethod extends Method,GroupElement;
interface MergeMethod extends Method;
interface LayerMethod extends Method,ArchitectureElement,GroupElement;
interface InputStructure;
interface InputElement;
interface ArgumentListing;
interface ArgumentAssignment;
interface scope GroupStructure;
interface Group;
SingleInput implements InputStructure,InputElement = input:Name@InputDef "->";
ArrayInput implements InputElement = input:Name@InputDef "[" (index:UnitNumberResolution)? "]" "->";
InputGroupStructure implements GroupStructure,InputStructure = groups:InputGroup+
MergeStructure;
scope OutputStructure implements ArchitectureElement = "output" (GroupOrdinalRange)? "{"
elements:ArchitectureElement* "}" "->"
output:Name@OutputDef;
scope RepeatStructure implements ArchitectureElement,GroupElement = "repeat"
intLiteral:UnitNumberResolution "{"
ArchitectureElement* "}";
StandardGroupStructure implements ArchitectureElement,GroupElement,GroupStructure = groups:StandardGroup+
MergeStructure;
MergeStructure = "merge" method:MergeMethod;
StandardGroup implements Group = declaration:GroupDeclaration "{"
body:GroupBody "}";
InputGroup implements Group = declaration:GroupDeclaration "{"
input:InputElement
body:GroupBody "}";
GroupDeclaration = "group" (GroupOrdinalRange|GroupOrdinal);
GroupOrdinal = intLiteral:UnitNumberResolution;
GroupOrdinalRange = startInt:UnitNumberResolution".."endInt:UnitNumberResolution;
GroupBody = elements:GroupElement*;
ArgumentRhs = number:Number
| tuple:Tuple
| booleanVal:BooleanLiteral;
//| type:ArgumentKeyword;
Tuple = "(" values:Number "," values:(Number || ",")+ ")";
//interface ArgumentKeyword;
//ast ArgumentKeyword = method Optional<String> getName(){};
interface Variable;
ast Method = method ASTArgumentListing getArgumentListing(){}
method Enum getType(){};
ast ArgumentAssignment = method Enum getLhs(){}
method ASTArgumentRhs getRhs(){};
//ast ArgumentListing = method java.util.List<? extends ASTArgumentAssignment> getArguments(){};
ast InputElement = method String getInput(){}
method Optional<de.monticore.lang.monticar.cnnarch._symboltable.InputDefSymbol> getInputSymbol(){};
ast Group = method ASTGroupDeclaration getDeclaration(){}
method ASTGroupBody getBody(){};
//ast GroupStructure = method java.util.List<? extends ASTGroup> getGroups(){}
// methdod ASTMergeStructure getMergeStructure(){};
symbol IODeclaration implements ArchDeclaration = "def"
(in:"input" | out:"output")
type:ArchType
Name&
(ArrayDeclaration)?;
ArchType implements Type = (ElementType ("^" "{" (IOVariable || ",")+ "}")?)?;
symbol IOVariable implements Variable = Name&;
symbol Constant implements Variable = "def" Name& "=" rhs:ArchRhs;
ConcatenateMethod implements MergeMethod = type:ConcatenateType "(" argumentListing:ConcatenateArgumentListing ")";
ConcatenateArgumentListing implements ArgumentListing = arguments:(ConcatenateArgumentAssignment || ",")*;
ConcatenateArgumentAssignment implements ArgumentAssignment = lhs:ConcatenateArgument "=" rhs:ArgumentRhs;
enum ConcatenateArgument = XPLACEHOLDERX:"_placeholder";
enum ConcatenateType = "concatenate";
symbol scope MethodDeclaration implements ArchDeclaration = "def"
Name& "("
parameters:(Parameter || ",")* ")" "{"
body:ArchBody "}";
AddMethod implements MergeMethod = type:AddType "(" argumentListing:AddArgumentListing ")";
AddArgumentListing implements ArgumentListing = arguments:(AddArgumentAssignment|| ",")*;
AddArgumentAssignment implements ArgumentAssignment = lhs:AddArgument "=" rhs:ArgumentRhs;
enum AddArgument = XPLACEHOLDERX:"_placeholder";
enum AddType = "add";
symbol Parameter implements Variable = Name& ("=" default:ArchRhs)?;
SplitMethod implements GroupMethod = type:SplitType "(" argumentListing:SplitArgumentListing ")";
SplitArgumentListing implements ArgumentListing = arguments:(SplitArgumentAssignment || ",")*;
SplitArgumentAssignment implements ArgumentAssignment = lhs:SplitArgument "=" rhs:ArgumentRhs;
enum SplitArgument = XPLACEHOLDERX:"_placeholder";
enum SplitType = "split";
ArchBody = elements:(ArchitectureElement || "->")*;
IOLayer implements ArchitectureElement = Name& ("[" index:ArchExpression "]")?;
ConvolutionMethod implements LayerMethod = type:ConvolutionType "(" argumentListing:ConvolutionArgumentListing ")";
ConvolutionArgumentListing implements ArgumentListing = arguments:(ConvolutionArgumentAssignment || ",")*;
ConvolutionArgumentAssignment implements ArgumentAssignment = lhs:ConvolutionArgument "=" rhs:ArgumentRhs;
enum ConvolutionArgument = KERNEL:"kernel" //required
| FILTERS:"filters" //required
| STRIDE:"stride"
| NOBIAS:"no_bias";
enum ConvolutionType = "convolution";
MethodLayer implements ArchitectureElement = Name& "(" arguments:(Argument || ",")* ")";
FullyConnectedMethod implements LayerMethod = type:FullyConnectedType "(" argumentListing:FullyConnectedArgumentListing ")";
FullyConnectedArgumentListing implements ArgumentListing = arguments:(FullyConnectedArgumentAssignment || ",")*;
FullyConnectedArgumentAssignment implements ArgumentAssignment = lhs:FullyConnectedArgument "=" rhs:ArgumentRhs;
enum FullyConnectedArgument = UNITS:"units" //required
| NOBIAS:"no_bias";
enum FullyConnectedType = "fullyConnected";
Argument = Name "=" rhs:ArchRhs;
ArchRhs = (expression:ArchExpression | sequence:ArchValueSequence);
ActivationMethod implements LayerMethod = "activation."type:ActivationType "(" argumentListing:ActivationArgumentListing ")";
ActivationArgumentListing implements ArgumentListing = arguments:(ActivationArgumentAssignment || ",")*;
ActivationArgumentAssignment implements ArgumentAssignment = lhs:ActivationArgument "=" rhs:ArgumentRhs;
enum ActivationArgument = XPLACEHOLDERX:"_placeholder";
enum ActivationType = "relu"
| "sigmoid"
| "tanh"
| "softmax";
ArchValueSequence = "[" parallelValues:(SerialValues || "|")* "]";
SerialValues = (ArchExpression || "->")+;
PoolingMethod implements LayerMethod = "pooling."type:PoolingType "(" argumentListing:PoolingArgumentListing ")";
PoolingArgumentListing implements ArgumentListing = arguments:(PoolingArgumentAssignment || ",")*;
PoolingArgumentAssignment implements ArgumentAssignment = lhs:PoolingArgument "=" rhs:ArgumentRhs;
enum PoolingArgument = KERNEL:"kernel" //required
| STRIDE:"stride"
| Global:"global";
enum PoolingType = "max"
| "avg";
ArchValueRange extends ArchValueSequence = "[" start:ArchExpression
(serial:"->" | parallel:"|")
(":" step:ArchExpression)?
":" end:ArchExpression "]";
ParallelLayer implements ArchitectureElement = "(" groups:(ArchBody || "|")+ ")";
DropoutMethod implements LayerMethod = type:DropoutType "(" argumentListing:DropoutArgumentListing ")";
DropoutArgumentListing implements ArgumentListing = arguments:(DropoutArgumentAssignment || ",")*;
DropoutArgumentAssignment implements ArgumentAssignment = lhs:DropoutArgument "=" rhs:ArgumentRhs;
enum DropoutArgument = P:"p";
enum DropoutType = "dropout";
ArrayAccessLayer implements ArchitectureElement = "[" index:ArchExpression "]";
BatchNormMethod implements LayerMethod = type:BatchNormType "(" argumentListing:BatchNormArgumentListing ")";
BatchNormArgumentListing implements ArgumentListing = arguments:(BatchNormArgumentAssignment || ",")*;
BatchNormArgumentAssignment implements ArgumentAssignment = lhs:BatchNormArgument "=" rhs:ArgumentRhs;
enum BatchNormArgument = XPLACEHOLDERX:"_placeholder";
enum BatchNormType = "batchNorm";
ArchExpression = (arithmeticExpression:MathArithmeticExpression
| booleanExpression:MathBooleanExpression
| tupleExpression:TupleExpression);
LrnMethod implements LayerMethod = type:LrnType "(" argumentListing:LrnArgumentListing ")";
LrnArgumentListing implements ArgumentListing = arguments:(LrnArgumentAssignment || ",")*;
LrnArgumentAssignment implements ArgumentAssignment = lhs:LrnArgument "=" rhs:ArgumentRhs;
enum LrnArgument = NSIZE:"nsize" //required
| ALPHA:"alpha"
| BETA:"beta"
| KNORM:"knorm";
enum LrnType = "lrn";
TupleExpression implements MathExpression = "(" expressions:MathArithmeticExpression "," expressions:(MathArithmeticExpression || ",")* ")";
}
\ No newline at end of file
......@@ -20,11 +20,24 @@
*/
package de.monticore.lang.monticar.cnnarch._ast;
import java.util.List;
import de.monticore.lang.monticar.common2._ast.ASTArrayDeclaration;
public interface ASTGroupStructure extends ASTGroupStructureTOP {
import java.util.Optional;
List<? extends ASTGroup> getGroups();
public class ASTIODeclaration extends ASTIODeclarationTOP {
ASTMergeStructure getMergeStructure();
public ASTIODeclaration() {
}
public ASTIODeclaration(ASTArchType type, String name, ASTArrayDeclaration arrayDeclaration, String in, String out) {
super(type, name, arrayDeclaration, in, out);
}
public boolean isInput(){
return in.isPresent();
}
public boolean isOutput(){
return out.isPresent();
}
}
/**
*
* ******************************************************************************
* MontiCAR Modeling Family, www.se-rwth.de
* Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
* All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* *******************************************************************************
*/
package de.monticore.lang.monticar.cnnarch._cocos;
import de.monticore.lang.monticar.cnnarch._ast.*;
import de.monticore.lang.monticar.cnnarch._symboltable.OutputDefSymbol;
import de.se_rwth.commons.logging.Log;
import java.util.*;
public class ArchitectureCheck implements CNNArchASTArchitectureCoCo {
public static final String OUTPUT_UNDEFINED_CODE = "x0601D";
public static final String OUTPUT_UNDEFINED_MSG = "0" + OUTPUT_UNDEFINED_CODE + " Undefined output. ";
public static final String OUTPUT_MISSING_CODE = "x0601C";
public static final String OUTPUT_MISSING_MSG = "0" + OUTPUT_MISSING_CODE + " Missing output. Architecture has to declare at least one output.";
public static final String OUTPUT_UNUSED_CODE = "x0601E";
public static final String OUTPUT_UNUSED_MSG = "0" + OUTPUT_UNUSED_CODE + " ";
public static final String OUTPUT_DUPLICATE_CODE = "x0601B";
public static final String OUTPUT_DUPLICATE_MSG = "0"+OUTPUT_DUPLICATE_CODE+" ";
@Override
public void check(ASTArchitecture node) {
List<ASTOutputDef> outDefs = new LinkedList<>();
List<ASTOutputStructure> outStructures = new LinkedList<>();
Map<ASTOutputDef, Integer> countOutputMap = new HashMap<>();
for (ASTVarDef def : node.getDefs()){
if (def instanceof ASTOutputDef){
outDefs.add((ASTOutputDef) def);
countOutputMap.put((ASTOutputDef) def, 0);
}
}
for(ASTArchitectureElement element : node.getElements()){
if (element instanceof ASTOutputStructure){
outStructures.add((ASTOutputStructure) element);
}
}
if (outDefs.isEmpty()){
Log.error(OUTPUT_MISSING_MSG, node.get_SourcePositionStart());
}
for(ASTOutputStructure outStr : outStructures){
Optional<OutputDefSymbol> outSymbol = outStr.getOutputSymbol();
if (outSymbol.isPresent() && outSymbol.get().getAstNode().isPresent()){
ASTOutputDef def = (ASTOutputDef) outSymbol.get().getAstNode().get();
countOutputMap.put(def, countOutputMap.get(def) + 1);
}
else {
Log.error(OUTPUT_UNDEFINED_MSG + "The output name " + outStr.getOutput() + " was never defined. "
, outStr.get_SourcePositionEnd());
}
}
for (ASTOutputDef def : outDefs){
if (countOutputMap.get(def).equals(0)){
Log.error(OUTPUT_UNUSED_MSG + "Output with the name " + def.getName() + " was declared but not used."
, def.get_SourcePositionStart());
}
else {
if (def.getArrayDeclaration().isPresent()){
/*if (!countOutputMap.get(def).equals(
def.getArrayDeclaration().get().getIntLiteral().getNumber().get().getDividend().intValue())){
}*/
}
else {
if (!countOutputMap.get(def).equals(1)){
Log.error(OUTPUT_DUPLICATE_MSG + "Output with the name " + def.getName() + " was assigned multiple times."
, def.get_SourcePositionStart());
}
}
}
}
}
}
/**
*
* ******************************************************************************
* MontiCAR Modeling Family, www.se-rwth.de
* Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
* All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* *******************************************************************************
*/
package de.monticore.lang.monticar.cnnarch._cocos;
import de.monticore.ast.ASTNode;
import de.monticore.lang.monticar.cnnarch._ast.*;
import de.se_rwth.commons.logging.Log;
import java.util.Optional;
public class ArgumentMissingCheck implements CNNArchASTMethodCoCo {
public static final String MISSING_ARG_CODE = "x06021";
public static final String MISSING_ARG_MSG = "0"+MISSING_ARG_CODE+" Missing argument. ";
public void check(ASTMethod node){
boolean isInOutput = false;
//check if the the node is in a OutputStructure scope
if (node.getEnclosingScope().isPresent()){
Optional<? extends ASTNode> optAst = node.getEnclosingScope().get().getAstNode();
if (optAst.isPresent() && optAst.get() instanceof ASTOutputStructure){
isInOutput = true;
}
}
//switch(node)
if (node instanceof ASTFullyConnectedMethod){
Optional<ASTArgumentRhs> unitArg = node.getArgumentListing().getArgument(ASTFullyConnectedArgument.UNITS);
if (!unitArg.isPresent() && !isInOutput){
Log.error(MISSING_ARG_MSG + "Argument 'units' is required. ", node.get_SourcePositionEnd());
}
}
else if (node instanceof ASTConvolutionMethod){
Optional<ASTArgumentRhs> kernelArg = node.getArgumentListing().getArgument(ASTConvolutionArgument.KERNEL);
Optional<ASTArgumentRhs> filtersArg = node.getArgumentListing().getArgument(ASTConvolutionArgument.FILTERS);
if (!kernelArg.isPresent()){
Log.error(MISSING_ARG_MSG + "Argument 'kernel' is required. ", node.get_SourcePositionEnd());
}
if (!filtersArg.isPresent()){
Log.error(MISSING_ARG_MSG + "Argument 'filters' is required. ", node.get_SourcePositionEnd());
}
}
else if (node instanceof ASTPoolingMethod){
Optional<ASTArgumentRhs> kernelArg = node.getArgumentListing().getArgument(ASTPoolingArgument.KERNEL);
Optional<ASTArgumentRhs> globalArg = node.getArgumentListing().getArgument(ASTPoolingArgument.GLOBAL);
if (!kernelArg.isPresent() && !globalArg.isPresent()){
Log.error(MISSING_ARG_MSG + "Argument 'kernel' or 'global' is required. ", node.get_SourcePositionEnd());
}
}
else if (node instanceof ASTLrnMethod){
Optional<ASTArgumentRhs> nsizeArg = node.getArgumentListing().getArgument(ASTLrnArgument.NSIZE);
if (!nsizeArg.isPresent()){
Log.error(MISSING_ARG_MSG + "Argument 'nsize' is required. ", node.get_SourcePositionEnd());
}
}
}
}
/**
*
* ******************************************************************************
* MontiCAR Modeling Family, www.se-rwth.de
* Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
* All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* *******************************************************************************
*/
package de.monticore.lang.monticar.cnnarch._cocos;
import de.monticore.lang.monticar.cnnarch._ast.ASTArgumentAssignment;
import de.monticore.lang.monticar.cnnarch._ast.ASTMethod;
import de.se_rwth.commons.logging.Log;
import java.util.HashSet;
import java.util.Set;
public class ArgumentNameCheck implements CNNArchASTMethodCoCo {
public static final String PLACEHOLDER_ARG_CODE = "x0303B";
public static final String DUPLICATE_ARG_CODE = "x03031";
public static final String PLACEHOLDER_ARG_MSG = "0"+PLACEHOLDER_ARG_CODE+" \"_placeholder\" is not an argument. ";
public static final String DUPLICATE_ARG_MSG = "0"+DUPLICATE_ARG_CODE+" Multiple assignments of the same argument are not allowed. ";
@Override
public void check(ASTMethod node) {
checkDuplicateArgument(node);
checkPlaceholderArgument(node);
}
public void checkDuplicateArgument(ASTMethod node){
Set<Enum> set = new HashSet<>();
for (ASTArgumentAssignment assignment : node.getArgumentListing().getArguments()) {
if (set.contains(assignment.getLhs())) {
Log.error(DUPLICATE_ARG_MSG,
assignment.get_SourcePositionStart());
}
else {
set.add(assignment.getLhs());
}
}
}
public void checkPlaceholderArgument(ASTMethod node){
for(ASTArgumentAssignment assignment:node.getArgumentListing().getArguments()){
if (assignment.getLhs().name().equals("_placeholder")){
Log.error(PLACEHOLDER_ARG_MSG,
assignment.get_SourcePositionStart());
}
}
}
}
/**
*
* ******************************************************************************
* MontiCAR Modeling Family, www.se-rwth.de
* Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
* All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* *******************************************************************************
*/
package de.monticore.lang.monticar.cnnarch._cocos;
import de.monticore.lang.monticar.cnnarch._ast.ASTArgumentAssignment;
import de.monticore.lang.monticar.cnnarch._ast.ASTArgumentRhs;
import de.monticore.lang.monticar.cnnarch._ast.ASTMethod;
import de.monticore.lang.monticar.cnnarch._ast.ASTTuple;
import de.se_rwth.commons.logging.Log;
import org.jscience.mathematics.number.Rational;
import siunit.monticoresiunit.si._ast.ASTNumber;
import siunit.monticoresiunit.si._ast.ASTUnitNumber;
import javax.measure.unit.Unit;
public class ArgumentTypeCheck implements CNNArchASTMethodCoCo {
public static final String INCORRECT_ARG_TYPE_CODE = "x03444";
public static final String INCORRECT_ARG_TYPE_MSG = "0"+INCORRECT_ARG_TYPE_CODE+" Incorrect argument type. ";
public void check(ASTMethod node){
String msgAddon;
for(ASTArgumentAssignment assignment:node.getArgumentListing().getArguments()){
boolean isValid = false;
ASTArgumentRhs rhs = assignment.getRhs();
switch(assignment.getLhs().name()){
case "UNITS":
isValid = checkInt(rhs);
msgAddon = "Argument 'units' has to be an integer.";
break;
case "NOBIAS":
isValid = checkBool(rhs);
msgAddon = "Argument 'no_bias' has to be a boolean.";
break;
case "FILTERS":
msgAddon = "Argument 'filters' has to be an integer.";
isValid = checkInt(rhs);
break;
case "KERNEL":
isValid = checkInt(rhs) || checkIntTuple(rhs);
msgAddon = "Argument 'kernel' has to be an integer or an integer-tuple.";
break;
case "STRIDE":
isValid = checkInt(rhs) || checkIntTuple(rhs);
msgAddon = "Argument 'stride' has to be an integer or an integer-tuple.";
break;
case "GLOBAL":
isValid = checkBool(rhs);