Commit 8ae82aeb authored by Thomas Michael Timmermanns's avatar Thomas Michael Timmermanns
Browse files

Added CoCo ArchitectureCheck and tests.

Changed ErrorCodes and error messages.
Added ASTGroupStructure methods.
parent 605b92b9
......@@ -20,7 +20,7 @@ grammar CNNArch extends de.monticore.lang.monticar.Common2 {
interface InputElement;
interface ArgumentListing;
interface ArgumentAssignment;
interface GroupStructure;
interface scope GroupStructure;
interface Group;
SingleInput implements InputStructure,InputElement = input:Name@InputDef "->";
......@@ -30,13 +30,13 @@ grammar CNNArch extends de.monticore.lang.monticar.Common2 {
MergeStructure;
OutputStructure implements ArchitectureElement = "output" (GroupOrdinalRange)? "{"
elements:ArchitectureElement* "}" "->"
output:Name@OutputDef;
scope OutputStructure implements ArchitectureElement = "output" (GroupOrdinalRange)? "{"
elements:ArchitectureElement* "}" "->"
output:Name@OutputDef;
RepeatStructure implements ArchitectureElement,GroupElement = "repeat"
intLiteral:UnitNumberResolution "{"
ArchitectureElement* "}";
scope RepeatStructure implements ArchitectureElement,GroupElement = "repeat"
intLiteral:UnitNumberResolution "{"
ArchitectureElement* "}";
StandardGroupStructure implements ArchitectureElement,GroupElement,GroupStructure = groups:StandardGroup+
MergeStructure;
......@@ -81,6 +81,8 @@ grammar CNNArch extends de.monticore.lang.monticar.Common2 {
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(){};
......
/**
*
* ******************************************************************************
* 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._ast;
import java.util.List;
public interface ASTGroupStructure extends ASTGroupStructureTOP {
List<? extends ASTGroup> getGroups();
ASTMergeStructure getMergeStructure();
}
......@@ -20,43 +20,81 @@
*/
package de.monticore.lang.monticar.cnnarch._cocos;
import de.monticore.lang.monticar.cnnarch._ast.ASTArchitecture;
import de.monticore.lang.monticar.cnnarch._ast.ASTArchitectureElement;
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.List;
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) {
completeArchitecture(node.getElements());
}
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);
}
}
//set position for each layer and insert flatten layer if necessary
private void completeArchitecture(List<ASTArchitectureElement> layers) {
/*int pos = 0;
boolean isConvNet = false;
int flattenPos = -1;
if (outDefs.isEmpty()){
Log.error(OUTPUT_MISSING_MSG, node.get_SourcePositionStart());
}
for(ASTMainLayer layer : layers) {
for(ASTOutputStructure outStr : outStructures){
Optional<OutputDefSymbol> outSymbol = outStr.getOutputSymbol();
if (outSymbol.isPresent() && outSymbol.get().getAstNode().isPresent()){
if (layer.getMethod() instanceof ASTConvolutionMethod) {
isConvNet = true;
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());
}
}
if (layer.getMethod() instanceof ASTFullyConnectedMethod && flattenPos == -1) {
flattenPos = pos;
pos++;
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())){
//layer.setPosition(pos);
pos++;
}*/
}
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());
}
}
}
}
if (isConvNet) {
ASTMainLayer flattenLayer = (new ASTMainLayer.Builder()).method(flattenMethodBuilder.build()).build();
layers.add(flattenPos, flattenLayer);
//flattenLayer.setPosition(flattenPos);
}*/
}
}
\ No newline at end of file
}
/**
*
* ******************************************************************************
* 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());
}
}
}
}
......@@ -20,7 +20,6 @@
*/
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;
......@@ -28,14 +27,25 @@ import de.se_rwth.commons.logging.Log;
import java.util.HashSet;
import java.util.Set;
public class DuplicateArgumentCheck implements CNNArchASTMethodCoCo {
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("0x03011 Multiple assignments of the same argument are not allowed",
Log.error(DUPLICATE_ARG_MSG,
assignment.get_SourcePositionStart());
}
else {
......@@ -43,4 +53,14 @@ public class DuplicateArgumentCheck implements CNNArchASTMethodCoCo {
}
}
}
}
\ No newline at end of file
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());
}
}
}
}
......@@ -20,52 +20,24 @@
*/
package de.monticore.lang.monticar.cnnarch._cocos;
import de.monticore.lang.monticar.cnnarch._ast.*;
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;
import java.util.*;
public class ArgumentCheck implements CNNArchASTMethodCoCo {
public class ArgumentTypeCheck implements CNNArchASTMethodCoCo {
@Override
public void check(ASTMethod node) {
checkDuplicateArgument(node);
checkPlaceholderArgument(node);
checkArgumentType(node);
}
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 checkDuplicateArgument(ASTMethod node){
Set<Enum> set = new HashSet<>();
for (ASTArgumentAssignment assignment : node.getArgumentListing().getArguments()) {
if (set.contains(assignment.getLhs())) {
Log.error("0x03011 Multiple assignments of the same argument are not allowed",
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("0x0301B \"_placeholder\" is not an argument",
assignment.get_SourcePositionStart());
}
}
}
public void checkRequiredArguments(ASTMethod node){
}
public void checkArgumentType(ASTMethod node){
final String msg = "0x03424 Incorrect argument type. ";
public void check(ASTMethod node){
String msgAddon;
for(ASTArgumentAssignment assignment:node.getArgumentListing().getArguments()){
......@@ -122,7 +94,7 @@ public class ArgumentCheck implements CNNArchASTMethodCoCo {
}
if (!isValid){
Log.error(msg + msgAddon);
Log.error(INCORRECT_ARG_TYPE_MSG + msgAddon, rhs.get_SourcePositionStart());
}
}
}
......
......@@ -25,7 +25,10 @@ public class CNNArchCocos {
public static CNNArchCoCoChecker createChecker() {
return new CNNArchCoCoChecker()
.addCoCo(new ArgumentCheck())
.addCoCo(new OutputCheck());
.addCoCo(new OutputCheck())
.addCoCo(new ArgumentNameCheck())
.addCoCo(new ArgumentTypeCheck())
.addCoCo(new ArgumentMissingCheck())
.addCoCo(new ArchitectureCheck());
}
}
\ No newline at end of file
......@@ -27,18 +27,25 @@ import java.util.Optional;
public class OutputCheck implements CNNArchASTOutputStructureCoCo {
public static final String OUTPUT_MISSING_VAR_FC_CODE = "x06068";
public static final String OUTPUT_MISSING_VAR_FC_MSG = "0" + OUTPUT_MISSING_VAR_FC_CODE +
" The output structure has to contain a fullyConnected-Layer without the argument 'units'. " +
"This is because the number of outputs is variable for all architectures. " +
"Example: output{ fullyConnected() activation.softmax() } -> out";
@Override
public void check(ASTOutputStructure node) {
checkFullyConnectedLayer(node);
}
public void checkFullyConnectedLayer(ASTOutputStructure node){
private void checkFullyConnectedLayer(ASTOutputStructure node){
ASTFullyConnectedMethod lastFullyConnectedLayer = null;
for (ASTArchitectureElement element: node.getElements()){
if (element instanceof ASTFullyConnectedMethod){
if (lastFullyConnectedLayer != null){
Log.error("0x06021 The argument 'units' is required if the fullyConnected()-layer is not the last fc-layer"
Log.error(ArgumentMissingCheck.MISSING_ARG_MSG +
"The argument 'units' is required if the fullyConnected()-layer is not the last fc-layer in a output structure."
, lastFullyConnectedLayer.get_SourcePositionStart());
lastFullyConnectedLayer = null;
}
......@@ -55,10 +62,7 @@ public class OutputCheck implements CNNArchASTOutputStructureCoCo {
}
if (lastFullyConnectedLayer == null){
Log.error("0x06028 The output block has to contain a fullyConnectedLayer without the argument 'units'. " +
"This is because the number of outputs is variable for all architectures. " +
"Example: output{ fullyConnected() activation.softmax() } -> out"
, node.get_SourcePositionEnd());
Log.error(OUTPUT_MISSING_VAR_FC_MSG, node.get_SourcePositionEnd());
}
}
......
......@@ -23,10 +23,10 @@ package de.monticore.lang.monticar.cnnarch._symboltable;
import de.monticore.lang.monticar.cnnarch._ast.ASTArchitecture;
import de.monticore.lang.monticar.cnnarch._ast.ASTCNNArchCompilationUnit;
import de.monticore.symboltable.ArtifactScope;
import de.monticore.symboltable.ImportStatement;
import de.monticore.symboltable.MutableScope;
import de.monticore.symboltable.ResolvingConfiguration;
import de.monticore.lang.monticar.cnnarch._ast.ASTOutputDef;
import de.monticore.lang.monticar.cnnarch._ast.ASTOutputStructure;
import de.monticore.lang.monticar.cnnarch._cocos.ArchitectureCheck;
import de.monticore.symboltable.*;
import de.se_rwth.commons.logging.Log;
import java.util.ArrayList;
......@@ -39,7 +39,6 @@ public class CNNArchSymbolTableCreator extends CNNArchSymbolTableCreatorTOP {
private String compilationUnitPackage = "";
public CNNArchSymbolTableCreator(final ResolvingConfiguration resolvingConfig,
final MutableScope enclosingScope) {
super(resolvingConfig, enclosingScope);
......@@ -70,8 +69,34 @@ public class CNNArchSymbolTableCreator extends CNNArchSymbolTableCreatorTOP {
);
addToScopeAndLinkWithNode(compilationUnitSymbol, compilationUnit);
}
/*@Override
public void visit(ASTOutputDef ast) {
Log.debug("Building Symboltable for Script: " + ast.getName(),
CNNArchSymbolTableCreator.class.getSimpleName());
OutputSymbol outputSymbol = new OutputSymbol(ast.getName());
addToScope(outputSymbol);
}
@Override
public void visit(ASTOutputStructure ast) {
Log.debug("Linking symbol " + ast.getOutput() + " to output: ",
CNNArchSymbolTableCreator.class.getSimpleName());
Optional<Symbol> optSymbol = compilationUnitScope.resolveDown(ast.getOutput(), OutputKind.KIND);
if (optSymbol.isPresent()){
OutputSymbol outSym = (OutputSymbol) optSymbol.get();
addToScopeAndLinkWithNode(outSym, ast);
}
else {
Log.error("0"+OUTPUT_UNDEFINED_CODE+" Output symbol with name "+ ast.getOutput() +" does not exist."
, ast.get_SourcePositionEnd());
}
}*/
public void endVisit(final ASTArchitecture architecture) {
removeCurrentScope();
......
......@@ -46,7 +46,6 @@ public class AbstractCoCoTest extends AbstractSymtabTest {
private static final String MODEL_PATH = "src/test/resources/";
protected static ASTCNNArchNode getAstNode(String modelPath, String model) {
Scope symTab = createSymTab(MODEL_PATH + modelPath);
CNNArchCompilationUnitSymbol comp = symTab.<CNNArchCompilationUnitSymbol> resolve(
model, CNNArchCompilationUnitSymbol.KIND).orElse(null);
......
......@@ -20,20 +20,11 @@
*/
package de.monticore.lang.monticar.cnnarch.cocos;
import de.monticore.lang.monticar.cnnarch.ParserTest;
import de.monticore.lang.monticar.cnnarch._cocos.ArgumentCheck;
import de.monticore.lang.monticar.cnnarch._cocos.CNNArchCoCoChecker;
import de.monticore.lang.monticar.cnnarch._cocos.CNNArchCocos;
import de.monticore.lang.monticar.cnnarch._cocos.OutputCheck;
import de.monticore.lang.monticar.cnnarch._symboltable.CNNArchLanguage;
import de.monticore.lang.monticar.cnnarch._cocos.*;
import de.se_rwth.commons.logging.Log;
import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.junit.Assert.assertTrue;
public class AllCoCoTest extends AbstractCoCoTest {
String baseDir="src/test/resources";
......@@ -70,47 +61,80 @@ public class AllCoCoTest extends AbstractCoCoTest {
@Test
public void testArgumentCoCos() throws IOException{
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentCheck())
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentNameCheck())
, getAstNode("invalid_tests", "DuplicateArgument")
, new ExpectedErrorInfo(1,"x03011"));
, new ExpectedErrorInfo(1,ArgumentNameCheck.DUPLICATE_ARG_CODE));
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentCheck())
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentTypeCheck())
, getAstNode("invalid_tests", "BooleanArgumentTypeTest")
, new ExpectedErrorInfo(3,"x03424"));
, new ExpectedErrorInfo(3,ArgumentTypeCheck.INCORRECT_ARG_TYPE_CODE));
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentCheck())
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentTypeCheck())
, getAstNode("invalid_tests", "IntegerArgumentTypeTest")
, new ExpectedErrorInfo(7,"x03424"));
, new ExpectedErrorInfo(7,ArgumentTypeCheck.INCORRECT_ARG_TYPE_CODE));
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentMissingCheck())
, getAstNode("invalid_tests", "MissingConvolutionArgument1")
, new ExpectedErrorInfo(1,ArgumentMissingCheck.MISSING_ARG_CODE));
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentMissingCheck())
, getAstNode("invalid_tests", "MissingConvolutionArgument2")
, new ExpectedErrorInfo(2, ArgumentMissingCheck.MISSING_ARG_CODE));
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentMissingCheck())
, getAstNode("invalid_tests", "MissingFullyConnectedArgument")
, new ExpectedErrorInfo(1, ArgumentMissingCheck.MISSING_ARG_CODE));
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentMissingCheck())
, getAstNode("invalid_tests", "MissingPoolingArgument1")
, new ExpectedErrorInfo(1, ArgumentMissingCheck.MISSING_ARG_CODE));
/*
testInvalidModel("IntegerArgumentTypeTest",9,"x03012");
checkInvalid(new CNNArchCoCoChecker().addCoCo(new ArgumentMissingCheck())
, getAstNode("invalid_tests", "MissingLRNArgument")
, new ExpectedErrorInfo(1, ArgumentMissingCheck.MISSING_ARG_CODE));