From fce795db379818ecc7e7a50a3db7eb9018d5aaf7 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Thu, 7 Sep 2017 15:41:28 +0200 Subject: [PATCH 01/17] Cleanup the pretty printer --- src/main/grammars/org/nest/NESTML.mc4 | 32 +- .../codegeneration/NestCodeGenerator.java | 17 +- .../converters/NESTReferenceConverter.java | 1 - .../codegeneration/helpers/ASTInputs.java | 25 +- .../codegeneration/helpers/ASTOutputs.java | 15 +- .../nest/codegeneration/sympy/AstCreator.java | 11 +- .../sympy/DeltaSolutionTransformer.java | 6 +- .../sympy/EquationsBlockProcessor.java | 18 +- .../sympy/ExactSolutionTransformer.java | 26 +- .../sympy/ShapesToOdesTransformer.java | 8 +- .../codegeneration/sympy/TransformerBase.java | 41 +- .../org/nest/nestml/_ast/ASTDeclaration.java | 13 +- .../_ast/{ASTBody.java => ASTNeuron.java} | 206 ++++----- .../_cocos/FunctionDefinedMultipleTimes.java | 7 +- .../MemberVariableDefinedMultipleTimes.java | 9 +- .../_cocos/NeuronWithMultipleOrNoInput.java | 7 +- .../_cocos/NeuronWithMultipleOrNoOutput.java | 3 +- .../_cocos/NeuronWithMultipleOrNoUpdate.java | 6 +- .../VariableBlockDefinedMultipleTimes.java | 20 +- .../org/nest/nestml/_parser/NESTMLParser.java | 6 +- .../NESTMLSymbolTableCreator.java | 26 +- .../_symboltable/symbols/VariableSymbol.java | 4 +- .../prettyprinter/NESTMLPrettyPrinter.java | 432 +++++++----------- .../prettyprinter/SPLPrettyPrinter.java | 335 -------------- .../SPLPrettyPrinterFactory.java | 43 -- src/main/java/org/nest/utils/AstUtils.java | 4 +- .../org/nest/nestml/neuron/NeuronClass.ftl | 2 +- .../java/org/nest/base/ModelbasedTest.java | 4 +- .../sympy/EquationsBlockProcessorTest.java | 2 +- .../sympy/ExpressionFolderTest.java | 2 +- .../codegeneration/sympy/SolverInputTest.java | 8 +- .../codegeneration/sympy/SymPySolverTest.java | 2 +- .../{ASTBodyTest.java => ASTNeuronTest.java} | 10 +- .../nest/nestml/_cocos/NestmlCoCosTest.java | 2 - .../nest/nestml/_parser/NESTMLParserTest.java | 4 +- .../NESTMLSymbolTableCreatorTest.java | 24 +- .../NESTMLPrettyPrinterTest.java | 30 +- .../java/org/nest/utils/AstUtilsTest.java | 4 +- .../org/nest/nestml/parsing/comment.nestml | 4 + 39 files changed, 428 insertions(+), 991 deletions(-) rename src/main/java/org/nest/nestml/_ast/{ASTBody.java => ASTNeuron.java} (55%) delete mode 100644 src/main/java/org/nest/nestml/prettyprinter/SPLPrettyPrinter.java delete mode 100644 src/main/java/org/nest/nestml/prettyprinter/SPLPrettyPrinterFactory.java rename src/test/java/org/nest/nestml/_ast/{ASTBodyTest.java => ASTNeuronTest.java} (73%) diff --git a/src/main/grammars/org/nest/NESTML.mc4 b/src/main/grammars/org/nest/NESTML.mc4 index 7588313e6..a3b6c3346 100644 --- a/src/main/grammars/org/nest/NESTML.mc4 +++ b/src/main/grammars/org/nest/NESTML.mc4 @@ -157,7 +157,7 @@ grammar NESTML extends org.nest.Literals { vars:Variable ("," vars:Variable)* Datatype ("[" sizeParameter:Name "]")? - ( "=" Expr)? SL_COMMENT? + ( "=" Expr)? ("[[" invariant:Expr "]]")?; /** ATReturnStmt Models the return statement in a function. @@ -190,20 +190,12 @@ grammar NESTML extends org.nest.Literals { @attribute Name The name of the neuron @attribute Body The body of the neuron, e.g. internal, state, parameter... */ - Neuron = "neuron" Name Body; - - /** ASTBodyElement represents a single entry in the neuron or component: e.g. internal, state, - parameter... The interface is used to enable language extension. - */ - interface BodyElement; - - /** ASTBody The body of the neuron, e.g. internal, state, parameter... - */ - Body = BLOCK_OPEN - (NEWLINE | BodyElement)* - BLOCK_CLOSE; + Neuron = "neuron" Name + BLOCK_OPEN + (NEWLINE | BlockWithVariables | UpdateBlock | Equations | Input | Output | Function)* + BLOCK_CLOSE; - /** ASTVar_Block represent a block with variables, e.g.: + /** ASTBlockWithVariables represent a block with variables, e.g.: state: y0, y1, y2, y3 mV [y1 > 0; y2 > 0] end @@ -213,7 +205,7 @@ grammar NESTML extends org.nest.Literals { @attribute internal true if the varblock ist a state internal. @attribute AliasDecl a list with variable declarations. */ - Var_Block implements BodyElement = + BlockWithVariables = (["state"]|["parameters"]|["internals"]) BLOCK_OPEN (Declaration | NEWLINE)* @@ -227,7 +219,7 @@ grammar NESTML extends org.nest.Literals { end @attribute block Implementation of the dynamics. */ - Dynamics implements BodyElement = + UpdateBlock = "update" BLOCK_OPEN Block @@ -240,7 +232,7 @@ grammar NESTML extends org.nest.Literals { end @attribute odeDeclaration Block with equations and differential equations. */ - Equations implements BodyElement = + Equations = "equations" BLOCK_OPEN OdeDeclaration @@ -254,7 +246,7 @@ grammar NESTML extends org.nest.Literals { @attribute inputLine set of input lines. */ - Input implements BodyElement = "input" + Input = "input" BLOCK_OPEN (InputLine | NEWLINE)* BLOCK_CLOSE; @@ -284,7 +276,7 @@ grammar NESTML extends org.nest.Literals { @attribute spike true iff the neuron has a spike output. @attribute current true iff. the neuron is a current output. */ - Output implements BodyElement = "output" BLOCK_OPEN (["spike"] | ["current"]) ; + Output = "output" BLOCK_OPEN (["spike"] | ["current"]) ; /** ASTFunction a function definition: function set_V_m(v mV): @@ -296,7 +288,7 @@ grammar NESTML extends org.nest.Literals { @attribute primitiveType Primitive return type, e.g. int @attribute block Implementation of the function. */ - Function implements BodyElement = "function" Name "(" Parameters? ")" (returnType:Datatype)? + Function = "function" Name "(" Parameters? ")" (returnType:Datatype)? BLOCK_OPEN Block BLOCK_CLOSE; diff --git a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java index db835ec52..1a173c6da 100644 --- a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java +++ b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java @@ -12,9 +12,8 @@ import org.nest.codegeneration.helpers.*; import org.nest.codegeneration.sympy.EquationsBlockProcessor; import org.nest.codegeneration.sympy.OdeTransformer; -import org.nest.nestml._ast.ASTBody; -import org.nest.nestml._ast.ASTNESTMLCompilationUnit; import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; import org.nest.nestml._ast.ASTOdeDeclaration; import org.nest.nestml._symboltable.NESTMLLanguage; import org.nest.nestml._symboltable.NestmlSymbols; @@ -70,6 +69,7 @@ private void analyseAndGenerate( workingVersion = solveOdesAndShapes(workingVersion, outputBase); workingVersion = AstUtils.deepCloneNeuronAndBuildSymbolTable(workingVersion, outputBase); + generateNestCode(workingVersion, outputBase); final String msg = "Successfully generated NEST code for: '" + astNeuron.getName() + "' in: '" @@ -81,8 +81,7 @@ private ASTNeuron solveOdesAndShapes( final ASTNeuron astNeuron, final Path outputBase) { - final ASTBody astBody = astNeuron.getBody(); - final Optional odesBlock = astBody.getOdeBlock(); + final Optional odesBlock = astNeuron.getOdeBlock(); if (odesBlock.isPresent()) { if (odesBlock.get().getShapes().size() == 0 && odesBlock.get().getODEs().size() > 1) { final String msg = String.format( @@ -233,10 +232,10 @@ private void setNeuronGenerationParameter( glex.setGlobalValue("variableHelper", new VariableHelper()); glex.setGlobalValue("odeTransformer", new OdeTransformer()); - glex.setGlobalValue("outputEvent", ASTOutputs.printOutputEvent(neuron.getBody())); + glex.setGlobalValue("outputEvent", ASTOutputs.printOutputEvent(neuron)); glex.setGlobalValue("isSpikeInput", ASTInputs.isSpikeInput(neuron)); glex.setGlobalValue("isCurrentInput", ASTInputs.isCurrentInput(neuron)); - glex.setGlobalValue("body", neuron.getBody()); + glex.setGlobalValue("body", neuron); final GslReferenceConverter converter = new GslReferenceConverter(); final ExpressionsPrettyPrinter expressionsPrinter = new LegacyExpressionPrinter(converter); @@ -247,11 +246,11 @@ private void setNeuronGenerationParameter( private void defineSolverType(final GlobalExtensionManagement glex, final ASTNeuron neuron) { - final ASTBody astBody = neuron.getBody(); glex.setGlobalValue("useGSL", false); - if (astBody.getOdeBlock().isPresent()) { - if (astBody.getOdeBlock().get().getShapes().size() == 0 || astBody.getOdeBlock().get().getODEs().size() > 1) { + if (neuron.getOdeBlock().isPresent()) { + if (neuron.getOdeBlock().get().getShapes().size() == 0 || + neuron.getOdeBlock().get().getODEs().size() > 1) { glex.setGlobalValue("names", new GslNames()); glex.setGlobalValue("useGSL", true); diff --git a/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java index 23349c17e..1c2690bc1 100644 --- a/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java +++ b/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java @@ -50,7 +50,6 @@ public String convertBinaryOperator(final String binaryOperator) { public String convertFunctionCall(final ASTFunctionCall astFunctionCall) { checkState(astFunctionCall.getEnclosingScope().isPresent(), "No scope assigned. Run SymbolTable creator."); - final Scope scope = astFunctionCall.getEnclosingScope().get(); final String functionName = astFunctionCall.getCalleeName(); if ("and".equals(functionName)) { diff --git a/src/main/java/org/nest/codegeneration/helpers/ASTInputs.java b/src/main/java/org/nest/codegeneration/helpers/ASTInputs.java index f9c3ae0f2..0d47c090e 100644 --- a/src/main/java/org/nest/codegeneration/helpers/ASTInputs.java +++ b/src/main/java/org/nest/codegeneration/helpers/ASTInputs.java @@ -5,10 +5,8 @@ */ package org.nest.codegeneration.helpers; -import de.monticore.ast.ASTNode; -import org.nest.nestml._ast.ASTBody; -import org.nest.nestml._ast.ASTInputLine; import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTInputLine; import java.util.List; import java.util.Optional; @@ -19,9 +17,9 @@ * @author plotnikov */ public class ASTInputs { - public static boolean isSpikeInput(final ASTNode node) { - final ASTBody bodyDecorator = (getBodyNode(node)); - final List neuronInputLines = bodyDecorator.getInputLines(); + + public static boolean isSpikeInput(final ASTNeuron node) { + final List neuronInputLines = node.getInputLines(); Optional inputSpikeCandidate = neuronInputLines .stream() .filter(ASTInputLine::isSpike) @@ -29,9 +27,8 @@ public static boolean isSpikeInput(final ASTNode node) { return inputSpikeCandidate.isPresent(); } - public static boolean isCurrentInput(final ASTNode node) { - final ASTBody bodyDecorator = (getBodyNode(node)); - final List neuronInputLines = bodyDecorator.getInputLines(); + public static boolean isCurrentInput(final ASTNeuron node) { + final List neuronInputLines = node.getInputLines(); Optional inputSpikeCandidate = neuronInputLines .stream() .filter(ASTInputLine::isCurrent) @@ -39,15 +36,5 @@ public static boolean isCurrentInput(final ASTNode node) { return inputSpikeCandidate.isPresent(); } - private static ASTBody getBodyNode(ASTNode node) { - ASTBody bodyElement;// TODO probably introduce a grammar rule for this - if (node instanceof ASTNeuron) { - bodyElement = ((ASTNeuron) node).getBody(); - } - else { - throw new RuntimeException("Unexpected instance of the neuron element"); - } - return bodyElement; - } } diff --git a/src/main/java/org/nest/codegeneration/helpers/ASTOutputs.java b/src/main/java/org/nest/codegeneration/helpers/ASTOutputs.java index be12d1ebe..8b236d99e 100644 --- a/src/main/java/org/nest/codegeneration/helpers/ASTOutputs.java +++ b/src/main/java/org/nest/codegeneration/helpers/ASTOutputs.java @@ -6,7 +6,6 @@ package org.nest.codegeneration.helpers; import de.monticore.ast.ASTNode; -import org.nest.nestml._ast.ASTBody; import org.nest.nestml._ast.ASTNeuron; import org.nest.nestml._ast.ASTOutput; @@ -18,12 +17,12 @@ * @author plotnikov */ public class ASTOutputs { - public static boolean isOutputEventPresent(final ASTBody astBody) { - return !astBody.getOutputs().isEmpty(); + public static boolean isOutputEventPresent(final ASTNeuron astNeuron) { + return !astNeuron.getOutputs().isEmpty(); } - public static String printOutputEvent(final ASTBody astBody) { - final List neuronOutputs = astBody.getOutputs(); + public static String printOutputEvent(final ASTNeuron astNeuron) { + final List neuronOutputs = astNeuron.getOutputs(); if (!neuronOutputs.isEmpty()) { ASTOutput output = neuronOutputs.get(0); @@ -42,11 +41,11 @@ else if (output.isCurrent()) { } } - private static ASTBody getBodyNode(ASTNode node) { - ASTBody bodyElement;// TODO probably introduce a grammar rule for this + private static ASTNeuron getBodyNode(ASTNode node) { + ASTNeuron bodyElement;// TODO probably introduce a grammar rule for this if (node instanceof ASTNeuron) { - bodyElement = ((ASTNeuron) node).getBody(); + bodyElement = ((ASTNeuron) node); } else { throw new RuntimeException("Unexpected instance of the neuron element"); diff --git a/src/main/java/org/nest/codegeneration/sympy/AstCreator.java b/src/main/java/org/nest/codegeneration/sympy/AstCreator.java index 8fcfcbb3f..729720af3 100644 --- a/src/main/java/org/nest/codegeneration/sympy/AstCreator.java +++ b/src/main/java/org/nest/codegeneration/sympy/AstCreator.java @@ -73,10 +73,17 @@ static ASTStmt createStatement(final String statementAsString) { } - static public ASTVar_Block createInternalBlock() { - final ASTVar_Block astVar_block = NESTMLNodeFactory.createASTVar_Block(); + static public ASTBlockWithVariables createInternalBlock() { + final ASTBlockWithVariables astVar_block = NESTMLNodeFactory.createASTBlockWithVariables(); astVar_block.setInternals(true); return astVar_block; } + + static public ASTBlockWithVariables createStateBlock() { + final ASTBlockWithVariables astVar_block = NESTMLNodeFactory.createASTBlockWithVariables(); + astVar_block.setState(true); + + return astVar_block; + } } diff --git a/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java b/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java index 1dcfd26d5..367858d20 100644 --- a/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java @@ -29,11 +29,11 @@ ASTNeuron addExactSolution( ASTNeuron workingVersion = astNeuron; //addVariableToInternals(astNeuron, p30File); - workingVersion.getBody().addToInternalBlock(createDeclaration("__h ms = resolution()")); + workingVersion.addToInternalBlock(createDeclaration("__h ms = resolution()")); workingVersion = addVariableToInternals(workingVersion, solverOutput.const_input); workingVersion = addVariableToInternals(workingVersion, solverOutput.ode_var_factor); - final List i_sumCalls = AstUtils.getAll(astNeuron.getBody().getOdeBlock().get(), ASTFunctionCall.class) + final List i_sumCalls = AstUtils.getAll(astNeuron.getOdeBlock().get(), ASTFunctionCall.class) .stream() .filter(astFunctionCall -> astFunctionCall.getCalleeName().equals(PredefinedFunctions.CURR_SUM)) .collect(toList()); @@ -41,7 +41,7 @@ ASTNeuron addExactSolution( // Apply spikes from the buffer to the state variable for (ASTFunctionCall i_sum_call : i_sumCalls) { final String bufferName = AstUtils.toString(i_sum_call.getArgs().get(1)); - solverOutput.ode_var_update_instructions.add(astNeuron.getBody().getEquations().get(0).getLhs().getName() + "+=" + bufferName); + solverOutput.ode_var_update_instructions.add(astNeuron.getEquations().get(0).getLhs().getName() + "+=" + bufferName); } workingVersion = replaceIntegrateCallThroughPropagation(workingVersion, solverOutput.ode_var_update_instructions); diff --git a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java index 2d89e722a..d26b334a7 100644 --- a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java +++ b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java @@ -5,9 +5,8 @@ */ package org.nest.codegeneration.sympy; -import org.nest.nestml._ast.ASTBody; -import org.nest.nestml._ast.ASTFunctionCall; import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTFunctionCall; import org.nest.reporting.Reporter; import java.nio.file.Path; @@ -39,18 +38,15 @@ public class EquationsBlockProcessor { * @return Transformed neuron with either: exact solution or transformed shapes to its ODE notation */ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path outputBase) { - final ASTBody astBody = astNeuron.getBody(); - if (astBody.getOdeBlock().isPresent()) { - + if (astNeuron.getOdeBlock().isPresent()) { reporter.reportProgress(String.format("The neuron %s contains an ODE block. It will be analysed.", astNeuron.getName())); - final Optional deltaShape = getFunctionCall(DELTA, astBody.getOdeBlock().get()); final ASTNeuron deepCopy = deepCloneNeuronAndBuildSymbolTable(astNeuron, outputBase); // this function is called only for neurons with an ode block. thus, retrieving it is safe. - if (deepCopy.getBody().getOdeBlock().get().getShapes().size() > 0 && - deepCopy.getBody().getOdeBlock().get().getODEs().size() == 1) { + if (deepCopy.getOdeBlock().get().getShapes().size() > 0 && + deepCopy.getOdeBlock().get().getODEs().size() == 1) { - final SolverOutput solverOutput = evaluator.solveOdeWithShapes(deepCopy.getBody().getOdeBlock().get(), outputBase); + final SolverOutput solverOutput = evaluator.solveOdeWithShapes(deepCopy.getOdeBlock().get(), outputBase); reporter.reportProgress("The model ODE with shapes will be analyzed."); reporter.reportProgress("The solver script is evaluated. Results are stored under " + outputBase.toString()); @@ -76,9 +72,9 @@ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path output return astNeuron; } } - else if (deepCopy.getBody().getOdeBlock().get().getShapes().size() > 0) { + else if (deepCopy.getOdeBlock().get().getShapes().size() > 0) { reporter.reportProgress("Shapes will be solved with GLS."); - final SolverOutput solverOutput = evaluator.solveShapes(deepCopy.getBody().getOdeBlock().get().getShapes(), outputBase); + final SolverOutput solverOutput = evaluator.solveShapes(deepCopy.getOdeBlock().get().getShapes(), outputBase); return shapesToOdesTransformer.transformShapesToOdeForm(astNeuron, solverOutput); } diff --git a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java index 331ebf5fb..4b16fe2ee 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java @@ -6,11 +6,9 @@ package org.nest.codegeneration.sympy; import org.nest.nestml._ast.ASTAssignment; -import org.nest.nestml._ast.ASTBody; -import org.nest.nestml._ast.ASTExpr; import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTExpr; import org.nest.nestml._symboltable.symbols.VariableSymbol; -import org.nest.nestml.prettyprinter.NESTMLPrettyPrinter; import org.nest.reporting.Reporter; import java.util.List; @@ -35,7 +33,7 @@ ASTNeuron addExactSolution( final ASTNeuron astNeuron, final SolverOutput solverOutput) { ASTNeuron workingVersion = astNeuron; - workingVersion.getBody().addToInternalBlock(createDeclaration("__h ms = resolution()")); + workingVersion.addToInternalBlock(createDeclaration("__h ms = resolution()")); workingVersion = addVariableToInternals(workingVersion, solverOutput.ode_var_factor); workingVersion = addVariableToInternals(workingVersion, solverOutput.const_input); @@ -43,7 +41,7 @@ ASTNeuron addExactSolution( workingVersion = addVariablesToInternals(workingVersion, solverOutput.propagator_elements); workingVersion = addVariablesToState(workingVersion, solverOutput.shape_state_variables); workingVersion = addShapeStateUpdatesToUpdateBlock(workingVersion, solverOutput); - workingVersion.getBody().removeOdeBlock(); + workingVersion.removeOdeBlock(); // oder is important, otherwise addShapeStateUpdatesToUpdateBlock will try to resolve state variables, // for which nor symbol are added. TODO filter them @@ -53,15 +51,13 @@ ASTNeuron addExactSolution( } private ASTNeuron addShapeStateUpdatesToUpdateBlock(final ASTNeuron astNeuron, final SolverOutput solverOutput) { - final ASTBody body = astNeuron.getBody(); - - addStateUpdates(solverOutput, body); - addUpdatesWithPSCInitialValues(solverOutput, body, variableNameExtracter, shapeNameExtracter); + addStateUpdates(solverOutput, astNeuron); + addUpdatesWithPSCInitialValues(solverOutput, astNeuron, variableNameExtracter, shapeNameExtracter); return astNeuron; } - private void addStateUpdates(final SolverOutput solverOutput, final ASTBody astBody) { + private void addStateUpdates(final SolverOutput solverOutput, final ASTNeuron astNeuron) { final Set tempVariables = solverOutput.updates_to_shape_state_variables .stream() .map(Map.Entry::getKey) @@ -72,17 +68,17 @@ private void addStateUpdates(final SolverOutput solverOutput, final ASTBody astB .stream() .map(update -> update + " real") .map(AstCreator::createDeclaration) - .forEach(astAssignment -> addDeclrationToUpdateBlock(astAssignment, astBody)); + .forEach(astAssignment -> addDeclrationToUpdateBlock(astAssignment, astNeuron)); solverOutput.updates_to_shape_state_variables .stream() .map(update -> update.getKey() + " = " + update.getValue()) .map(AstCreator::createAssignment) - .forEach(astAssignment -> addAssignmentToUpdateBlock(astAssignment, astBody)); + .forEach(astAssignment -> addAssignmentToUpdateBlock(astAssignment, astNeuron)); } // TODO: enable the optimization - private List computeShapeUpdates(final SolverOutput solverOutput, final ASTBody astBody) { + private List computeShapeUpdates(final SolverOutput solverOutput, final ASTNeuron astNeuron) { final List stateUpdatesASTs = solverOutput.updates_to_shape_state_variables .stream() @@ -96,7 +92,7 @@ private List computeShapeUpdates(final SolverOutput solverOutput, .collect(toList()); final List stateVariableNames = newArrayList(); - stateVariableNames.addAll(astBody.getStateSymbols() + stateVariableNames.addAll(astNeuron.getStateSymbols() .stream() .map(VariableSymbol::getName) .collect(toList())); @@ -117,7 +113,7 @@ private List computeShapeUpdates(final SolverOutput solverOutput, for (int j = 0; j < nodesToReplace.size(); ++j) { final Optional vectorizedVariable = getVectorizedVariable(nodesToReplace.get(j), scope); final ASTDeclaration aliasAst = createDeclaration(tmpInternalVariables.get(j) + " real " + printVectorParameter(vectorizedVariable) + " = " + printer.print(nodesToReplace.get(j))); - astBody.addToInternalBlock(aliasAst); + astNeuron.addToInternalBlock(aliasAst); } }*/ diff --git a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java index cf4ab5ceb..276e9bd10 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java @@ -9,6 +9,7 @@ import org.nest.nestml._ast.ASTEquation; import org.nest.nestml._ast.ASTNeuron; import org.nest.nestml._ast.ASTOdeDeclaration; +import org.nest.nestml.prettyprinter.NESTMLPrettyPrinter; import java.util.List; import java.util.Map; @@ -25,18 +26,19 @@ class ShapesToOdesTransformer extends TransformerBase { ASTNeuron transformShapesToOdeForm(final ASTNeuron astNeuron, final SolverOutput solverOutput) { - checkArgument(astNeuron.getBody().getOdeBlock().isPresent()); + checkArgument(astNeuron.getOdeBlock().isPresent()); ASTNeuron workingVersion = addVariablesToState(astNeuron, solverOutput.shape_state_variables); workingVersion = addVariablesToInternals(workingVersion, solverOutput.initial_values); workingVersion = removeShapes(workingVersion); addUpdatesWithPSCInitialValues( solverOutput, - workingVersion.getBody(), + workingVersion, variableNameExtracter, shapeNameExtracter); - addStateShapeEquationsToEquationsBlock(solverOutput.shape_state_odes, workingVersion.getBody().getOdeBlock().get()); + addStateShapeEquationsToEquationsBlock(solverOutput.shape_state_odes, workingVersion.getOdeBlock().get()); + return workingVersion; } diff --git a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java index 883833650..5b7c59555 100644 --- a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java +++ b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java @@ -49,20 +49,19 @@ public class TransformerBase { private final NESTMLParser parser = new NESTMLParser(); ASTNeuron addVariablesToState(final ASTNeuron astNeuron, final List shapeStateVariables) { - checkState(astNeuron.getBody().getEnclosingScope().isPresent()); - final Scope scope = astNeuron.getBody().getEnclosingScope().get(); - final List correspondingShapeSymbols = shapeStateVariables - .stream() - .map(this::getShapeNameFromStateVariable) - .map(shapeName -> resolve(shapeName, scope)) - .collect(Collectors.toList()); + //final List correspondingShapeSymbols = shapeStateVariables + // .stream() + // .map(this::getShapeNameFromStateVariable) + // .collect(Collectors.toList()); for (int i = 0; i < shapeStateVariables.size(); ++i) { - final String vectorDatatype = correspondingShapeSymbols.get(i).isVector()?"[" + correspondingShapeSymbols.get(i).getVectorParameter().get() + "]":""; - final String stateVarDeclaration = shapeStateVariables.get(i) + " real " + vectorDatatype; + // final Scope scope = astNeuron.getEnclosingScope().get(); + //checkState(astNeuron.getEnclosingScope().isPresent()); + //final String vectorDatatype = correspondingShapeSymbols.get(i).isVector()?"[" + correspondingShapeSymbols.get(i).getVectorParameter().get() + "]":""; + final String stateVarDeclaration = shapeStateVariables.get(i) + " real"; - astNeuron.getBody().addToStateBlock(createDeclaration(stateVarDeclaration)); + astNeuron.addToStateBlock(createDeclaration(stateVarDeclaration)); } return astNeuron; @@ -108,7 +107,7 @@ ASTNeuron addVariableToInternals( + " = " + declaration.getValue(); final ASTDeclaration astDeclaration = parser.parseDeclaration(new StringReader(declarationString)).get(); vectorVariable.ifPresent(var -> astDeclaration.setSizeParameter(var.getVectorParameter().get())); - astNeuron.getBody().addToInternalBlock(astDeclaration); + astNeuron.addToInternalBlock(astDeclaration); return astNeuron; } catch (IOException e) { @@ -118,13 +117,10 @@ ASTNeuron addVariableToInternals( } ASTNeuron replaceIntegrateCallThroughPropagation(final ASTNeuron astNeuron, List propagatorSteps) { - - final ASTBody astBodyDecorator = astNeuron.getBody(); - // It must work for multiple integrate calls! final Optional integrateCall = AstUtils.getFunctionCall( PredefinedFunctions.INTEGRATE_ODES, - astBodyDecorator.getDynamics().get(0)); + astNeuron.getUpdateBlocks().get(0)); if (integrateCall.isPresent()) { final Optional smallStatement = AstUtils.getParent(integrateCall.get(), astNeuron); @@ -162,7 +158,7 @@ ASTNeuron replaceIntegrateCallThroughPropagation(final ASTNeuron astNeuron, List */ void addUpdatesWithPSCInitialValues( final SolverOutput solverOutput, - final ASTBody body, + final ASTNeuron body, final Function stateVariableNameExtracter, final Function shapeNameExtracter) { final List i_sumCalls = OdeTransformer.get_sumFunctionCalls(body.getOdeBlock().get()); @@ -194,7 +190,7 @@ void addUpdatesWithPSCInitialValues( } - void addAssignmentToUpdateBlock(final ASTAssignment astAssignment, final ASTBody astBody) { + void addAssignmentToUpdateBlock(final ASTAssignment astAssignment, final ASTNeuron astNeuron) { final ASTStmt astStmt = NESTMLNodeFactory.createASTStmt(); final ASTSmall_Stmt astSmall_stmt = NESTMLNodeFactory.createASTSmall_Stmt(); @@ -203,10 +199,10 @@ void addAssignmentToUpdateBlock(final ASTAssignment astAssignment, final ASTBody // Goal: add the y-assignments at the end of the expression astSmall_stmt.setAssignment(astAssignment); - astBody.getDynamics().get(0).getBlock().getStmts().add(astStmt); + astNeuron.getUpdateBlocks().get(0).getBlock().getStmts().add(astStmt); } - void addDeclrationToUpdateBlock(final ASTDeclaration astDeclaration, final ASTBody astBody) { + void addDeclrationToUpdateBlock(final ASTDeclaration astDeclaration, final ASTNeuron astNeuron) { final ASTStmt astStmt = NESTMLNodeFactory.createASTStmt(); final ASTSmall_Stmt astSmall_stmt = NESTMLNodeFactory.createASTSmall_Stmt(); @@ -215,7 +211,7 @@ void addDeclrationToUpdateBlock(final ASTDeclaration astDeclaration, final ASTBo // Goal: add the y-assignments at the end of the expression astSmall_stmt.setDeclaration(astDeclaration); - astBody.getDynamics().get(0).getBlock().getStmts().add(astStmt); + astNeuron.getUpdateBlocks().get(0).getBlock().getStmts().add(astStmt); } ASTStmt statement(final ASTAssignment astAssignment) { @@ -227,10 +223,7 @@ ASTStmt statement(final ASTAssignment astAssignment) { } ASTNeuron removeShapes(ASTNeuron astNeuron) { - //final List stateVariablesDeclarations = shapesToStateVariables( - // astNeuron.getBody().getOdeBlock().get()); - // stateVariablesDeclarations.forEach(stateVariable -> astNeuron.getBody().addToStateBlock(stateVariable)); - astNeuron.getBody().getOdeBlock().get().getShapes().clear(); + astNeuron.getOdeBlock().get().getShapes().clear(); return astNeuron; } diff --git a/src/main/java/org/nest/nestml/_ast/ASTDeclaration.java b/src/main/java/org/nest/nestml/_ast/ASTDeclaration.java index bd89d1e42..81c72adb8 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTDeclaration.java +++ b/src/main/java/org/nest/nestml/_ast/ASTDeclaration.java @@ -31,7 +31,7 @@ * @author plotnikov */ public class ASTDeclaration extends ASTDeclarationTOP { - private final List commentLines = Lists.newArrayList(); + private final List docStrings = Lists.newArrayList(); protected ASTDeclaration(){ @@ -41,20 +41,19 @@ public ASTDeclaration(List vars, ASTDatatype datatype, String sizeParameter, ASTExpr expr, - String sL_comment, ASTExpr invariant, boolean recordable, boolean function) { - super(vars, datatype, sizeParameter, expr, sL_comment, invariant, recordable, function); + super(vars, datatype, sizeParameter, expr, invariant, recordable, function); } - public void addComment(final String comment) { - commentLines.add(comment); + public void addDocString(final String docString) { + docStrings.add(docString); } - public List getComments() { - return commentLines; + public List getDocStrings() { + return docStrings; } } diff --git a/src/main/java/org/nest/nestml/_ast/ASTBody.java b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java similarity index 55% rename from src/main/java/org/nest/nestml/_ast/ASTBody.java rename to src/main/java/org/nest/nestml/_ast/ASTNeuron.java index a73bd0006..8ae3f0124 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTBody.java +++ b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java @@ -5,7 +5,6 @@ */ package org.nest.nestml._ast; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import de.monticore.ast.ASTNode; import de.monticore.symboltable.Scope; @@ -13,7 +12,6 @@ import org.nest.nestml._symboltable.symbols.VariableSymbol; import org.nest.utils.AstUtils; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -28,77 +26,67 @@ * * @author plotnikov */ -@SuppressWarnings({"unused"}) // function are used in freemarker templates -public class ASTBody extends ASTBodyTOP { +public class ASTNeuron extends ASTNeuronTOP { - public ASTBody() { + public ASTNeuron() { // this constructor is used in the generated code and must be provided } - public ASTBody( + public ASTNeuron( + final String name, final ASTBLOCK_OPEN bLOCK_open, final List nEWLINEs, - final List bodyElements, + final List blockWithVariabless, + final List updateBlocks, + final List equationss, + final List inputs, + final List outputs, + final List functions, final ASTBLOCK_CLOSE bLOCK_close) { - super(bLOCK_open, nEWLINEs, bodyElements, bLOCK_close); + super(name, bLOCK_open, nEWLINEs, blockWithVariabless, updateBlocks, equationss, inputs, outputs, functions, bLOCK_close); } - // Retrieves model structure blocks - public List getFunctions() { - List result = this.getBodyElements().stream() - .filter(be -> be instanceof ASTFunction) - .map(be -> (ASTFunction) be) - .collect(Collectors.toList()); - - return ImmutableList.copyOf(result); - } - - public List getDynamics() { - List result = this.getBodyElements().stream() - .filter(be -> be instanceof ASTDynamics) - .map(be -> (ASTDynamics) be) - .collect(Collectors.toList()); - - return ImmutableList.copyOf(result); - } - - public Optional getDynamicsBlock() { - return this.getBodyElements().stream() - .filter(be -> be instanceof ASTDynamics) - .map(be -> (ASTDynamics) be) - .findFirst(); + public Optional getUpdateBlock() { + return this.getUpdateBlocks().stream().findFirst(); } + /** + * It is used in the dynamics functions + * @return + */ public String printDynamicsComment() { - return printBlockComment(getDynamicsBlock()); + return printBlockComment(getUpdateBlock()); } - public Optional getStateBlock() { - return this.getBodyElements().stream() - .filter(be -> be instanceof ASTVar_Block && ((ASTVar_Block) be).isState()) + public Optional getStateBlock() { + return this.getBlockWithVariabless() + .stream() + .filter(ASTBlockWithVariables::isState) .findFirst(); // there is at most one } public List getStateDeclarations() { - final Optional stateBlock = getStateBlock(); + final Optional stateBlock = getStateBlock(); final List result = Lists.newArrayList(); - stateBlock.ifPresent(block -> result.addAll( ((ASTVar_Block) block).getDeclarations())); + stateBlock.ifPresent(block -> result.addAll( block.getDeclarations())); return result; } public String printStateComment() { return printBlockComment(getStateBlock()); } - public Optional getParameterBlock() { - return this.getBodyElements().stream() - .filter(be -> be instanceof ASTVar_Block && ((ASTVar_Block) be).isParameters ()) + + public Optional getParameterBlock() { + return this.getBlockWithVariabless() + .stream() + .filter(ASTBlockWithVariables::isParameters) .findFirst(); // there is at most one } public List getParameterDeclarations() { - final Optional stateBlock = getParameterBlock(); + final Optional stateBlock = getParameterBlock(); final List result = Lists.newArrayList(); - stateBlock.ifPresent(block -> result.addAll( ((ASTVar_Block) block).getDeclarations())); + stateBlock.ifPresent(block -> result.addAll(block.getDeclarations())); return result; } @@ -106,16 +94,17 @@ public String printParameterComment() { return printBlockComment(getParameterBlock()); } - public Optional getInternalBlock() { - return this.getBodyElements().stream() - .filter(be -> be instanceof ASTVar_Block && ((ASTVar_Block) be).isInternals()) + public Optional getInternalBlock() { + return this.getBlockWithVariabless() + .stream() + .filter(ASTBlockWithVariables::isInternals) .findFirst(); // there is at most one } public List getInternalDeclarations() { - final Optional stateBlock = getInternalBlock(); + final Optional stateBlock = getInternalBlock(); final List result = Lists.newArrayList(); - stateBlock.ifPresent(block -> result.addAll( ((ASTVar_Block) block).getDeclarations())); + stateBlock.ifPresent(block -> result.addAll(block.getDeclarations())); return result; } @@ -151,17 +140,10 @@ public List variablesDefinedByODE() { } private Optional findEquationsBlock() { - final Optional equations = this.getBodyElements() + return this.getEquationss() .stream() - .filter(be -> be instanceof ASTEquations) .findFirst(); - if (equations.isPresent()) { - // only ASTEquations are filtered - return Optional.of((ASTEquations) equations.get()); - } - else { - return Optional.empty(); - } + } private String printBlockComment(final Optional block) { @@ -170,7 +152,7 @@ private String printBlockComment(final Optional block) { // STATE variables handling public List getStateSymbols() { - return this.getEnclosingScope().get().resolveLocally(VariableSymbol.KIND) + return this.getSpannedScope().get().resolveLocally(VariableSymbol.KIND) .stream() .map(stateSymbol -> (VariableSymbol) stateSymbol) .filter(VariableSymbol::isState) @@ -179,7 +161,7 @@ public List getStateSymbols() { } public List getOdeDefinedSymbols() { - return this.getEnclosingScope().get().resolveLocally(VariableSymbol.KIND) + return this.getSpannedScope().get().resolveLocally(VariableSymbol.KIND) .stream() .map(stateSymbol -> (VariableSymbol) stateSymbol) .filter(VariableSymbol::isState) @@ -189,7 +171,7 @@ public List getOdeDefinedSymbols() { } public List getStateSymbolsWithoutOde() { - return this.getEnclosingScope().get().resolveLocally(VariableSymbol.KIND) + return this.getSpannedScope().get().resolveLocally(VariableSymbol.KIND) .stream() .map(stateSymbol -> (VariableSymbol) stateSymbol) .filter(VariableSymbol::isState) @@ -199,14 +181,14 @@ public List getStateSymbolsWithoutOde() { } public List getStateAliasSymbols() { - return getVariableSymbols(getDeclarationsFromBlock(ASTVar_Block::isState), getEnclosingScope().get()) + return getVariableSymbols(getDeclarationsFromBlock(ASTBlockWithVariables::isState), getSpannedScope().get()) .stream() .filter(VariableSymbol::isFunction) .collect(Collectors.toList()); } public List getStateNonAliasSymbols() { - final Collection variableSymbols = getEnclosingScope().get().resolveLocally(VariableSymbol.KIND); + final Collection variableSymbols = getSpannedScope().get().resolveLocally(VariableSymbol.KIND); return variableSymbols .stream() .filter(VariableSymbol::isState) @@ -216,18 +198,18 @@ public List getStateNonAliasSymbols() { // Parameter variable handling public List getParameterSymbols() { - return getVariableSymbols(getDeclarationsFromBlock(ASTVar_Block::isParameters ), getEnclosingScope().get()); + return getVariableSymbols(getDeclarationsFromBlock(ASTBlockWithVariables::isParameters ), getSpannedScope().get()); } public List getParameterAliasSymbols() { - return getVariableSymbols(getDeclarationsFromBlock(ASTVar_Block::isParameters ), getEnclosingScope().get()) + return getVariableSymbols(getDeclarationsFromBlock(ASTBlockWithVariables::isParameters ), getSpannedScope().get()) .stream() .filter(VariableSymbol::isFunction) .collect(Collectors.toList()); } public List getParameterNonAliasSymbols() { - return getVariableSymbols(getDeclarationsFromBlock(ASTVar_Block::isParameters ), getEnclosingScope().get()) + return getVariableSymbols(getDeclarationsFromBlock(ASTBlockWithVariables::isParameters ), getSpannedScope().get()) .stream() .filter(variable -> !variable.isFunction()) .collect(Collectors.toList()); @@ -235,32 +217,29 @@ public List getParameterNonAliasSymbols() { // Internal variables handling public List getInternalSymbols() { - return getVariableSymbols(getDeclarationsFromBlock(ASTVar_Block::isInternals), getEnclosingScope().get()); + return getVariableSymbols(getDeclarationsFromBlock(ASTBlockWithVariables::isInternals), getSpannedScope().get()); } public List getInternalAliasSymbols() { - return getVariableSymbols(getDeclarationsFromBlock(ASTVar_Block::isInternals), getEnclosingScope().get()) + return getVariableSymbols(getDeclarationsFromBlock(ASTBlockWithVariables::isInternals), getSpannedScope().get()) .stream() .filter(VariableSymbol::isFunction) .collect(Collectors.toList()); } public List getInternalNonAliasSymbols() { - return getVariableSymbols(getDeclarationsFromBlock(ASTVar_Block::isInternals), getEnclosingScope().get()) + return getVariableSymbols(getDeclarationsFromBlock(ASTBlockWithVariables::isInternals), getSpannedScope().get()) .stream() .filter(variable -> !variable.isFunction()) .collect(Collectors.toList()); } - private List getDeclarationsFromBlock(final Predicate predicate) { + private List getDeclarationsFromBlock(final Predicate blockSelector) { final List result = Lists.newArrayList(); - this.getBodyElements().stream().filter(be -> be instanceof ASTVar_Block).forEach(be -> { - ASTVar_Block block = (ASTVar_Block) be; - if (predicate.test(block)) { - result.addAll(block.getDeclarations()); - } - }); + this.getBlockWithVariabless().stream() + .filter(blockSelector) + .forEach(block -> result.addAll(block.getDeclarations())); return result; } @@ -284,14 +263,11 @@ public List getParameterInvariants() { public void addToInternalBlock(final ASTDeclaration astDeclaration) { if (!this.getInternalBlock().isPresent()) { - final ASTVar_Block internalBlock = AstCreator.createInternalBlock(); - getBodyElements().add(internalBlock); + final ASTBlockWithVariables internalBlock = AstCreator.createInternalBlock(); + getBlockWithVariabless().add(internalBlock); } - this.getBodyElements().stream().filter(variableBlock -> variableBlock instanceof ASTVar_Block).forEach(be -> { - - ASTVar_Block block = (ASTVar_Block) be; - + this.getBlockWithVariabless().forEach(block -> { if (block.isInternals()) { block.getDeclarations().add(astDeclaration); } @@ -300,70 +276,48 @@ public void addToInternalBlock(final ASTDeclaration astDeclaration) { } - public void addToStateBlock(final ASTDeclaration ASTDeclaration) { - this.getBodyElements().stream().filter(variableBlock -> variableBlock instanceof ASTVar_Block).forEach(be -> { - - ASTVar_Block block = (ASTVar_Block) be; + public void addToStateBlock(final ASTDeclaration astDeclaration) { + if (!this.getInternalBlock().isPresent()) { + final ASTBlockWithVariables stateBlock = AstCreator.createStateBlock(); + getBlockWithVariabless().add(stateBlock); + } + this.getBlockWithVariabless().forEach(block -> { if (block.isState()) { - block.getDeclarations().add(ASTDeclaration); + block.getDeclarations().add(astDeclaration); } }); } - private Optional findDynamics() { - return this.getBodyElements().stream() - .filter(be -> be instanceof ASTDynamics) - .findFirst(); + private Optional findDynamics() { + return this.getUpdateBlocks().stream().findFirst(); } public List getInputLines() { - List result = new ArrayList(); - - for (ASTBodyElement be : this.getBodyElements()) { - if (be instanceof ASTInput) { - ASTInput in = (ASTInput) be; - for (ASTInputLine inline : in.getInputLines()) { - result.add(inline); - } - } - } - - return ImmutableList.copyOf(result); - } + List result = Lists.newArrayList(); - public List getOutputs() { - final List result = this.getBodyElements().stream() - .filter(be -> be instanceof ASTOutput) - .map(be -> (ASTOutput) be) - .collect(Collectors.toList()); + for (final ASTInput inputLine : this.getInputs()) { + result.addAll(inputLine.getInputLines()); + } - return ImmutableList.copyOf(result); + return result; } public Optional getOdeBlock() { - final Optional odeBlock = bodyElements - .stream() - .filter(astBodyElement -> astBodyElement instanceof ASTEquations) - .findAny(); + final Optional odeBlock = findEquationsBlock(); // checked by the filter conditions - return odeBlock.map(astBodyElement -> ((ASTEquations) astBodyElement).getOdeDeclaration()); + return odeBlock.map(astBodyElement -> (astBodyElement).getOdeDeclaration()); } public void removeOdeBlock() { - final Optional odeBlock = bodyElements - .stream() - .filter(astBodyElement -> astBodyElement instanceof ASTEquations) - .findAny(); - - odeBlock.ifPresent(astBodyElement -> bodyElements.remove(astBodyElement)); + this.setEquationss(Lists.newArrayList()); } public List getODEAliases() { - return enclosingScope.get().resolveLocally(VariableSymbol.KIND) + return spannedScope.get().resolveLocally(VariableSymbol.KIND) .stream() .map(variable -> (VariableSymbol) variable) .filter(variable -> variable.isFunction() && variable.isInEquation()) @@ -371,7 +325,7 @@ public List getODEAliases() { } public List getInputBuffers() { - return enclosingScope.get().resolveLocally(VariableSymbol.KIND) + return spannedScope.get().resolveLocally(VariableSymbol.KIND) .stream() .map(inputBuffer -> (VariableSymbol) inputBuffer) .filter(inputBuffer -> inputBuffer.isSpikeBuffer() || inputBuffer.isCurrentBuffer()) @@ -379,7 +333,7 @@ public List getInputBuffers() { } public List getSpikeBuffers() { - return enclosingScope.get().resolveLocally(VariableSymbol.KIND) + return spannedScope.get().resolveLocally(VariableSymbol.KIND) .stream() .map(inputBuffer -> (VariableSymbol) inputBuffer) .filter(VariableSymbol::isSpikeBuffer) @@ -387,7 +341,7 @@ public List getSpikeBuffers() { } public List getCurrentBuffers() { - return enclosingScope.get().resolveLocally(VariableSymbol.KIND) + return spannedScope.get().resolveLocally(VariableSymbol.KIND) .stream() .map(inputBuffer -> (VariableSymbol) inputBuffer) .filter(VariableSymbol::isCurrentBuffer) @@ -395,7 +349,7 @@ public List getCurrentBuffers() { } public List getMultipleReceptors() { - return enclosingScope.get().resolveLocally(VariableSymbol.KIND) + return spannedScope.get().resolveLocally(VariableSymbol.KIND) .stream() .map(inputBuffer -> (VariableSymbol) inputBuffer) .filter(VariableSymbol::isSpikeBuffer) @@ -404,7 +358,7 @@ public List getMultipleReceptors() { } public boolean isArrayBuffer() { - return enclosingScope.get().resolveLocally(VariableSymbol.KIND) + return spannedScope.get().resolveLocally(VariableSymbol.KIND) .stream() .map(inputBuffer -> (VariableSymbol) inputBuffer) .filter(VariableSymbol::isBuffer) diff --git a/src/main/java/org/nest/nestml/_cocos/FunctionDefinedMultipleTimes.java b/src/main/java/org/nest/nestml/_cocos/FunctionDefinedMultipleTimes.java index 3e55346aa..2b54d59d9 100644 --- a/src/main/java/org/nest/nestml/_cocos/FunctionDefinedMultipleTimes.java +++ b/src/main/java/org/nest/nestml/_cocos/FunctionDefinedMultipleTimes.java @@ -8,9 +8,8 @@ import de.monticore.symboltable.Scope; import de.monticore.symboltable.Symbol; import de.se_rwth.commons.logging.Log; -import org.nest.nestml._ast.ASTBody; -import org.nest.nestml._ast.ASTFunction; import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTFunction; import org.nest.nestml._symboltable.symbols.MethodSymbol; import org.nest.nestml._symboltable.symbols.NeuronSymbol; @@ -27,10 +26,10 @@ public class FunctionDefinedMultipleTimes implements NESTMLASTNeuronCoCo { @Override public void check(final ASTNeuron astNeuron) { - final ASTBody astBodyDecorator = (astNeuron.getBody()); + final ASTNeuron astNeuronDecorator = (astNeuron); final Optional neuronSymbol = (Optional) astNeuron.getSymbol(); if (neuronSymbol.isPresent()) { - astBodyDecorator.getFunctions().forEach(this::checkFunctionName); + astNeuronDecorator.getFunctions().forEach(this::checkFunctionName); } else { final String msg = NestmlErrorStrings.getErrorMsgNeuronHasNoSymbol(this,astNeuron.getName()); diff --git a/src/main/java/org/nest/nestml/_cocos/MemberVariableDefinedMultipleTimes.java b/src/main/java/org/nest/nestml/_cocos/MemberVariableDefinedMultipleTimes.java index 0c4e2d915..7d4786c1e 100644 --- a/src/main/java/org/nest/nestml/_cocos/MemberVariableDefinedMultipleTimes.java +++ b/src/main/java/org/nest/nestml/_cocos/MemberVariableDefinedMultipleTimes.java @@ -8,9 +8,8 @@ import com.google.common.collect.Maps; import de.monticore.ast.ASTNode; import de.se_rwth.commons.SourcePosition; -import org.nest.nestml._ast.ASTBody; -import org.nest.nestml._ast.ASTDeclaration; import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTDeclaration; import org.nest.nestml._ast.ASTVariable; import org.nest.utils.AstUtils; @@ -33,11 +32,7 @@ public class MemberVariableDefinedMultipleTimes implements NESTMLASTNeuronCoCo { @Override - public void check(ASTNeuron neuron) { - check(neuron.getBody()); - } - - private void check(ASTBody body) { + public void check(ASTNeuron body) { Map varNames = Maps.newHashMap(); body.getStateDeclarations().forEach(declaration -> addNames(varNames, declaration)); body.getParameterDeclarations().forEach(declaration -> addNames(varNames, declaration)); diff --git a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoInput.java b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoInput.java index 779bfb4f3..ba5230226 100644 --- a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoInput.java +++ b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoInput.java @@ -8,7 +8,6 @@ import org.nest.nestml._ast.*; import java.util.List; -import java.util.stream.Collectors; import static de.se_rwth.commons.logging.Log.error; @@ -20,20 +19,20 @@ public class NeuronWithMultipleOrNoInput implements NESTMLASTNeuronCoCo { public void check(final ASTNeuron neuron) { - final ASTBody body = (neuron.getBody()); - List inputBlocks = body.getBodyElements().stream().filter(be -> be instanceof ASTInput).collect(Collectors.toList()); + List inputBlocks = neuron.getInputs(); if (inputBlocks.size() == 0) { final String msg = NestmlErrorStrings.errorNoInput(this); error(msg, neuron.get_SourcePositionStart()); } else if (inputBlocks.size() == 1) { - final List inputs = body.getInputLines(); + final List inputs = neuron.getInputLines(); if (inputs.isEmpty()) { final String msg = NestmlErrorStrings.errorNoInput(this); error(msg, neuron.get_SourcePositionStart()); } + } else { // #inputs > 1 final String msg = NestmlErrorStrings.errorMultipleInputs(this); diff --git a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoOutput.java b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoOutput.java index a771abed0..36cd8f79d 100644 --- a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoOutput.java +++ b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoOutput.java @@ -6,7 +6,6 @@ package org.nest.nestml._cocos; import de.se_rwth.commons.logging.Log; -import org.nest.nestml._ast.ASTBody; import org.nest.nestml._ast.ASTNeuron; import org.nest.nestml._ast.ASTOutput; @@ -21,7 +20,7 @@ public class NeuronWithMultipleOrNoOutput implements NESTMLASTNeuronCoCo { public void check(ASTNeuron neuron) { - ASTBody bodyDecorator = (neuron.getBody()); + ASTNeuron bodyDecorator = (neuron); final List outputs = bodyDecorator.getOutputs(); if (outputs.size() == 0) { diff --git a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoUpdate.java b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoUpdate.java index 484257118..f0b70e71e 100644 --- a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoUpdate.java +++ b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoUpdate.java @@ -5,7 +5,6 @@ */ package org.nest.nestml._cocos; -import org.nest.nestml._ast.ASTBody; import org.nest.nestml._ast.ASTNeuron; import static de.se_rwth.commons.logging.Log.error; @@ -18,15 +17,14 @@ public class NeuronWithMultipleOrNoUpdate implements NESTMLASTNeuronCoCo { public void check(final ASTNeuron neuron) { - final ASTBody bodyDecorator = neuron.getBody(); - if (bodyDecorator.getDynamics().isEmpty()) { + if (neuron.getUpdateBlocks().isEmpty()) { final String msg = NestmlErrorStrings.getErrorMsgDynamicsNotPresent(this); error(msg, neuron.get_SourcePositionStart()); } - if (bodyDecorator.getDynamics().size() > 1) { + if (neuron.getUpdateBlocks().size() > 1) { final String msg = NestmlErrorStrings.getErrorMsgMultipleDynamics(this); error( msg, neuron.get_SourcePositionStart()); } diff --git a/src/main/java/org/nest/nestml/_cocos/VariableBlockDefinedMultipleTimes.java b/src/main/java/org/nest/nestml/_cocos/VariableBlockDefinedMultipleTimes.java index 62eaf5aa6..4723a898a 100644 --- a/src/main/java/org/nest/nestml/_cocos/VariableBlockDefinedMultipleTimes.java +++ b/src/main/java/org/nest/nestml/_cocos/VariableBlockDefinedMultipleTimes.java @@ -21,9 +21,8 @@ package org.nest.nestml._cocos; import de.se_rwth.commons.logging.Log; -import org.nest.nestml._ast.ASTBody; +import org.nest.nestml._ast.ASTBlockWithVariables; import org.nest.nestml._ast.ASTNeuron; -import org.nest.nestml._ast.ASTVar_Block; import java.util.List; import java.util.function.Predicate; @@ -37,14 +36,13 @@ public class VariableBlockDefinedMultipleTimes implements NESTMLASTNeuronCoCo { public void check(final ASTNeuron neuron) { - final ASTBody bodyDecorator = neuron.getBody(); - checkBlock(bodyDecorator, "state", ASTVar_Block::isState); - checkBlock(bodyDecorator, "parameters", ASTVar_Block::isParameters); - checkBlock(bodyDecorator, "internals", ASTVar_Block::isInternals); + checkBlock(neuron, "state", ASTBlockWithVariables::isState); + checkBlock(neuron, "parameters", ASTBlockWithVariables::isParameters); + checkBlock(neuron, "internals", ASTBlockWithVariables::isInternals); } - private void checkBlock(final ASTBody astBody, final String blockName, final Predicate blockType) { - final List blocks = filterVarBlockByType(astBody, blockType); + private void checkBlock(final ASTNeuron astNeuron, final String blockName, final Predicate blockType) { + final List blocks = filterVarBlockByType(astNeuron, blockType); if (blocks.size() > 1) { final String msg = NestmlErrorStrings.error(this, blocks.get(0).get_SourcePositionStart(), blockName); Log.error(msg); @@ -52,11 +50,9 @@ private void checkBlock(final ASTBody astBody, final String blockName, final Pre } - private List filterVarBlockByType(final ASTBody astBody, final Predicate blockType) { - return astBody.getBodyElements() + private List filterVarBlockByType(final ASTNeuron astNeuron, final Predicate blockType) { + return astNeuron.getBlockWithVariabless() .stream() - .filter(astBodyElement -> astBodyElement instanceof ASTVar_Block) - .map(astBodyElement -> (ASTVar_Block) astBodyElement) .filter(blockType) .collect(Collectors.toList()); } diff --git a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java index 730b8aaa5..b9f056ee4 100644 --- a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java +++ b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java @@ -56,7 +56,7 @@ public Optional parseNESTMLCompilationUnit(final Strin for (final ASTDeclaration astDeclaration:declarations) { int line = astDeclaration.get_SourcePositionStart().getLine(); final List variableComments = extractComments(sourceText, line - 1); - variableComments.forEach(astDeclaration::addComment); + variableComments.forEach(astDeclaration::addDocString); } } @@ -71,14 +71,14 @@ private List extractComments(final List sourceText, int lineInde final List result = Lists.newArrayList(); String DOC_STRING_START = "##"; if (sourceText.get(lineIndex).contains(DOC_STRING_START)) { - result.add(sourceText.get(lineIndex).substring(sourceText.get(lineIndex).indexOf(DOC_STRING_START) + 1).trim()); + result.add(sourceText.get(lineIndex).substring(sourceText.get(lineIndex).indexOf(DOC_STRING_START)).trim()); } int searchBackIndex = lineIndex - 1; while (searchBackIndex > 0) { final String currentLine = sourceText.get(searchBackIndex); if (currentLine.trim().startsWith(DOC_STRING_START)) { - result.add(0, currentLine.substring(currentLine.indexOf(DOC_STRING_START) + 1).trim()); + result.add(0, currentLine.substring(currentLine.indexOf(DOC_STRING_START)).trim()); } else { break; diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java index 8eda81786..40ed90444 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java @@ -42,7 +42,7 @@ public class NESTMLSymbolTableCreator extends CommonSymbolTableCreator implements NESTMLVisitor { private static String LOGGER_NAME = "NESTML_SymbolTableCreator"; private Optional currentTypeSymbol = empty(); - private Optional varBlock = empty(); + private Optional varBlock = empty(); public NESTMLSymbolTableCreator( final ResolvingConfiguration resolvingConfiguration, @@ -98,8 +98,8 @@ public void visit(final ASTNeuron astNeuron) { public void endVisit(final ASTNeuron astNeuron) { setEnclosingScopeOfNodes(astNeuron); - if (astNeuron.getBody().getOdeBlock().isPresent()) { - addFunctionVariables(astNeuron.getBody().getOdeBlock().get()); + if (astNeuron.getOdeBlock().isPresent()) { + addFunctionVariables(astNeuron.getOdeBlock().get()); } // new variable from the ODE block could be added. Check, whether they don't clutter with existing one @@ -112,13 +112,13 @@ public void endVisit(final ASTNeuron astNeuron) { if (undefinedMethods.isEmpty()) { final List multipleDefinitions = nestmlCoCosManager.checkThatElementDefinedAtMostOnce(astNeuron); if (multipleDefinitions.isEmpty()) { - if (astNeuron.getBody().getOdeBlock().isPresent()) { + if (astNeuron.getOdeBlock().isPresent()) { final List afterAddingDerivedVariables = nestmlCoCosManager.checkThatElementDefinedAtMostOnce(astNeuron); if (afterAddingDerivedVariables.isEmpty()) { - assignOdeToVariables(astNeuron.getBody().getOdeBlock().get()); - markConductanceBasedBuffers(astNeuron.getBody().getOdeBlock().get(), astNeuron.getBody().getInputLines()); + assignOdeToVariables(astNeuron.getOdeBlock().get()); + markConductanceBasedBuffers(astNeuron.getOdeBlock().get(), astNeuron.getInputLines()); } else { final String msg = LOGGER_NAME + " : Cannot correctly build the symboltable, at least one variable is " + @@ -227,6 +227,7 @@ private void markConductanceBasedBuffers(final ASTOdeDeclaration astOdeDeclarati .filter(VariableSymbol::isSpikeBuffer) .collect(Collectors.toList()); final List equations = Lists.newArrayList(); + equations.addAll(astOdeDeclaration.getODEs()); equations.addAll(astOdeDeclaration.getOdeFunctions()); @@ -236,11 +237,10 @@ private void markConductanceBasedBuffers(final ASTOdeDeclaration astOdeDeclarati .flatMap(astEquation -> getCondSumFunctionCall(astEquation).stream()) // that there is one parameter which is the simple name is granted by cocos .map(astFunctionCall -> astFunctionCall.getArgs().get(1).getVariable().get()) - .filter(variable -> variable.getName().toString().equals(spikeBuffer.getName())) + .filter(variable -> variable.getName().equals(spikeBuffer.getName())) .findAny(); bufferInCondSumCall.ifPresent(o -> spikeBuffer.setConductanceBased(true)); - } } @@ -264,9 +264,7 @@ private void markConductanceBasedBuffers(final ASTOdeDeclaration astOdeDeclarati public void visit(final ASTInputLine inputLineAst) { checkState(this.currentScope().isPresent()); checkState(currentTypeSymbol.isPresent()); - final TypeSymbol bufferType = PredefinedTypes.getBufferType(); - final VariableSymbol var = new VariableSymbol(inputLineAst.getName()); var.setType(bufferType); @@ -339,7 +337,7 @@ public void endVisit(final ASTFunction funcAst) { removeCurrentScope(); } - public void visit(final ASTDynamics dynamicsAst) { + public void visit(final ASTUpdateBlock dynamicsAst) { checkState(this.currentScope().isPresent()); checkState(currentTypeSymbol.isPresent(), "This statement is defined in a nestml type."); @@ -353,17 +351,17 @@ public void visit(final ASTDynamics dynamicsAst) { } @Override - public void endVisit(final ASTDynamics de) { + public void endVisit(final ASTUpdateBlock astUpdateBlock) { removeCurrentScope(); } @Override - public void visit(final ASTVar_Block astVarBlock) { + public void visit(final ASTBlockWithVariables astVarBlock) { varBlock = of(astVarBlock); } @Override - public void endVisit(final ASTVar_Block astVarBlock) { + public void endVisit(final ASTBlockWithVariables astVarBlock) { varBlock = empty(); } diff --git a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java index 583192af4..c937eced4 100644 --- a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java +++ b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java @@ -238,7 +238,7 @@ public String printComment(final String prefix) { final StringBuffer output = new StringBuffer(); if(getAstNode().isPresent() && getAstNode().get() instanceof ASTDeclaration) { final ASTDeclaration astDeclaration = (ASTDeclaration) getAstNode().get(); - astDeclaration.getComments().forEach(comment -> output.append(prefix + " " + comment)); + astDeclaration.getDocStrings().forEach(comment -> output.append(prefix + " " + comment)); } return output.toString(); @@ -247,7 +247,7 @@ public String printComment(final String prefix) { public Boolean hasComment() { if(getAstNode().isPresent() && getAstNode().get() instanceof ASTDeclaration) { final ASTDeclaration astDeclaration = (ASTDeclaration) getAstNode().get(); - return !astDeclaration.getComments().isEmpty(); + return !astDeclaration.getDocStrings().isEmpty(); } return false; diff --git a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java index bd2c89b85..38bc715a8 100644 --- a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java +++ b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java @@ -5,6 +5,11 @@ */ package org.nest.nestml.prettyprinter; +import de.monticore.ast.ASTNode; +import de.monticore.ast.Comment; +import de.monticore.prettyprint.CommentPrettyPrinter; +import de.monticore.prettyprint.IndentPrinter; +import de.monticore.types.prettyprint.TypesPrettyPrinterConcreteVisitor; import org.nest.nestml._ast.*; import org.nest.nestml._visitor.NESTMLInheritanceVisitor; import org.nest.utils.AstUtils; @@ -13,347 +18,260 @@ import java.util.List; import java.util.Optional; -import static org.nest.nestml.prettyprinter.SPLPrettyPrinterFactory.createDefaultPrettyPrinter; import static org.nest.nestml._symboltable.typechecking.TypeChecker.deserializeUnitIfNotPrimitive; import static org.nest.utils.AstUtils.printComments; /** - * Provides convenient functions to statically type interfaces astnodes resulting from the Body-grammar + * Provides convenient functions to statically type interfaces ast-nodes resulting from the Body-grammar * production. * - * @author (last commit) $Author$ - * @version $Revision$, $Date$ + * @author plotnikov */ -public class NESTMLPrettyPrinter extends PrettyPrinterBase implements NESTMLInheritanceVisitor { +public class NESTMLPrettyPrinter implements NESTMLInheritanceVisitor { + private static final String BLOCK_CLOSE = "end"; + private static final String BLOCK_OPEN = ":"; private final ExpressionsPrettyPrinter expressionsPrinter; + private final ASTNESTMLNode root; + private final IndentPrinter printer = new IndentPrinter(); - public static class Builder { - public static NESTMLPrettyPrinter build() { - return new NESTMLPrettyPrinter(new ExpressionsPrettyPrinter()); - } + private NESTMLPrettyPrinter(final ASTNESTMLNode root) { + this.expressionsPrinter = new ExpressionsPrettyPrinter(); + this.root = root; } - private NESTMLPrettyPrinter(final ExpressionsPrettyPrinter expressionsPrinter) { - this.expressionsPrinter = expressionsPrinter; + public static String print(final ASTNESTMLNode astNestmlNode) { + final NESTMLPrettyPrinter prettyPrinter = new NESTMLPrettyPrinter(astNestmlNode); + astNestmlNode.accept(prettyPrinter); + return prettyPrinter.printer.getContent(); } - public String print(final ASTNESTMLNode astNestmlNode) { - astNestmlNode.accept(this); - return this.result(); - } + //////////////////////////////////////////////////////////////////////////// + // NESTML PART + //////////////////////////////////////////////////////////////////////////// /** - * NESTMLCompilationUnit = "package" packageName:QualifiedName - * BLOCK_OPEN - * (Import | NEWLINE)* - * (Neuron | Component | SL_COMMENT | NEWLINE)* - * BLOCK_CLOSE (SL_COMMENT | NEWLINE)*; + * Neuron = "neuron" Name + BLOCK_OPEN + (NEWLINE | + BlockWithVariables | + UpdateBlock | + Equations | + Input | + Output | + Function)* + BLOCK_CLOSE; + * @param astNeuron */ @Override - public void visit(final ASTNESTMLCompilationUnit node) { - printCommentsIfPresent(node); + public void handle(final ASTNeuron astNeuron) { + CommentPrettyPrinter.printPreComments(astNeuron, printer); + + printer.println("neuron " + astNeuron.getName() + BLOCK_OPEN); + printer.indent(); + + printNodes(astNeuron.getBlockWithVariabless()); + printNodes(astNeuron.getUpdateBlocks()); + printNodes(astNeuron.getEquationss()); + printNodes(astNeuron.getInputs()); + printNodes(astNeuron.getOutputs()); + printNodes(astNeuron.getFunctions()); + + printer.unindent(); + printer.println(BLOCK_CLOSE); + CommentPrettyPrinter.printPostComments(astNeuron, printer); } - - /** - * Grammar: - * Neuron = "neuron" Name Body; - */ @Override - public void visit(final ASTNeuron astNeuron) { - printCommentsIfPresent(astNeuron); + public void handle(final ASTBlockWithVariables astBlockWithVariables) { + CommentPrettyPrinter.printPreComments(astBlockWithVariables, printer); - print("neuron " + astNeuron.getName()); - } + printBlockKeyword(astBlockWithVariables); + printer.indent(); - /** - * Grammar: - * Body = BLOCK_OPEN ( SL_COMMENT | NEWLINE | BodyElement)* BLOCK_CLOSE; - */ - @Override - public void visit(final ASTBody astBody) { - printCommentsIfPresent(astBody); - println(BLOCK_OPEN); - indent(); - } + astBlockWithVariables.getDeclarations().forEach(node -> node.accept(this)); - /** - * Grammar: - * Body = BLOCK_OPEN ( SL_COMMENT | NEWLINE | BodyElement)* BLOCK_CLOSE; - */ - @Override - public void endVisit(final ASTBody astBody) { - unindent(); - println(BLOCK_CLOSE); - } - - @Override - public void visit(final ASTBodyElement astBodyElement) { - printCommentsIfPresent(astBodyElement); - } - /** - * Var_Block implements BodyElement = - * ([state:"state"]|[para:"parameter"]|[internal:"internal"]) - * BLOCK_OPEN - * (AliasDecl (";" AliasDecl)* (";")? - * | SL_COMMENT | NEWLINE)* - * BLOCK_CLOSE; - */ - @Override - public void visit(final ASTVar_Block astVarBlock) { - printBlockKeyword(astVarBlock); - indent(); - for (ASTDeclaration astDeclaration:astVarBlock.getDeclarations()) { - printDeclarationStatement(astDeclaration); - println(); - } + printer.unindent(); + printer.println(BLOCK_CLOSE); + CommentPrettyPrinter.printPostComments(astBlockWithVariables, printer); } - private void printBlockKeyword(final ASTVar_Block astVarBlock) { + private void printBlockKeyword(final ASTBlockWithVariables astVarBlock) { if (astVarBlock.isState()) { - println("state" + BLOCK_OPEN); + printer.println("state" + BLOCK_OPEN); } else if (astVarBlock.isInternals()) { - println("internals" + BLOCK_OPEN); + printer.println("internals" + BLOCK_OPEN); } else if (astVarBlock.isParameters ()) { - println("parameters" + BLOCK_OPEN); + printer.println("parameters" + BLOCK_OPEN); } } - private void printDeclarationStatement(final ASTDeclaration astDeclaration) { - final SPLPrettyPrinter splPrettyPrinter = createDefaultPrettyPrinter(getIndentionLevel()); - splPrettyPrinter.printDeclaration(astDeclaration); - print(splPrettyPrinter.result()); + public void handle(final ASTUpdateBlock astUpdateBlock) { + printer.println("update" + BLOCK_OPEN); + printer.indent(); + printNode(astUpdateBlock.getBlock()); + printer.unindent(); + printer.println(BLOCK_CLOSE); } - - @Override - public void endVisit(final ASTVar_Block astVarBlock) { - unindent(); - println(BLOCK_CLOSE); + private void printNodes(final List nodes) { + for (ASTNESTMLNode node:nodes) { + printNode(node); + } } - /** - * Grammar: - * Input implements BodyElement = "input" - * BLOCK_OPEN - * (InputLine | SL_COMMENT | NEWLINE)* - * BLOCK_CLOSE; - */ - @Override - public void visit(final ASTInput astInput) { - println("input" + BLOCK_OPEN); - indent(); + private void printNode(ASTNESTMLNode node) { + node.accept(this); } - /** - * Grammar: - * Input implements BodyElement = "input" - * BLOCK_OPEN - * (InputLine | SL_COMMENT | NEWLINE)* - * BLOCK_CLOSE; - */ - @Override - public void endVisit(final ASTInput astInput) { - unindent(); - println(BLOCK_CLOSE); + //////////////////////////////////////////////////////////////////////////// + // SPL PART + //////////////////////////////////////////////////////////////////////////// + public void handle(final ASTDeclaration astDeclaration) { + astDeclaration.getDocStrings().forEach(printer::println); + + printAliasPrefix(astDeclaration); + printDeclarationVariables(astDeclaration); + printDeclarationType(astDeclaration); + printOptionalInitializationExpression(astDeclaration); + printInvariants(astDeclaration); + CommentPrettyPrinter.printPostComments(astDeclaration, printer); + printer.println(); } - /** - * Equations implements BodyElement = - * "equations" - * BLOCK_OPEN - * OdeDeclaration - * BLOCK_CLOSE; - * - * OdeDeclaration = (Eq | Shape | ODEAlias | NEWLINE)+; - * Equation = lhs:Derivative "=" rhs:Expr (";")?; - * Derivative = name:QualifiedName (differentialOrder:"\'")*; - * ODEAlias = variableName:Name Datatype "=" Expr; - */ - @Override - public void visit(final ASTOdeDeclaration astOdeDeclaration) { - println("equations" + BLOCK_OPEN); - indent(); - - astOdeDeclaration.getShapes().stream().map(this::printShape).forEach(this::println); - astOdeDeclaration.getOdeFunctions().stream().map(this::printODEAlias).forEach(this::println); - astOdeDeclaration.getODEs().stream().map(this::printEquation).forEach(this::println); - - } - - /** - * This method is used in freemaker template. Therefore, it must remain public. - */ - public String printEquation(final ASTEquation astEquation) { - return astEquation.getLhs() + " = " + expressionsPrinter.print(astEquation.getRhs()); - } + private void printAliasPrefix(final ASTDeclaration astAliasDecl) { + if (astAliasDecl.isRecordable()) { + printer.print("recordable "); + } - /** - * This method is used in freemaker template. Therefore, it must remain public. - */ - public String printShape(final ASTShape astShape) { - return "shape " + astShape.getLhs() + " = " + expressionsPrinter.print(astShape.getRhs()); + if (astAliasDecl.isFunction()) { + printer.print("function "); + } } - /** - * This method is used in freemaker template. Therefore, remains public. - */ - public String printODEAlias(final ASTOdeFunction astOdeAlias) { - final String datatype = deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(astOdeAlias.getDatatype())); + private void printInvariants(final ASTDeclaration astAliasDecl) { + if (astAliasDecl.getInvariant().isPresent()) { + printer.print("[["); + final ASTExpr astInvariant = astAliasDecl.getInvariant().get(); + printer.print(expressionsPrinter.print(astInvariant)); + printer.print("]]"); - final String initExpression = expressionsPrinter.print(astOdeAlias.getExpr()); - final StringBuilder recordable = new StringBuilder(); - if (astOdeAlias.isRecordable()) { - recordable.append("recordable "); } - return recordable.toString() + "function " + astOdeAlias.getVariableName() + " " + datatype + " = " + initExpression; } - @Override - public void endVisit(final ASTEquations astEquations) { - unindent(); - println(BLOCK_CLOSE); - } - /** - * grammar - * InputLine = Name "<-" InputType* ([spike:"spike"]|[current:"current"]); - * InputType = (["inhibitory"]|["excitatory"]); - */ - @Override - public void visit(final ASTInputLine astInputLine) { - print(astInputLine.getName()); - printArrayParameter(astInputLine); - print(" <- "); - printInputTypes(astInputLine.getInputTypes()); - printOutputType(astInputLine); - println(); - } + private void printDeclarationVariables(final ASTDeclaration astDeclaration) { + final List variableNames = astDeclaration.getVars(); + for (int variableIndex = 0; variableIndex < variableNames.size(); ++ variableIndex) { + boolean isLastVariableInDeclaration = (variableIndex + 1) == variableNames.size(); - private void printInputTypes(final List inputTypes) { - for (final ASTInputType inputType:inputTypes) { - if (inputType.isInhibitory()) { - print("inhibitory "); - } - else { - print("excitatory "); + printer.print(variableNames.get(variableIndex).toString()); + if (!isLastVariableInDeclaration) { + printer.print(", "); } } + printer.print(" "); } - private void printArrayParameter(final ASTInputLine astInputLine) { - astInputLine.getSizeParameter().ifPresent(parameter -> print("[" + parameter + "]")); + private void printDeclarationType(final ASTDeclaration astDeclaration) { + printer.print(deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(astDeclaration.getDatatype()))); + if (astDeclaration.getSizeParameter().isPresent()) { + printer.print(" [" + astDeclaration.getSizeParameter().get() + "]"); + } + } - private void printOutputType(final ASTInputLine astInputLine) { - if (astInputLine.isSpike()) { - print("spike"); - } - else { - print("current"); + private void printOptionalInitializationExpression(final ASTDeclaration astDeclaration) { + if (astDeclaration.getExpr().isPresent()) { + printer.print(" = " + expressionsPrinter.print(astDeclaration.getExpr().get())); } } /** - * Output implements BodyElement = - * "output" BLOCK_OPEN ([spike:"spike"]|[current:"current"]) ; + * Small_Stmt = Assignment| FunctionCall | Declaration | ReturnStmt; */ @Override - public void visit(final ASTOutput astOutput) { - print("output: "); - if (astOutput.isSpike()) { - print("spike"); + public void handle(final ASTSmall_Stmt astSmallStmt ) { + CommentPrettyPrinter.printPreComments(astSmallStmt, printer); + + if (astSmallStmt.getAssignment().isPresent()) { + my_handle(astSmallStmt.getAssignment().get()); + } else if (astSmallStmt.getFunctionCall().isPresent()) { + my_handle(astSmallStmt.getFunctionCall().get()); + } else if (astSmallStmt.getDeclaration().isPresent()) { + // TODO: must be also a functions that is get called from the corresponding method + astSmallStmt.getDeclaration().get().accept(this); + } else if (astSmallStmt.getReturnStmt().isPresent()) { + my_handle(astSmallStmt.getReturnStmt().get()); } - else { - print("current"); - } - - println(); + printer.println(); + CommentPrettyPrinter.printPreComments(astSmallStmt, printer); } /** - * Function implements BodyElement = - "function" Name "(" Parameters? ")" (returnType:QualifiedName | PrimitiveType)? - BLOCK_OPEN - Block - BLOCK_CLOSE; + * Grammar: + * Assignment = variableName:QualifiedName "=" Expr; */ - @Override - public void visit(final ASTFunction astFunction) { - print("function " + astFunction.getName()); - printParameters(astFunction.getParameters()); - printOptionalReturnValue(astFunction); - println(BLOCK_OPEN); - indent(); - printSplBlock(astFunction.getBlock()); - unindent(); - println(BLOCK_CLOSE); - - } - - private void printParameters(final Optional functionParameters) { - print("("); - if (functionParameters.isPresent()) { - final List astParameters = functionParameters.get().getParameters(); - for (int curParameterIndex = 0; curParameterIndex < astParameters.size(); ++curParameterIndex) { - boolean isLastParameter = (curParameterIndex + 1) == astParameters.size(); - final ASTParameter curParameter = astParameters.get(curParameterIndex); - print(curParameter.getName() + " " + deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(curParameter.getDatatype()))); - if (!isLastParameter) { - print(", "); - } - - } - + public void my_handle(final ASTAssignment astAssignment) { + final String lhsVariableName = astAssignment.getLhsVarialbe().toString(); + final String rhsOfAssignment = expressionsPrinter.print(astAssignment.getExpr()); + if (astAssignment.isAssignment()) { + printer.print(lhsVariableName + " = " + rhsOfAssignment); } - print(")"); - } - - private void printOptionalReturnValue(final ASTFunction astFunction) { - if (astFunction.getReturnType().isPresent()) { - print(deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(astFunction.getReturnType().get()))); + if (astAssignment.isCompoundSum()) { + printer.print(lhsVariableName + " += " + rhsOfAssignment); + } + if (astAssignment.isCompoundMinus()) { + printer.print(lhsVariableName + " -= " + rhsOfAssignment); + } + if (astAssignment.isCompoundProduct()) { + printer.print(lhsVariableName + " *= " + rhsOfAssignment); + } + if (astAssignment.isCompoundQuotient()) { + printer.print(lhsVariableName + " /= " + rhsOfAssignment); } } + /** + * Grammar: + * FunctionCall = QualifiedName "(" ArgList ")"; + * ArgList = (args:Expr ("," args:Expr)*)?; + */ - private void printSplBlock(final ASTBlock astBlock) { - final SPLPrettyPrinter splPrinter = createDefaultPrettyPrinter(getIndentionLevel()); - splPrinter.print(astBlock); + public void my_handle(final ASTFunctionCall astFunctionCall) { + final String functionName = astFunctionCall.getCalleeName(); + printer.print(functionName + "("); + final List functionArguments = astFunctionCall.getArgs(); + for (int argumentIndex = 0; argumentIndex < functionArguments.size(); ++argumentIndex) { + boolean isLastFunctionArgument = (argumentIndex + 1) == functionArguments.size(); + final ASTExpr currentArgument = functionArguments.get(argumentIndex); + printer.print(expressionsPrinter.print(currentArgument)); + if (!isLastFunctionArgument) { + printer.print(", "); + } - print(splPrinter.result()); + } + printer.print(")"); } /** - * Dynamics implements BodyElement = - * "update:" - * BLOCK_OPEN - * Block - * BLOCK_CLOSE; + * ReturnStmt = "return" Expr?; */ - @Override - public void visit(final ASTDynamics astDynamics) { - print("update"); - println(BLOCK_OPEN); - indent(); - printSplBlock(astDynamics.getBlock()); - unindent(); - println(); - println(BLOCK_CLOSE); - } + public void my_handle(final ASTReturnStmt astReturnStmt) { - private void printCommentsIfPresent(final ASTNESTMLNode astNestmlNode) { - final String comment = printComments(astNestmlNode); - if (!comment.isEmpty()) { - println(comment); + if (astReturnStmt.getExpr().isPresent()) { + final String returnExpressionAsString = expressionsPrinter.print(astReturnStmt.getExpr().get()); + printer.print("return " + returnExpressionAsString); + } + else { + printer.print("return"); } } - } diff --git a/src/main/java/org/nest/nestml/prettyprinter/SPLPrettyPrinter.java b/src/main/java/org/nest/nestml/prettyprinter/SPLPrettyPrinter.java deleted file mode 100644 index 4a044286d..000000000 --- a/src/main/java/org/nest/nestml/prettyprinter/SPLPrettyPrinter.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * SPLPrettyPrinter.java - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * NEST 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with NEST. If not, see . - */ -package org.nest.nestml.prettyprinter; - -import de.monticore.ast.ASTNode; -import de.monticore.prettyprint.IndentPrinter; -import de.monticore.types.prettyprint.TypesPrettyPrinterConcreteVisitor; -import org.nest.nestml._ast.ASTBLOCK_CLOSE; -import org.nest.nestml._ast.ASTBLOCK_OPEN; -import org.nest.nestml._ast.ASTExpr; -import org.nest.nestml._ast.ASTFunctionCall; -import org.nest.nestml._ast.*; -import org.nest.nestml._visitor.NESTMLVisitor; -import org.nest.utils.AstUtils; -import org.nest.utils.PrettyPrinterBase; - -import java.util.List; -import java.util.Optional; - -import static org.nest.nestml._symboltable.typechecking.TypeChecker.deserializeUnitIfNotPrimitive; - -/** - * Produces the concrete textual representation from the AST. - * - * @author plotnikov - */ -public class SPLPrettyPrinter extends PrettyPrinterBase implements NESTMLVisitor { - private final ExpressionsPrettyPrinter expressionsPrinter; - private ASTNESTMLNode root; - - public SPLPrettyPrinter(final ExpressionsPrettyPrinter expressionsPrettyPrinter) { - this.expressionsPrinter = expressionsPrettyPrinter; - } - - public void print(final ASTNESTMLNode node) { - root = node; - node.accept(this); - } - - /** - * Grammar: - * IF_Clause = "if" Expr BLOCK_OPEN Block; - */ - @Override - public void visit(final ASTIF_Clause astIfClause) { - print("if" + " "); - final String conditionExpression = expressionsPrinter.print(astIfClause.getExpr()); - print(conditionExpression); - } - - /** - * This method unidents the output. - */ - @Override - public void endVisit(final ASTIF_Clause astIfClause) { - Optional parent = AstUtils.getParent(astIfClause, root); - if (parent.isPresent() && parent.get() instanceof ASTIF_Stmt) { - final ASTIF_Stmt astIfStmt = (ASTIF_Stmt) parent.get(); - final boolean isSingleIfClause = !astIfStmt.getELSE_Clause().isPresent() && astIfStmt.getELIF_Clauses().isEmpty(); - // any other form of if clause ends with an 'end' keyword and is handled in the corresponding visit method. - if (!isSingleIfClause) { - unindent(); - } - - } - - } - - /** - * ELIF_Clause = "elif" Expr BLOCK_OPEN Block; - */ - @Override - public void visit(final ASTELIF_Clause astElifNode) { - print("elif" + " "); - final String conditionExpression = expressionsPrinter.print(astElifNode.getExpr()); - print(conditionExpression); - } - - /** - * Doesn't terminate with 'end' and must be unindented manually - */ - @Override - public void endVisit(final ASTELIF_Clause astElifNode) { - unindent(); - } - - /** - * Grammar: - * ELSE_Clause = "else" BLOCK_OPEN Block; - */ - @Override - public void visit(final ASTELSE_Clause astElseClause) { - print("else"); - } - - @Override - public void visit(final ASTStmt astStmt) { - final String comment = AstUtils.printComments(astStmt); - if (!comment.isEmpty()) { - println(comment); - } - - } - - /** - * Small_Stmt = Assignment| FunctionCall | Declaration | ReturnStmt; - */ - @Override - public void visit(final ASTSmall_Stmt astSmallStmt ) { - print(AstUtils.printComments(astSmallStmt)); - - if (astSmallStmt.getAssignment().isPresent()) { - printAssignment(astSmallStmt.getAssignment().get()); - } else if (astSmallStmt.getFunctionCall().isPresent()) { - printFunctionCall(astSmallStmt.getFunctionCall().get()); - } else if (astSmallStmt.getDeclaration().isPresent()) { - printDeclaration(astSmallStmt.getDeclaration().get()); - } else if (astSmallStmt.getReturnStmt().isPresent()) { - printReturnStatement(astSmallStmt.getReturnStmt().get()); - } - println(); - } - - /** - * Grammar: - * Assignment = variableName:QualifiedName "=" Expr; - */ - private void printAssignment(final ASTAssignment astAssignment) { - final String lhsVariableName = astAssignment.getLhsVarialbe().toString(); - final String rhsOfAssignment = expressionsPrinter.print(astAssignment.getExpr()); - if (astAssignment.isAssignment()) { - print(lhsVariableName + " = " + rhsOfAssignment); - } - if (astAssignment.isCompoundSum()) { - print(lhsVariableName + " += " + rhsOfAssignment); - } - if (astAssignment.isCompoundMinus()) { - print(lhsVariableName + " -= " + rhsOfAssignment); - } - if (astAssignment.isCompoundProduct()) { - print(lhsVariableName + " *= " + rhsOfAssignment); - } - if (astAssignment.isCompoundQuotient()) { - print(lhsVariableName + " /= " + rhsOfAssignment); - } - - } - - /** - * Grammar: - * FunctionCall = QualifiedName "(" ArgList ")"; - * ArgList = (args:Expr ("," args:Expr)*)?; - */ - private void printFunctionCall(final ASTFunctionCall astFunctionCall) { - final String functionName = astFunctionCall.getCalleeName(); - print(functionName + "("); - final List functionArguments = astFunctionCall.getArgs(); - for (int argumentIndex = 0; argumentIndex < functionArguments.size(); ++argumentIndex) { - boolean isLastFunctionArgument = (argumentIndex + 1) == functionArguments.size(); - final ASTExpr currentArgument = functionArguments.get(argumentIndex); - print(expressionsPrinter.print(currentArgument)); - if (!isLastFunctionArgument) { - print(", "); - } - - } - print(")"); - } - - /** - * ReturnStmt = "return" Expr?; - */ - private void printReturnStatement(final ASTReturnStmt astReturnStmt) { - - if (astReturnStmt.getExpr().isPresent()) { - final String returnExpressionAsString = expressionsPrinter.print(astReturnStmt.getExpr().get()); - print("return " + returnExpressionAsString); - } - else { - print("return"); - } - - } - - /** - * Grammar - * Declaration = vars:Name ("," vars:Name)* (type:QualifiedName | primitiveType:PrimitiveType) ( "=" Expr )? ; - */ - public void printDeclaration(final ASTDeclaration astDeclaration) { - printDeclarationComments(astDeclaration); - printAliasPrefix(astDeclaration); - printDeclarationVariables(astDeclaration); - printDeclarationType(astDeclaration); - printOptionalInitializationExpression(astDeclaration); - printInvariants(astDeclaration); - } - - private void printAliasPrefix(final ASTDeclaration astAliasDecl) { - if (astAliasDecl.isRecordable()) { - print("recordable "); - } - - if (astAliasDecl.isFunction()) { - print("function "); - } - } - - private void printInvariants(final ASTDeclaration astAliasDecl) { - if (astAliasDecl.getInvariant().isPresent()) { - print("[["); - final ASTExpr astInvariant = astAliasDecl.getInvariant().get(); - print(expressionsPrinter.print(astInvariant)); - print("]]"); - - } - } - - private void printDeclarationComments(final ASTDeclaration astDeclaration) { - astDeclaration.getComments().forEach(c -> println("# " + c)); - } - - private void printDeclarationVariables(final ASTDeclaration astDeclaration) { - final List variableNames = astDeclaration.getVars(); - for (int variableIndex = 0; variableIndex < variableNames.size(); ++ variableIndex) { - boolean isLastVariableInDeclaration = (variableIndex + 1) == variableNames.size(); - - print(variableNames.get(variableIndex).toString()); - if (!isLastVariableInDeclaration) { - print(", "); - } - - } - - print(" "); - } - - private void printDeclarationType(final ASTDeclaration astDeclaration) { - print(deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(astDeclaration.getDatatype()))); - if (astDeclaration.getSizeParameter().isPresent()) { - print(" [" + astDeclaration.getSizeParameter().get() + "]"); - } - - } - - private void printOptionalInitializationExpression(final ASTDeclaration astDeclaration) { - if (astDeclaration.getExpr().isPresent()) { - print(" = " + expressionsPrinter.print(astDeclaration.getExpr().get())); - } - - } - - /** - * Grammar: - * FOR_Stmt = "for" var:Name "in" from:Expr "..." to:Expr ("step" step:SignedNumericLiteral)? - * BLOCK_OPEN Block BLOCK_CLOSE; - */ - @Override public void visit(final ASTFOR_Stmt astForStmt) { - print("for "); - print(astForStmt.getVar()); - print(" in "); - print(expressionsPrinter.print(astForStmt.getFrom())); - print(" ... "); - print(expressionsPrinter.print(astForStmt.getTo())); - print(" step "); - print(typesPrinter().prettyprint(astForStmt.getStep())); - } - - /** - * Grammar: - * WHILE_Stmt = "while" Expr BLOCK_OPEN Block BLOCK_CLOSE; - */ - @Override - public void visit(final ASTWHILE_Stmt astWhileStmt) { - print("while "); - print(expressionsPrinter.print(astWhileStmt.getExpr())); - } - - @Override - public void visit(final ASTBlock astBlock ) { - final String comment = AstUtils.printComments(astBlock); - if (!comment.isEmpty()) { - println(comment); - } - } - - @Override - public void visit(final ASTBLOCK_OPEN astBlockOpen) { - final String comment = AstUtils.printComments(astBlockOpen); - if (comment.isEmpty()) { - println(BLOCK_OPEN); - } - else { - println(BLOCK_OPEN + " " + comment); - } - indent(); - - } - - @Override - public void endVisit(final ASTBLOCK_CLOSE astBlockClose) { - unindent(); - final String comment = AstUtils.printComments(astBlockClose); - if (comment.isEmpty()) { - println(BLOCK_CLOSE); - } - else { - println(BLOCK_CLOSE + " " + comment); - } - - } - - private TypesPrettyPrinterConcreteVisitor typesPrinter() { - final IndentPrinter printer = new IndentPrinter(); - return new TypesPrettyPrinterConcreteVisitor(printer); - } - -} diff --git a/src/main/java/org/nest/nestml/prettyprinter/SPLPrettyPrinterFactory.java b/src/main/java/org/nest/nestml/prettyprinter/SPLPrettyPrinterFactory.java deleted file mode 100644 index 9018086bb..000000000 --- a/src/main/java/org/nest/nestml/prettyprinter/SPLPrettyPrinterFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SPLPrettyPrinterFactory.java - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * NEST 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with NEST. If not, see . - */ - -package org.nest.nestml.prettyprinter; - -/** - * Instantiates SPL printers. Optionally, set the indentation level which is useful for the - * composition of printers. - * - * @author plotnikov - */ -public class SPLPrettyPrinterFactory { - - public static SPLPrettyPrinter createDefaultPrettyPrinter() { - return new SPLPrettyPrinter(new ExpressionsPrettyPrinter()); - } - - public static SPLPrettyPrinter createDefaultPrettyPrinter(int indentionLevel) { - final SPLPrettyPrinter splPrettyPrinter = new SPLPrettyPrinter(new ExpressionsPrettyPrinter()); - splPrettyPrinter.setIndentionLevel(indentionLevel); - return splPrettyPrinter; - - } - -} diff --git a/src/main/java/org/nest/utils/AstUtils.java b/src/main/java/org/nest/utils/AstUtils.java index 1e9fdc0c6..d0f8476e6 100644 --- a/src/main/java/org/nest/utils/AstUtils.java +++ b/src/main/java/org/nest/utils/AstUtils.java @@ -382,12 +382,10 @@ public static boolean isInhExc(final ASTInputLine astInputLine ) { private static void printModelToFile( final ASTNeuron astNeuron, final Path outputFile) { - final NESTMLPrettyPrinter prettyPrinter = NESTMLPrettyPrinter.Builder.build(); - astNeuron.accept(prettyPrinter); final File prettyPrintedModelFile = outputFile.toFile(); try { - FileUtils.write(prettyPrintedModelFile, prettyPrinter.result()); + FileUtils.write(prettyPrintedModelFile, NESTMLPrettyPrinter.print(astNeuron)); } catch (IOException e) { final String msg = "Cannot write the prettyprinted model to the file: " + outputFile; diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl index 560f1fce4..903ce09ae 100644 --- a/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl +++ b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl @@ -278,7 +278,7 @@ ${neuronName}::update( - <#assign dynamics = body.getDynamicsBlock().get()> + <#assign dynamics = body.getUpdateBlock().get()> ${tc.include("org.nest.spl.Block", dynamics.getBlock())} // voltage logging diff --git a/src/test/java/org/nest/base/ModelbasedTest.java b/src/test/java/org/nest/base/ModelbasedTest.java index 699e4ae8c..a01eda0ed 100644 --- a/src/test/java/org/nest/base/ModelbasedTest.java +++ b/src/test/java/org/nest/base/ModelbasedTest.java @@ -66,12 +66,10 @@ protected ASTNESTMLCompilationUnit parseAndBuildSymboltable(final String pathToM protected void printModelToFile( final ASTNESTMLCompilationUnit root, final String outputModelFile) { - final NESTMLPrettyPrinter prettyPrinter = NESTMLPrettyPrinter.Builder.build(); - root.accept(prettyPrinter); final File prettyPrintedModelFile = new File(outputModelFile); try { - FileUtils.write(prettyPrintedModelFile, prettyPrinter.result()); + FileUtils.write(prettyPrintedModelFile, NESTMLPrettyPrinter.print(root)); } catch (IOException e) { throw new RuntimeException("Cannot write the prettyprinted model to the file: " + outputModelFile, e); diff --git a/src/test/java/org/nest/codegeneration/sympy/EquationsBlockProcessorTest.java b/src/test/java/org/nest/codegeneration/sympy/EquationsBlockProcessorTest.java index 382cb4820..9a0606218 100644 --- a/src/test/java/org/nest/codegeneration/sympy/EquationsBlockProcessorTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/EquationsBlockProcessorTest.java @@ -98,7 +98,7 @@ private Scope solveOdesAndShapes(final String pathToModel) { FilesHelper.deleteFilesInFolder(outputBase); testant.solveOdeWithShapes(modelRoot.getNeurons().get(0), outputBase); - System.out.println(NESTMLPrettyPrinter.Builder.build().print(modelRoot.getNeurons().get(0))); + System.out.println(NESTMLPrettyPrinter.print(modelRoot.getNeurons().get(0))); return scopeCreator.runSymbolTableCreator(modelRoot); } diff --git a/src/test/java/org/nest/codegeneration/sympy/ExpressionFolderTest.java b/src/test/java/org/nest/codegeneration/sympy/ExpressionFolderTest.java index 40509fe9b..9d3f67e91 100644 --- a/src/test/java/org/nest/codegeneration/sympy/ExpressionFolderTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/ExpressionFolderTest.java @@ -69,7 +69,7 @@ public void testFoldingPipeline() throws IOException { final SolverOutput solverOutput = SolverOutput.fromJSON(SolverJsonData.IAF_PSC_ALPHA); final List stateVariableNames = newArrayList(); - stateVariableNames.addAll(neuron.getBody().getStateSymbols() + stateVariableNames.addAll(neuron.getStateSymbols() .stream() .map(VariableSymbol::getName) .collect(toList())); diff --git a/src/test/java/org/nest/codegeneration/sympy/SolverInputTest.java b/src/test/java/org/nest/codegeneration/sympy/SolverInputTest.java index 0e7eaa9ef..f6aa50415 100644 --- a/src/test/java/org/nest/codegeneration/sympy/SolverInputTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/SolverInputTest.java @@ -41,7 +41,7 @@ public class SolverInputTest extends ModelbasedTest { public void test_cond_model() { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(COND_MODEL_FILE_PATH); - final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getBody().getOdeBlock().get(); + final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getOdeBlock().get(); SolverInput solverInput = new SolverInput(odeBlock); String result = solverInput.toJSON(); System.out.println(result); @@ -53,7 +53,7 @@ public void test_cond_model() { public void test_psc_model() { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(PSC_MODEL_FILE_PATH); - final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getBody().getOdeBlock().get(); + final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getOdeBlock().get(); SolverInput solverInput = new SolverInput(odeBlock); String result = solverInput.toJSON(); System.out.println(result); @@ -65,7 +65,7 @@ public void test_psc_model() { public void test_shapes_only() { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(PSC_MODEL_FILE_PATH); - final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getBody().getOdeBlock().get(); + final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getOdeBlock().get(); SolverInput solverInput = new SolverInput(odeBlock.getShapes()); String result = solverInput.toJSON(); System.out.println(result); @@ -77,7 +77,7 @@ public void test_shapes_only() { public void test_delta_shape() { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(DELTA_MODEL_FILE_PATH); - final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getBody().getOdeBlock().get(); + final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getOdeBlock().get(); SolverInput solverInput = new SolverInput(odeBlock); String result = solverInput.toJSON(); System.out.println(result); diff --git a/src/test/java/org/nest/codegeneration/sympy/SymPySolverTest.java b/src/test/java/org/nest/codegeneration/sympy/SymPySolverTest.java index 022fbe837..817e55d08 100644 --- a/src/test/java/org/nest/codegeneration/sympy/SymPySolverTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/SymPySolverTest.java @@ -86,7 +86,7 @@ private SolverOutput executeSolver(final String pathToModel) throws IOException FilesHelper.deleteFilesInFolder(SYMPY_OUTPUT); final SymPySolver symPySolver = new SymPySolver(); - final ASTOdeDeclaration astOdeDeclaration = root.get().getNeurons().get(0).getBody().getOdeBlock().get(); + final ASTOdeDeclaration astOdeDeclaration = root.get().getNeurons().get(0).getOdeBlock().get(); return symPySolver.solveOdeWithShapes(astOdeDeclaration, SYMPY_OUTPUT); } diff --git a/src/test/java/org/nest/nestml/_ast/ASTBodyTest.java b/src/test/java/org/nest/nestml/_ast/ASTNeuronTest.java similarity index 73% rename from src/test/java/org/nest/nestml/_ast/ASTBodyTest.java rename to src/test/java/org/nest/nestml/_ast/ASTNeuronTest.java index 4f40ecaed..19d4f7dc5 100644 --- a/src/test/java/org/nest/nestml/_ast/ASTBodyTest.java +++ b/src/test/java/org/nest/nestml/_ast/ASTNeuronTest.java @@ -18,14 +18,14 @@ * * @author plotnikov */ -public class ASTBodyTest extends ModelbasedTest { +public class ASTNeuronTest extends ModelbasedTest { private static final String PSC_MODEL_THREE_BUFFERS = "src/test/resources/codegeneration/iaf_psc_alpha_three_buffers.nestml"; @Test public void getSameTypeBuffer() throws Exception { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(PSC_MODEL_THREE_BUFFERS); - final ASTBody astBody = root.getNeurons().get(0).getBody(); - final List buffers = astBody.getMultipleReceptors(); + final ASTNeuron astNeuron = root.getNeurons().get(0); + final List buffers = astNeuron.getMultipleReceptors(); assertEquals(3, buffers.size()); } @@ -33,8 +33,8 @@ public void getSameTypeBuffer() throws Exception { @Test public void getCurrentBuffer() { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(PSC_MODEL_THREE_BUFFERS); - final ASTBody astBody = root.getNeurons().get(0).getBody(); - final List buffers = astBody.getCurrentBuffers(); + final ASTNeuron astNeuron = root.getNeurons().get(0); + final List buffers = astNeuron.getCurrentBuffers(); assertEquals(1, buffers.size()); } diff --git a/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java b/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java index ecfd3661e..3eb3f87ba 100644 --- a/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java +++ b/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java @@ -751,8 +751,6 @@ private void checkModelAndAssertWithErrors( final Optional ast = getAstRoot(pathToModel.toString()); assertTrue(ast.isPresent()); scopeCreator.runSymbolTableCreator(ast.get()); - NESTMLPrettyPrinter p = NESTMLPrettyPrinter.Builder.build(); - ast.get().accept(p); nestmlCoCoChecker.checkAll(ast.get()); diff --git a/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java b/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java index f606813ae..328add652 100644 --- a/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java +++ b/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java @@ -68,8 +68,8 @@ public void testCommentsExtraction() throws IOException { assertTrue(ast.isPresent()); final List declarations = AstUtils.getAll(ast.get(), ASTDeclaration.class); for (final ASTDeclaration declaration:declarations) { - assertEquals(3, declaration.getComments().size()); - declaration.getComments().forEach(System.out::println); + assertEquals(3, declaration.getDocStrings().size()); + declaration.getDocStrings().forEach(System.out::println); } } diff --git a/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java b/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java index c53841f0d..d3a42e945 100644 --- a/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java +++ b/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java @@ -10,10 +10,10 @@ import de.monticore.symboltable.ScopeSpanningSymbol; import org.junit.Test; import org.nest.base.ModelbasedTest; -import org.nest.nestml._ast.ASTBody; -import org.nest.nestml._ast.ASTBodyElement; +import org.nest.nestml._ast.ASTBlockWithVariables; import org.nest.nestml._ast.ASTFunction; import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._ast.ASTNeuron; import org.nest.nestml._symboltable.predefined.PredefinedFunctions; import org.nest.nestml._symboltable.predefined.PredefinedTypes; import org.nest.nestml._symboltable.symbols.MethodSymbol; @@ -89,9 +89,9 @@ public void testResolvingFromSeparateBlocks() throws IOException { scopeCreator.runSymbolTableCreator(root); - final ASTBody astBodyDecorator = (root.getNeurons().get(0).getBody()); + final ASTNeuron astNeuronDecorator = (root.getNeurons().get(0)); - final Optional neuronState = astBodyDecorator.getStateBlock(); + final Optional neuronState = astNeuronDecorator.getStateBlock(); assertTrue(neuronState.isPresent()); // retrieve state block @@ -100,13 +100,13 @@ public void testResolvingFromSeparateBlocks() throws IOException { assertTrue(y0Symbol.isPresent()); // retrieve parameter block - final Scope parameterScope = astBodyDecorator.getParameterBlock().get().getEnclosingScope().get(); + final Scope parameterScope = astNeuronDecorator.getParameterBlock().get().getEnclosingScope().get(); assertSame(stateScope, parameterScope); assertTrue(parameterScope.resolve("y0", VariableSymbol.KIND).isPresent()); assertTrue(parameterScope.resolve("C_m", VariableSymbol.KIND).isPresent()); // retrieve dynamics block - final Scope dynamicsScope = astBodyDecorator.getDynamics().get(0).getBlock().getEnclosingScope().get(); + final Scope dynamicsScope = astNeuronDecorator.getUpdateBlocks().get(0).getBlock().getEnclosingScope().get(); final Optional newVarInMethodSymbol = dynamicsScope.resolve("newVarInMethod", VariableSymbol.KIND); @@ -123,9 +123,9 @@ public void testShadowingOfVariablesInMethods() throws IOException { scopeCreator.runSymbolTableCreator(root); - final ASTBody astBodyDecorator = (root.getNeurons().get(0).getBody()); + final ASTNeuron astNeuronDecorator = (root.getNeurons().get(0)); - final Optional neuronState = astBodyDecorator.getStateBlock(); + final Optional neuronState = astNeuronDecorator.getStateBlock(); assertTrue(neuronState.isPresent()); final Optional testVarFromParameter = neuronState.get().getEnclosingScope().get().resolve("scopeTestVar", @@ -136,7 +136,7 @@ public void testShadowingOfVariablesInMethods() throws IOException { assertTrue(testVarFromParameter.get().getType().equals(PredefinedTypes.getStringType())); // check the symbol in function block - final Optional scopeTestingFunction = astBodyDecorator + final Optional scopeTestingFunction = astNeuronDecorator .getFunctions() .stream() .filter(astFunction -> astFunction.getName().equals("scopeTestingFunction")) @@ -222,9 +222,9 @@ public void testResolvingOfPredefinedFunctions() throws IOException { scopeCreator.runSymbolTableCreator(root); - final ASTBody astBodyDecorator = (root.getNeurons().get(0).getBody()); + final ASTNeuron astNeuronDecorator = (root.getNeurons().get(0)); - final Optional neuronState = astBodyDecorator.getStateBlock(); + final Optional neuronState = astNeuronDecorator.getStateBlock(); assertTrue(neuronState.isPresent()); // retrieve state block @@ -264,7 +264,7 @@ public void testRecognitionOfConductanceBasedBuffers() { assertEquals(1, root.getNeurons().size()); scopeCreator.runSymbolTableCreator(root); - final List spikeBuffers = root.getNeurons().get(0).getBody().getSpikeBuffers(); + final List spikeBuffers = root.getNeurons().get(0).getSpikeBuffers(); assertTrue(spikeBuffers.size() == 1); assertTrue(spikeBuffers.get(0).isConductanceBased()); } diff --git a/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java b/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java index 69b2153c0..cf3cbf955 100644 --- a/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java +++ b/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java @@ -7,7 +7,6 @@ import org.nest.nestml._ast.ASTBlock; import org.nest.nestml._ast.ASTNESTMLCompilationUnit; import org.nest.nestml._parser.NESTMLParser; -import org.nest.utils.AstUtils; import org.nest.utils.FilesHelper; import java.io.IOException; @@ -28,12 +27,8 @@ */ public class NESTMLPrettyPrinterTest extends ModelbasedTest { private final NESTMLParser nestmlParser = new NESTMLParser(); - @BeforeClass - public static void disableFailQuick() { - Log.enableFailQuick(false); - } - private Optional parseStringAsSPLFile(final String fileAsString) throws IOException { + private Optional parseString(final String fileAsString) throws IOException { return nestmlParser.parse(new StringReader(fileAsString)); } @@ -78,31 +73,28 @@ private void parseAllNESTMLModelsFromFolder(final String folderPath) throws IOEx private void parseAndCheckNestmlModel(String pathToModel) throws IOException { System.out.println("Handles the model: " + pathToModel); - final NESTMLPrettyPrinter splPrettyPrinter = NESTMLPrettyPrinter.Builder.build(); - final Optional splModelRoot = nestmlParser.parse(pathToModel); - assertTrue("Cannot parse the model: " + pathToModel, splModelRoot.isPresent()); + final Optional modelRoot = nestmlParser.parse(pathToModel); + assertTrue("Cannot parse the model: " + pathToModel, modelRoot.isPresent()); - splModelRoot.get().accept(splPrettyPrinter); - - final Optional prettyPrintedRoot = parseStringAsSPLFile(splPrettyPrinter.result()); + System.out.printf(NESTMLPrettyPrinter.print(modelRoot.get())); + final Optional prettyPrintedRoot = parseString(NESTMLPrettyPrinter.print(modelRoot.get())); assertTrue(prettyPrintedRoot.isPresent()); } @Test public void testPrintingComment() throws IOException { - final ExpressionsPrettyPrinter prettyPrinter = new ExpressionsPrettyPrinter(); - final SPLPrettyPrinter splPrettyPrinter = new SPLPrettyPrinter(prettyPrinter); final ASTNESTMLCompilationUnit root = parseNestmlModel("src/test/resources/org/nest/nestml/parsing/comment.nestml"); - final Optional astBlock = AstUtils.getAny(root, ASTBlock.class); - assertTrue(astBlock.isPresent()); - splPrettyPrinter.print(astBlock.get()); - final String printedModel = splPrettyPrinter.result(); + + final String printedModel = NESTMLPrettyPrinter.print(root.getNeurons().get(0).getFunctions().get(0).getBlock()); + + System.out.println("!!!"); System.out.println(printedModel); + System.out.println("!!!"); - Optional prettyPrintedRoot = nestmlParser.parseBlock(new StringReader(splPrettyPrinter.result())); + Optional prettyPrintedRoot = nestmlParser.parseBlock(new StringReader(printedModel)); assertTrue(prettyPrintedRoot.isPresent()); IntStream.range(1, 11).forEach( diff --git a/src/test/java/org/nest/utils/AstUtilsTest.java b/src/test/java/org/nest/utils/AstUtilsTest.java index 8601e48c8..fecfbe591 100644 --- a/src/test/java/org/nest/utils/AstUtilsTest.java +++ b/src/test/java/org/nest/utils/AstUtilsTest.java @@ -23,9 +23,9 @@ public class AstUtilsTest extends ModelbasedTest { @Test public void testComputationAliases() { final ASTNESTMLCompilationUnit astCompilationUnit = parseAndBuildSymboltable(PSC_MODEL_WITH_ODE); - Assert.assertTrue(astCompilationUnit.getNeurons().get(0).getBody().getOdeBlock().isPresent()); + Assert.assertTrue(astCompilationUnit.getNeurons().get(0).getOdeBlock().isPresent()); - final List aliasesIn = AstUtils.getAliasSymbols(astCompilationUnit.getNeurons().get(0).getBody().getOdeBlock().get()); + final List aliasesIn = AstUtils.getAliasSymbols(astCompilationUnit.getNeurons().get(0).getOdeBlock().get()); final Optional testant = aliasesIn.stream().filter(alias -> alias.getName().equals("I_syn_ampa")).findAny(); Assert.assertTrue(testant.isPresent()); } diff --git a/src/test/resources/org/nest/nestml/parsing/comment.nestml b/src/test/resources/org/nest/nestml/parsing/comment.nestml index d5128b590..cca6acc43 100644 --- a/src/test/resources/org/nest/nestml/parsing/comment.nestml +++ b/src/test/resources/org/nest/nestml/parsing/comment.nestml @@ -5,14 +5,18 @@ neuron Dummy: # Comment 3 if 3 > 4: # Comment 4 + aa integer elif 5>6: # Comment 5 + bb integer else: # Comment 6 + cc integer end # Comment 7 if true: # Comment 8 + dd integer end # Comment 9 # Comment 10 From 6dba957ea87f19550e4584ffd805442346ca23f1 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Fri, 8 Sep 2017 14:45:09 +0200 Subject: [PATCH 02/17] Cleanup the grammar. Improve naming. --- src/main/grammars/org/nest/NESTML.mc4 | 17 +- .../codegeneration/NestCodeGenerator.java | 10 +- .../codegeneration/helpers/ASTOutputs.java | 8 +- .../sympy/DeltaSolutionTransformer.java | 2 +- .../sympy/EquationsBlockProcessor.java | 12 +- .../sympy/ExactSolutionTransformer.java | 2 +- .../sympy/ShapesToOdesTransformer.java | 11 +- .../codegeneration/sympy/SolverInput.java | 6 +- .../codegeneration/sympy/SymPySolver.java | 4 +- .../codegeneration/sympy/TransformerBase.java | 4 +- ...eclaration.java => ASTEquationsBlock.java} | 16 +- .../java/org/nest/nestml/_ast/ASTNeuron.java | 33 +- .../_cocos/NeuronWithMultipleOrNoInput.java | 2 +- .../_cocos/NeuronWithMultipleOrNoOutput.java | 4 +- .../nestml/_cocos/SumHasCorrectParameter.java | 8 +- .../nestml/_cocos/UsageOfAmbiguousName.java | 4 +- .../NESTMLSymbolTableCreator.java | 16 +- .../_symboltable/NestmlCoCosManager.java | 2 +- .../_visitor/ODEPostProcessingVisitor.java | 4 +- .../prettyprinter/NESTMLPrettyPrinter.java | 335 ++++++++++++++++-- .../function/GSLDifferentiationFunction.ftl | 2 +- .../nest/spl/small_statement/FunctionCall.ftl | 2 +- .../codegeneration/sympy/SolverInputTest.java | 10 +- .../codegeneration/sympy/SymPySolverTest.java | 4 +- .../nest/nestml/_cocos/NestmlCoCosTest.java | 2 +- .../nest/nestml/_parser/ODEParsingTest.java | 14 +- .../NESTMLPrettyPrinterTest.java | 10 +- .../java/org/nest/utils/AstUtilsTest.java | 4 +- .../org/nest/nestml/parsing/comment.nestml | 9 +- 29 files changed, 414 insertions(+), 143 deletions(-) rename src/main/java/org/nest/nestml/_ast/{ASTOdeDeclaration.java => ASTEquationsBlock.java} (76%) diff --git a/src/main/grammars/org/nest/NESTML.mc4 b/src/main/grammars/org/nest/NESTML.mc4 index a3b6c3346..6ee220462 100644 --- a/src/main/grammars/org/nest/NESTML.mc4 +++ b/src/main/grammars/org/nest/NESTML.mc4 @@ -95,16 +95,9 @@ grammar NESTML extends org.nest.Literals { @attribute Neuron The neuron representation */ - /********************************************************************************************************************* * Equations-Language *********************************************************************************************************************/ - /** ASTOdeDeclaration. Represents a block of equations and differential equations. - - @attribute Equation List with equations, e.g. "I = exp(t)" od differential equations. - */ - OdeDeclaration = (Equation | Shape | OdeFunction | NEWLINE)+; - OdeFunction = ([recordable:"recordable"])? "function" variableName:Name Datatype "=" Expr (";")?; /** ASTeq Represents an equation, e.g. "I = exp(t)" or represents an differential equations, e.g. "V_m' = V_m+1". @@ -192,7 +185,7 @@ grammar NESTML extends org.nest.Literals { */ Neuron = "neuron" Name BLOCK_OPEN - (NEWLINE | BlockWithVariables | UpdateBlock | Equations | Input | Output | Function)* + (NEWLINE | BlockWithVariables | UpdateBlock | EquationsBlock | InputBlock | OutputBlock | Function)* BLOCK_CLOSE; /** ASTBlockWithVariables represent a block with variables, e.g.: @@ -232,10 +225,10 @@ grammar NESTML extends org.nest.Literals { end @attribute odeDeclaration Block with equations and differential equations. */ - Equations = + EquationsBlock = "equations" BLOCK_OPEN - OdeDeclaration + (Equation | Shape | OdeFunction | NEWLINE)+ BLOCK_CLOSE; /** ASTInput represents the input block: @@ -246,7 +239,7 @@ grammar NESTML extends org.nest.Literals { @attribute inputLine set of input lines. */ - Input = "input" + InputBlock = "input" BLOCK_OPEN (InputLine | NEWLINE)* BLOCK_CLOSE; @@ -276,7 +269,7 @@ grammar NESTML extends org.nest.Literals { @attribute spike true iff the neuron has a spike output. @attribute current true iff. the neuron is a current output. */ - Output = "output" BLOCK_OPEN (["spike"] | ["current"]) ; + OutputBlock = "output" BLOCK_OPEN (["spike"] | ["current"]) ; /** ASTFunction a function definition: function set_V_m(v mV): diff --git a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java index 1a173c6da..357e8fa8f 100644 --- a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java +++ b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java @@ -14,7 +14,7 @@ import org.nest.codegeneration.sympy.OdeTransformer; import org.nest.nestml._ast.ASTNeuron; import org.nest.nestml._ast.ASTNESTMLCompilationUnit; -import org.nest.nestml._ast.ASTOdeDeclaration; +import org.nest.nestml._ast.ASTEquationsBlock; import org.nest.nestml._symboltable.NESTMLLanguage; import org.nest.nestml._symboltable.NestmlSymbols; import org.nest.nestml.prettyprinter.ExpressionsPrettyPrinter; @@ -81,7 +81,7 @@ private ASTNeuron solveOdesAndShapes( final ASTNeuron astNeuron, final Path outputBase) { - final Optional odesBlock = astNeuron.getOdeBlock(); + final Optional odesBlock = astNeuron.findEquationsBlock(); if (odesBlock.isPresent()) { if (odesBlock.get().getShapes().size() == 0 && odesBlock.get().getODEs().size() > 1) { final String msg = String.format( @@ -248,9 +248,9 @@ private void setNeuronGenerationParameter( private void defineSolverType(final GlobalExtensionManagement glex, final ASTNeuron neuron) { glex.setGlobalValue("useGSL", false); - if (neuron.getOdeBlock().isPresent()) { - if (neuron.getOdeBlock().get().getShapes().size() == 0 || - neuron.getOdeBlock().get().getODEs().size() > 1) { + if (neuron.findEquationsBlock().isPresent()) { + if (neuron.findEquationsBlock().get().getShapes().size() == 0 || + neuron.findEquationsBlock().get().getODEs().size() > 1) { glex.setGlobalValue("names", new GslNames()); glex.setGlobalValue("useGSL", true); diff --git a/src/main/java/org/nest/codegeneration/helpers/ASTOutputs.java b/src/main/java/org/nest/codegeneration/helpers/ASTOutputs.java index 8b236d99e..2f0815c7f 100644 --- a/src/main/java/org/nest/codegeneration/helpers/ASTOutputs.java +++ b/src/main/java/org/nest/codegeneration/helpers/ASTOutputs.java @@ -7,7 +7,7 @@ import de.monticore.ast.ASTNode; import org.nest.nestml._ast.ASTNeuron; -import org.nest.nestml._ast.ASTOutput; +import org.nest.nestml._ast.ASTOutputBlock; import java.util.List; @@ -18,13 +18,13 @@ */ public class ASTOutputs { public static boolean isOutputEventPresent(final ASTNeuron astNeuron) { - return !astNeuron.getOutputs().isEmpty(); + return !astNeuron.getOutputBlocks().isEmpty(); } public static String printOutputEvent(final ASTNeuron astNeuron) { - final List neuronOutputs = astNeuron.getOutputs(); + final List neuronOutputs = astNeuron.getOutputBlocks(); if (!neuronOutputs.isEmpty()) { - ASTOutput output = neuronOutputs.get(0); + ASTOutputBlock output = neuronOutputs.get(0); if (output.isSpike()) { return "nest::SpikeEvent"; diff --git a/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java b/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java index 367858d20..ad6d57f7d 100644 --- a/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java @@ -33,7 +33,7 @@ ASTNeuron addExactSolution( workingVersion = addVariableToInternals(workingVersion, solverOutput.const_input); workingVersion = addVariableToInternals(workingVersion, solverOutput.ode_var_factor); - final List i_sumCalls = AstUtils.getAll(astNeuron.getOdeBlock().get(), ASTFunctionCall.class) + final List i_sumCalls = AstUtils.getAll(astNeuron.findEquationsBlock().get(), ASTFunctionCall.class) .stream() .filter(astFunctionCall -> astFunctionCall.getCalleeName().equals(PredefinedFunctions.CURR_SUM)) .collect(toList()); diff --git a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java index d26b334a7..3d3020c41 100644 --- a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java +++ b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java @@ -38,15 +38,15 @@ public class EquationsBlockProcessor { * @return Transformed neuron with either: exact solution or transformed shapes to its ODE notation */ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path outputBase) { - if (astNeuron.getOdeBlock().isPresent()) { + if (astNeuron.findEquationsBlock().isPresent()) { reporter.reportProgress(String.format("The neuron %s contains an ODE block. It will be analysed.", astNeuron.getName())); final ASTNeuron deepCopy = deepCloneNeuronAndBuildSymbolTable(astNeuron, outputBase); // this function is called only for neurons with an ode block. thus, retrieving it is safe. - if (deepCopy.getOdeBlock().get().getShapes().size() > 0 && - deepCopy.getOdeBlock().get().getODEs().size() == 1) { + if (deepCopy.findEquationsBlock().get().getShapes().size() > 0 && + deepCopy.findEquationsBlock().get().getODEs().size() == 1) { - final SolverOutput solverOutput = evaluator.solveOdeWithShapes(deepCopy.getOdeBlock().get(), outputBase); + final SolverOutput solverOutput = evaluator.solveOdeWithShapes(deepCopy.findEquationsBlock().get(), outputBase); reporter.reportProgress("The model ODE with shapes will be analyzed."); reporter.reportProgress("The solver script is evaluated. Results are stored under " + outputBase.toString()); @@ -72,9 +72,9 @@ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path output return astNeuron; } } - else if (deepCopy.getOdeBlock().get().getShapes().size() > 0) { + else if (deepCopy.findEquationsBlock().get().getShapes().size() > 0) { reporter.reportProgress("Shapes will be solved with GLS."); - final SolverOutput solverOutput = evaluator.solveShapes(deepCopy.getOdeBlock().get().getShapes(), outputBase); + final SolverOutput solverOutput = evaluator.solveShapes(deepCopy.findEquationsBlock().get().getShapes(), outputBase); return shapesToOdesTransformer.transformShapesToOdeForm(astNeuron, solverOutput); } diff --git a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java index 4b16fe2ee..da460047d 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java @@ -41,7 +41,7 @@ ASTNeuron addExactSolution( workingVersion = addVariablesToInternals(workingVersion, solverOutput.propagator_elements); workingVersion = addVariablesToState(workingVersion, solverOutput.shape_state_variables); workingVersion = addShapeStateUpdatesToUpdateBlock(workingVersion, solverOutput); - workingVersion.removeOdeBlock(); + workingVersion.removeEquationsBlock(); // oder is important, otherwise addShapeStateUpdatesToUpdateBlock will try to resolve state variables, // for which nor symbol are added. TODO filter them diff --git a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java index 276e9bd10..a1f73c8e0 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java @@ -7,9 +7,8 @@ import org.nest.nestml._ast.ASTDeclaration; import org.nest.nestml._ast.ASTEquation; +import org.nest.nestml._ast.ASTEquationsBlock; import org.nest.nestml._ast.ASTNeuron; -import org.nest.nestml._ast.ASTOdeDeclaration; -import org.nest.nestml.prettyprinter.NESTMLPrettyPrinter; import java.util.List; import java.util.Map; @@ -26,7 +25,7 @@ class ShapesToOdesTransformer extends TransformerBase { ASTNeuron transformShapesToOdeForm(final ASTNeuron astNeuron, final SolverOutput solverOutput) { - checkArgument(astNeuron.getOdeBlock().isPresent()); + checkArgument(astNeuron.findEquationsBlock().isPresent()); ASTNeuron workingVersion = addVariablesToState(astNeuron, solverOutput.shape_state_variables); workingVersion = addVariablesToInternals(workingVersion, solverOutput.initial_values); @@ -37,14 +36,14 @@ ASTNeuron transformShapesToOdeForm(final ASTNeuron astNeuron, final SolverOutput variableNameExtracter, shapeNameExtracter); - addStateShapeEquationsToEquationsBlock(solverOutput.shape_state_odes, workingVersion.getOdeBlock().get()); + addStateShapeEquationsToEquationsBlock(solverOutput.shape_state_odes, workingVersion.findEquationsBlock().get()); return workingVersion; } private void addStateShapeEquationsToEquationsBlock( final List> equationsFile, - final ASTOdeDeclaration astOdeDeclaration) { + final ASTEquationsBlock astOdeDeclaration) { final List equations = equationsFile.stream() .map(ode -> ode.getKey() + "' = " + ode.getValue()) .map(AstCreator::createEquation) @@ -52,7 +51,7 @@ private void addStateShapeEquationsToEquationsBlock( astOdeDeclaration.getODEs().addAll(equations); } - private List shapesToStateVariables(final ASTOdeDeclaration astOdeDeclaration) { + private List shapesToStateVariables(final ASTEquationsBlock astOdeDeclaration) { final List stateVariables = astOdeDeclaration.getShapes() .stream() .map(shape -> shape.getLhs().toString()) diff --git a/src/main/java/org/nest/codegeneration/sympy/SolverInput.java b/src/main/java/org/nest/codegeneration/sympy/SolverInput.java index 7f76672af..8186c6ac8 100644 --- a/src/main/java/org/nest/codegeneration/sympy/SolverInput.java +++ b/src/main/java/org/nest/codegeneration/sympy/SolverInput.java @@ -25,7 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; import org.nest.nestml._ast.ASTEquation; -import org.nest.nestml._ast.ASTOdeDeclaration; +import org.nest.nestml._ast.ASTEquationsBlock; import org.nest.nestml._ast.ASTOdeFunction; import org.nest.nestml._ast.ASTShape; import org.nest.nestml.prettyprinter.ExpressionsPrettyPrinter; @@ -43,8 +43,8 @@ class SolverInput { public final String ode; private final ExpressionsPrettyPrinter printer = new ExpressionsPrettyPrinter(); - SolverInput(final ASTOdeDeclaration odeBlock) { - ASTOdeDeclaration tmp = odeBlock.deepClone(); + SolverInput(final ASTEquationsBlock odeBlock) { + ASTEquationsBlock tmp = odeBlock.deepClone(); tmp = OdeTransformer.replaceSumCalls(tmp); ode = printEquation(tmp.getODEs().get(0)); diff --git a/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java b/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java index 2594c3eaa..4d3e618c9 100644 --- a/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java +++ b/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java @@ -8,7 +8,7 @@ import com.google.common.base.Charsets; import com.google.common.collect.Lists; import com.google.common.io.Resources; -import org.nest.nestml._ast.ASTOdeDeclaration; +import org.nest.nestml._ast.ASTEquationsBlock; import org.nest.nestml._ast.ASTShape; import org.nest.reporting.Reporter; @@ -46,7 +46,7 @@ class SymPySolver { private static final String ODE_ANALYZER_SCRIPT = "OdeAnalyzer.py"; private static final String ODE_ANALYZER_SOURCE = "org/nest/sympy/OdeAnalyzer.py"; - SolverOutput solveOdeWithShapes(final ASTOdeDeclaration astOdeDeclaration, final Path output) { + SolverOutput solveOdeWithShapes(final ASTEquationsBlock astOdeDeclaration, final Path output) { return executeSolver(new SolverInput(astOdeDeclaration), output); } diff --git a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java index 5b7c59555..33f8c84b4 100644 --- a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java +++ b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java @@ -161,7 +161,7 @@ void addUpdatesWithPSCInitialValues( final ASTNeuron body, final Function stateVariableNameExtracter, final Function shapeNameExtracter) { - final List i_sumCalls = OdeTransformer.get_sumFunctionCalls(body.getOdeBlock().get()); + final List i_sumCalls = OdeTransformer.get_sumFunctionCalls(body.findEquationsBlock().get()); final List pscInitialValues = solverOutput.initial_values .stream() @@ -223,7 +223,7 @@ ASTStmt statement(final ASTAssignment astAssignment) { } ASTNeuron removeShapes(ASTNeuron astNeuron) { - astNeuron.getOdeBlock().get().getShapes().clear(); + astNeuron.findEquationsBlock().get().getShapes().clear(); return astNeuron; } diff --git a/src/main/java/org/nest/nestml/_ast/ASTOdeDeclaration.java b/src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java similarity index 76% rename from src/main/java/org/nest/nestml/_ast/ASTOdeDeclaration.java rename to src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java index 4b492f4df..6daae7bcf 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTOdeDeclaration.java +++ b/src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java @@ -1,5 +1,5 @@ /* - * ASTOdeDeclaration.java + * ASTEquationsBlock.java * * This file is part of NEST. * @@ -21,7 +21,7 @@ package org.nest.nestml._ast; import org.nest.nestml._ast.ASTEquation; -import org.nest.nestml._ast.ASTOdeDeclarationTOP; +import org.nest.nestml._ast.ASTEquationsBlockTOP; import org.nest.nestml._ast.ASTOdeFunction; import org.nest.nestml._ast.ASTShape; @@ -32,17 +32,19 @@ * * @author plotnikov */ -public class ASTOdeDeclaration extends ASTOdeDeclarationTOP { - public ASTOdeDeclaration() { +public class ASTEquationsBlock extends ASTEquationsBlockTOP { + public ASTEquationsBlock() { } - public ASTOdeDeclaration( + public ASTEquationsBlock( + final ASTBLOCK_OPEN bLOCK_OPEN, final List equations, final List shapes, final List oDEAliass, - final List nEWLINEs) { - super(equations, shapes, oDEAliass, nEWLINEs); + final List nEWLINEs, + final ASTBLOCK_CLOSE bLOCK_CLOSE ) { + super(bLOCK_OPEN, equations, shapes, oDEAliass, nEWLINEs, bLOCK_CLOSE); } @Override diff --git a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java index 8ae3f0124..c5f9e8466 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java +++ b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java @@ -38,9 +38,9 @@ public ASTNeuron( final List nEWLINEs, final List blockWithVariabless, final List updateBlocks, - final List equationss, - final List inputs, - final List outputs, + final List equationss, + final List inputs, + final List outputs, final List functions, final ASTBLOCK_CLOSE bLOCK_close) { super(name, bLOCK_open, nEWLINEs, blockWithVariabless, updateBlocks, equationss, inputs, outputs, functions, bLOCK_close); @@ -113,9 +113,9 @@ public String printInternalComment() { } public List getEquations() { - final Optional equations = findEquationsBlock(); + final Optional equations = findEquationsBlock(); if (equations.isPresent()) { - return equations.get().getOdeDeclaration().getODEs(); + return equations.get().getODEs(); } else { return Lists.newArrayList(); @@ -123,9 +123,9 @@ public List getEquations() { } public List getShapes() { - final Optional equations = findEquationsBlock(); + final Optional equations = findEquationsBlock(); if (equations.isPresent()) { - return equations.get().getOdeDeclaration().getShapes(); + return equations.get().getShapes(); } else { return Lists.newArrayList(); @@ -139,8 +139,8 @@ public List variablesDefinedByODE() { .collect(toList()); } - private Optional findEquationsBlock() { - return this.getEquationss() + public Optional findEquationsBlock() { + return this.getEquationsBlocks() .stream() .findFirst(); @@ -298,22 +298,15 @@ private Optional findDynamics() { public List getInputLines() { List result = Lists.newArrayList(); - for (final ASTInput inputLine : this.getInputs()) { - result.addAll(inputLine.getInputLines()); + for (final ASTInputBlock inputBlock : this.getInputBlocks()) { + result.addAll(inputBlock.getInputLines()); } return result; } - public Optional getOdeBlock() { - final Optional odeBlock = findEquationsBlock(); - // checked by the filter conditions - return odeBlock.map(astBodyElement -> (astBodyElement).getOdeDeclaration()); - - } - - public void removeOdeBlock() { - this.setEquationss(Lists.newArrayList()); + public void removeEquationsBlock() { + this.setEquationsBlocks(Lists.newArrayList()); } public List getODEAliases() { diff --git a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoInput.java b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoInput.java index ba5230226..d34876554 100644 --- a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoInput.java +++ b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoInput.java @@ -19,7 +19,7 @@ public class NeuronWithMultipleOrNoInput implements NESTMLASTNeuronCoCo { public void check(final ASTNeuron neuron) { - List inputBlocks = neuron.getInputs(); + List inputBlocks = neuron.getInputBlocks(); if (inputBlocks.size() == 0) { final String msg = NestmlErrorStrings.errorNoInput(this); error(msg, neuron.get_SourcePositionStart()); diff --git a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoOutput.java b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoOutput.java index 36cd8f79d..90d7063b4 100644 --- a/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoOutput.java +++ b/src/main/java/org/nest/nestml/_cocos/NeuronWithMultipleOrNoOutput.java @@ -7,7 +7,7 @@ import de.se_rwth.commons.logging.Log; import org.nest.nestml._ast.ASTNeuron; -import org.nest.nestml._ast.ASTOutput; +import org.nest.nestml._ast.ASTOutputBlock; import java.util.List; @@ -21,7 +21,7 @@ public class NeuronWithMultipleOrNoOutput implements NESTMLASTNeuronCoCo { public void check(ASTNeuron neuron) { ASTNeuron bodyDecorator = (neuron); - final List outputs = bodyDecorator.getOutputs(); + final List outputs = bodyDecorator.getOutputBlocks(); if (outputs.size() == 0) { final String msg = NestmlErrorStrings.errorNoOutput(this); diff --git a/src/main/java/org/nest/nestml/_cocos/SumHasCorrectParameter.java b/src/main/java/org/nest/nestml/_cocos/SumHasCorrectParameter.java index 4d716c27a..a58a5e271 100644 --- a/src/main/java/org/nest/nestml/_cocos/SumHasCorrectParameter.java +++ b/src/main/java/org/nest/nestml/_cocos/SumHasCorrectParameter.java @@ -23,7 +23,7 @@ import de.se_rwth.commons.logging.Log; import org.nest.nestml._ast.ASTExpr; import org.nest.nestml._ast.ASTFunctionCall; -import org.nest.nestml._ast.ASTOdeDeclaration; +import org.nest.nestml._ast.ASTEquationsBlock; import org.nest.utils.AstUtils; import java.util.List; @@ -37,11 +37,11 @@ * * @author plotnikov */ -public class SumHasCorrectParameter implements NESTMLASTOdeDeclarationCoCo { +public class SumHasCorrectParameter implements NESTMLASTEquationsBlockCoCo { @Override - public void check(final ASTOdeDeclaration odeDeclaration) { - final List functions = AstUtils.getAll(odeDeclaration, ASTFunctionCall.class) + public void check(final ASTEquationsBlock astEquationsBlock) { + final List functions = AstUtils.getAll(astEquationsBlock, ASTFunctionCall.class) .stream() .filter(astFunctionCall -> astFunctionCall.getCalleeName().equals(CURR_SUM) || astFunctionCall.getCalleeName().equals(COND_SUM)) diff --git a/src/main/java/org/nest/nestml/_cocos/UsageOfAmbiguousName.java b/src/main/java/org/nest/nestml/_cocos/UsageOfAmbiguousName.java index 65d00e90d..37e1fa4e2 100644 --- a/src/main/java/org/nest/nestml/_cocos/UsageOfAmbiguousName.java +++ b/src/main/java/org/nest/nestml/_cocos/UsageOfAmbiguousName.java @@ -41,7 +41,7 @@ * @author plotnikov */ public class UsageOfAmbiguousName implements - NESTMLASTOdeDeclarationCoCo, + NESTMLASTEquationsBlockCoCo, NESTMLASTAssignmentCoCo, NESTMLASTFunctionCallCoCo, NESTMLASTDeclarationCoCo, @@ -120,7 +120,7 @@ private void checkExpression(final ASTExpr expr) { @Override - public void check(final ASTOdeDeclaration node) { + public void check(final ASTEquationsBlock node) { node.getOdeFunctions().forEach( oderAlias-> { checkVariableByName(oderAlias.getVariableName(), node); diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java index 40ed90444..5cc9a798a 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java @@ -98,8 +98,8 @@ public void visit(final ASTNeuron astNeuron) { public void endVisit(final ASTNeuron astNeuron) { setEnclosingScopeOfNodes(astNeuron); - if (astNeuron.getOdeBlock().isPresent()) { - addFunctionVariables(astNeuron.getOdeBlock().get()); + if (astNeuron.findEquationsBlock().isPresent()) { + addFunctionVariables(astNeuron.findEquationsBlock().get()); } // new variable from the ODE block could be added. Check, whether they don't clutter with existing one @@ -112,13 +112,13 @@ public void endVisit(final ASTNeuron astNeuron) { if (undefinedMethods.isEmpty()) { final List multipleDefinitions = nestmlCoCosManager.checkThatElementDefinedAtMostOnce(astNeuron); if (multipleDefinitions.isEmpty()) { - if (astNeuron.getOdeBlock().isPresent()) { + if (astNeuron.findEquationsBlock().isPresent()) { final List afterAddingDerivedVariables = nestmlCoCosManager.checkThatElementDefinedAtMostOnce(astNeuron); if (afterAddingDerivedVariables.isEmpty()) { - assignOdeToVariables(astNeuron.getOdeBlock().get()); - markConductanceBasedBuffers(astNeuron.getOdeBlock().get(), astNeuron.getInputLines()); + assignOdeToVariables(astNeuron.findEquationsBlock().get()); + markConductanceBasedBuffers(astNeuron.findEquationsBlock().get(), astNeuron.getInputLines()); } else { final String msg = LOGGER_NAME + " : Cannot correctly build the symboltable, at least one variable is " + @@ -159,7 +159,7 @@ public void endVisit(final ASTNeuron astNeuron) { * end * Results in an additional variable for G' (first equations G''). For the sake of the simplicity */ - private void addFunctionVariables(final ASTOdeDeclaration astOdeDeclaration) { + private void addFunctionVariables(final ASTEquationsBlock astOdeDeclaration) { for (final ASTOdeFunction astOdeAlias:astOdeDeclaration.getOdeFunctions()) { final VariableSymbol var = new VariableSymbol(astOdeAlias.getVariableName()); var.setAstNode(astOdeAlias); @@ -179,7 +179,7 @@ private void addFunctionVariables(final ASTOdeDeclaration astOdeDeclaration) { } } - private void assignOdeToVariables(final ASTOdeDeclaration astOdeDeclaration) { + private void assignOdeToVariables(final ASTEquationsBlock astOdeDeclaration) { astOdeDeclaration.getODEs().forEach(this::addOdeToVariable); } @@ -215,7 +215,7 @@ private void addOdeToVariable(final ASTEquation ode) { * * spikes buffer is marked conductanceBased */ - private void markConductanceBasedBuffers(final ASTOdeDeclaration astOdeDeclaration, List inputLines) { + private void markConductanceBasedBuffers(final ASTEquationsBlock astOdeDeclaration, List inputLines) { checkState(currentScope().isPresent()); if (!inputLines.isEmpty()) { diff --git a/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java b/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java index 364fe4111..b9e277132 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java +++ b/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java @@ -46,7 +46,7 @@ private void registerVariableExistenceChecks() { variableExistenceChecker.addCoCo((NESTMLASTAssignmentCoCo) usageOfAmbiguousName); variableExistenceChecker.addCoCo((NESTMLASTCompound_StmtCoCo) usageOfAmbiguousName); variableExistenceChecker.addCoCo((NESTMLASTDeclarationCoCo) usageOfAmbiguousName); - variableExistenceChecker.addCoCo((NESTMLASTOdeDeclarationCoCo) usageOfAmbiguousName); + variableExistenceChecker.addCoCo((NESTMLASTEquationsBlockCoCo) usageOfAmbiguousName); variableExistenceChecker.addCoCo((NESTMLASTDeclarationCoCo) usageOfAmbiguousName); } diff --git a/src/main/java/org/nest/nestml/_visitor/ODEPostProcessingVisitor.java b/src/main/java/org/nest/nestml/_visitor/ODEPostProcessingVisitor.java index d58641261..75ce4c2ac 100644 --- a/src/main/java/org/nest/nestml/_visitor/ODEPostProcessingVisitor.java +++ b/src/main/java/org/nest/nestml/_visitor/ODEPostProcessingVisitor.java @@ -22,7 +22,7 @@ package org.nest.nestml._visitor; import de.monticore.symboltable.Scope; -import org.nest.nestml._ast.ASTOdeDeclaration; +import org.nest.nestml._ast.ASTEquationsBlock; import org.nest.nestml._ast.ASTEquation; import org.nest.nestml._ast.ASTOdeFunction; import org.nest.nestml._ast.ASTShape; @@ -118,7 +118,7 @@ public void visit(final ASTEquation astEquation) { } @Override - public void traverse(ASTOdeDeclaration node) { + public void traverse(ASTEquationsBlock node) { //TODO: Find a sensible hierarchy for shapes,equations and aliases. for (ASTShape astShape : node.getShapes()) { astShape.accept(getRealThis()); diff --git a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java index 38bc715a8..46850c403 100644 --- a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java +++ b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java @@ -5,21 +5,17 @@ */ package org.nest.nestml.prettyprinter; -import de.monticore.ast.ASTNode; -import de.monticore.ast.Comment; import de.monticore.prettyprint.CommentPrettyPrinter; import de.monticore.prettyprint.IndentPrinter; import de.monticore.types.prettyprint.TypesPrettyPrinterConcreteVisitor; import org.nest.nestml._ast.*; import org.nest.nestml._visitor.NESTMLInheritanceVisitor; import org.nest.utils.AstUtils; -import org.nest.utils.PrettyPrinterBase; import java.util.List; import java.util.Optional; import static org.nest.nestml._symboltable.typechecking.TypeChecker.deserializeUnitIfNotPrimitive; -import static org.nest.utils.AstUtils.printComments; /** * Provides convenient functions to statically type interfaces ast-nodes resulting from the Body-grammar @@ -31,16 +27,14 @@ public class NESTMLPrettyPrinter implements NESTMLInheritanceVisitor { private static final String BLOCK_CLOSE = "end"; private static final String BLOCK_OPEN = ":"; private final ExpressionsPrettyPrinter expressionsPrinter; - private final ASTNESTMLNode root; private final IndentPrinter printer = new IndentPrinter(); - private NESTMLPrettyPrinter(final ASTNESTMLNode root) { + private NESTMLPrettyPrinter() { this.expressionsPrinter = new ExpressionsPrettyPrinter(); - this.root = root; } public static String print(final ASTNESTMLNode astNestmlNode) { - final NESTMLPrettyPrinter prettyPrinter = new NESTMLPrettyPrinter(astNestmlNode); + final NESTMLPrettyPrinter prettyPrinter = new NESTMLPrettyPrinter(); astNestmlNode.accept(prettyPrinter); return prettyPrinter.printer.getContent(); } @@ -60,7 +54,6 @@ public static String print(final ASTNESTMLNode astNestmlNode) { Output | Function)* BLOCK_CLOSE; - * @param astNeuron */ @Override public void handle(final ASTNeuron astNeuron) { @@ -71,9 +64,9 @@ public void handle(final ASTNeuron astNeuron) { printNodes(astNeuron.getBlockWithVariabless()); printNodes(astNeuron.getUpdateBlocks()); - printNodes(astNeuron.getEquationss()); - printNodes(astNeuron.getInputs()); - printNodes(astNeuron.getOutputs()); + printNodes(astNeuron.getEquationsBlocks()); + printNodes(astNeuron.getInputBlocks()); + printNodes(astNeuron.getOutputBlocks()); printNodes(astNeuron.getFunctions()); printer.unindent(); @@ -109,26 +102,205 @@ else if (astVarBlock.isParameters ()) { } public void handle(final ASTUpdateBlock astUpdateBlock) { + CommentPrettyPrinter.printPreComments(astUpdateBlock, printer); printer.println("update" + BLOCK_OPEN); printer.indent(); + printNode(astUpdateBlock.getBlock()); + printer.unindent(); printer.println(BLOCK_CLOSE); + CommentPrettyPrinter.printPostComments(astUpdateBlock, printer); } - private void printNodes(final List nodes) { - for (ASTNESTMLNode node:nodes) { - printNode(node); + @Override + public void handle(final ASTInputBlock astInput) { + CommentPrettyPrinter.printPreComments(astInput, printer); + printer.println("input" + BLOCK_OPEN); + printer.indent(); + + for (final ASTInputLine astInputLine:astInput.getInputLines()) { + printer.print(astInputLine.getName()); + printArrayParameter(astInputLine); + printer.print(" <- "); + printInputTypes(astInputLine.getInputTypes()); + printOutputType(astInputLine); + printer.println(); } + + printer.unindent(); + printer.println(BLOCK_CLOSE); + CommentPrettyPrinter.printPreComments(astInput, printer); + } - private void printNode(ASTNESTMLNode node) { - node.accept(this); + private void printInputTypes(final List inputTypes) { + for (final ASTInputType inputType:inputTypes) { + if (inputType.isInhibitory()) { + printer.print("inhibitory "); + } + else { + printer.print("excitatory "); + } + + } + + } + + private void printArrayParameter(final ASTInputLine astInputLine) { + astInputLine.getSizeParameter().ifPresent(parameter -> printer.print("[" + parameter + "]")); + } + + private void printOutputType(final ASTInputLine astInputLine) { + if (astInputLine.isSpike()) { + printer.print("spike"); + } + else { + printer.print("current"); + } + + } + @Override + public void handle(final ASTFunction astFunction) { + CommentPrettyPrinter.printPreComments(astFunction, printer); + printer.print("function " + astFunction.getName()); + printParameters(astFunction.getParameters()); + printOptionalReturnValue(astFunction); + printer.println(BLOCK_OPEN); + printer.indent(); + astFunction.getBlock().accept(this); + printer.unindent(); + printer.println(BLOCK_CLOSE); + CommentPrettyPrinter.printPostComments(astFunction, printer); + } + + + private void printParameters(final Optional functionParameters) { + printer.print("("); + if (functionParameters.isPresent()) { + final List astParameters = functionParameters.get().getParameters(); + for (int curParameterIndex = 0; curParameterIndex < astParameters.size(); ++curParameterIndex) { + boolean isLastParameter = (curParameterIndex + 1) == astParameters.size(); + final ASTParameter curParameter = astParameters.get(curParameterIndex); + printer.print(curParameter.getName() + " " + deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(curParameter.getDatatype()))); + if (!isLastParameter) { + printer.print(", "); + } + + } + + } + printer.print(")"); + } + + private void printOptionalReturnValue(final ASTFunction astFunction) { + if (astFunction.getReturnType().isPresent()) { + printer.print(deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(astFunction.getReturnType().get()))); + } + + } + + @Override + public void handle(final ASTOutputBlock astOutput) { + printer.print("output: "); + if (astOutput.isSpike()) { + printer.print("spike"); + } + else { + printer.print("current"); + } + + printer.println(); + } + /** + * Equations implements BodyElement = + * "equations" + * BLOCK_OPEN + * OdeDeclaration + * BLOCK_CLOSE; + * + * OdeDeclaration = (Eq | Shape | ODEAlias | NEWLINE)+; + * Equation = lhs:Derivative "=" rhs:Expr (";")?; + * Derivative = name:QualifiedName (differentialOrder:"\'")*; + * ODEAlias = variableName:Name Datatype "=" Expr; + */ + @Override + public void handle(final ASTEquationsBlock astOdeDeclaration) { + CommentPrettyPrinter.printPreComments(astOdeDeclaration, printer); + printer.println("equations" + BLOCK_OPEN); + printer.indent(); + + astOdeDeclaration.getShapes().forEach(astShape -> printShape(astShape, printer)); + astOdeDeclaration.getOdeFunctions().forEach(astOdeFunction -> printOdeFunctions(astOdeFunction, printer)); + astOdeDeclaration.getODEs().forEach(astEquation -> printEquation(astEquation, printer)); + + printer.unindent(); + printer.println(BLOCK_CLOSE); + CommentPrettyPrinter.printPreComments(astOdeDeclaration, printer); + } + + + private void printShape(final ASTShape shape, final IndentPrinter printer) { + CommentPrettyPrinter.printPreComments(shape, printer); + printer.println(printShape(shape)); + CommentPrettyPrinter.printPostComments(shape, printer); + } + + /** + * This method is used in freemaker template. Therefore, it must remain public. + */ + public String printShape(final ASTShape astShape) { + return "shape " + astShape.getLhs() + " = " + expressionsPrinter.print(astShape.getRhs()); } + private void printOdeFunctions(final ASTOdeFunction astOdeFunction, final IndentPrinter printer) { + CommentPrettyPrinter.printPreComments(astOdeFunction, printer); + printer.println(printOdeFunction(astOdeFunction)); + CommentPrettyPrinter.printPostComments(astOdeFunction, printer); + } + + /** + * This method is used in freemaker template. Therefore, remains public. + */ + public String printOdeFunction(final ASTOdeFunction astOdeFunction) { + + final String datatype = deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(astOdeFunction.getDatatype())); + + final String initExpression = expressionsPrinter.print(astOdeFunction.getExpr()); + final StringBuilder recordable = new StringBuilder(); + if (astOdeFunction.isRecordable()) { + recordable.append("recordable "); + } + return recordable.toString() + "function " + astOdeFunction.getVariableName() + " " + datatype + " = " + initExpression; + } + + private void printEquation(final ASTEquation astEquation, final IndentPrinter printer) { + CommentPrettyPrinter.printPreComments(astEquation, printer); + printer.println(printEquation(astEquation)); + CommentPrettyPrinter.printPostComments(astEquation, printer); + } + + /** + * This method is used in freemaker template. Therefore, it must remain public. + */ + public String printEquation(final ASTEquation astEquation) { + return astEquation.getLhs() + " = " + expressionsPrinter.print(astEquation.getRhs()); + } //////////////////////////////////////////////////////////////////////////// // SPL PART //////////////////////////////////////////////////////////////////////////// + public void handle(final ASTStmt astStmt) { + CommentPrettyPrinter.printPreComments(astStmt, printer); + if (astStmt.small_StmtIsPresent()) { + printNode(astStmt.getSmall_Stmt().get()); + } + else if (astStmt.compound_StmtIsPresent()) { + printNode(astStmt.getCompound_Stmt().get()); + } + + CommentPrettyPrinter.printPostComments(astStmt, printer); + } + public void handle(final ASTDeclaration astDeclaration) { astDeclaration.getDocStrings().forEach(printer::println); @@ -196,18 +368,18 @@ private void printOptionalInitializationExpression(final ASTDeclaration astDecla * Small_Stmt = Assignment| FunctionCall | Declaration | ReturnStmt; */ @Override - public void handle(final ASTSmall_Stmt astSmallStmt ) { + public void handle(final ASTSmall_Stmt astSmallStmt) { CommentPrettyPrinter.printPreComments(astSmallStmt, printer); if (astSmallStmt.getAssignment().isPresent()) { - my_handle(astSmallStmt.getAssignment().get()); + printAssignment(astSmallStmt.getAssignment().get()); } else if (astSmallStmt.getFunctionCall().isPresent()) { - my_handle(astSmallStmt.getFunctionCall().get()); + printFunctionCall(astSmallStmt.getFunctionCall().get()); } else if (astSmallStmt.getDeclaration().isPresent()) { // TODO: must be also a functions that is get called from the corresponding method astSmallStmt.getDeclaration().get().accept(this); } else if (astSmallStmt.getReturnStmt().isPresent()) { - my_handle(astSmallStmt.getReturnStmt().get()); + printReturnStatement(astSmallStmt.getReturnStmt().get()); } printer.println(); CommentPrettyPrinter.printPreComments(astSmallStmt, printer); @@ -217,7 +389,8 @@ public void handle(final ASTSmall_Stmt astSmallStmt ) { * Grammar: * Assignment = variableName:QualifiedName "=" Expr; */ - public void my_handle(final ASTAssignment astAssignment) { + private void printAssignment(final ASTAssignment astAssignment) { + CommentPrettyPrinter.printPreComments(astAssignment, printer); final String lhsVariableName = astAssignment.getLhsVarialbe().toString(); final String rhsOfAssignment = expressionsPrinter.print(astAssignment.getExpr()); if (astAssignment.isAssignment()) { @@ -235,7 +408,7 @@ public void my_handle(final ASTAssignment astAssignment) { if (astAssignment.isCompoundQuotient()) { printer.print(lhsVariableName + " /= " + rhsOfAssignment); } - + CommentPrettyPrinter.printPostComments(astAssignment, printer); } /** @@ -244,7 +417,8 @@ public void my_handle(final ASTAssignment astAssignment) { * ArgList = (args:Expr ("," args:Expr)*)?; */ - public void my_handle(final ASTFunctionCall astFunctionCall) { + private void printFunctionCall(final ASTFunctionCall astFunctionCall) { + CommentPrettyPrinter.printPreComments(astFunctionCall, printer); final String functionName = astFunctionCall.getCalleeName(); printer.print(functionName + "("); final List functionArguments = astFunctionCall.getArgs(); @@ -258,13 +432,14 @@ public void my_handle(final ASTFunctionCall astFunctionCall) { } printer.print(")"); + CommentPrettyPrinter.printPostComments(astFunctionCall, printer); } /** * ReturnStmt = "return" Expr?; */ - public void my_handle(final ASTReturnStmt astReturnStmt) { - + private void printReturnStatement(final ASTReturnStmt astReturnStmt) { + CommentPrettyPrinter.printPreComments(astReturnStmt, printer); if (astReturnStmt.getExpr().isPresent()) { final String returnExpressionAsString = expressionsPrinter.print(astReturnStmt.getExpr().get()); printer.print("return " + returnExpressionAsString); @@ -272,6 +447,114 @@ public void my_handle(final ASTReturnStmt astReturnStmt) { else { printer.print("return"); } + CommentPrettyPrinter.printPostComments(astReturnStmt, printer); + } + + @Override + public void handle(final ASTCompound_Stmt astCompoundStmt) { + CommentPrettyPrinter.printPreComments(astCompoundStmt, printer); + + if (astCompoundStmt.getIF_Stmt().isPresent()) { + final ASTIF_Stmt ifStatement = astCompoundStmt.getIF_Stmt().get(); + printIfStatement(ifStatement); + } + else if (astCompoundStmt.getFOR_Stmt().isPresent()) { + final ASTFOR_Stmt astForStmt = astCompoundStmt.getFOR_Stmt().get(); + printForStatement(astForStmt); + } + else if (astCompoundStmt.getWHILE_Stmt().isPresent()) { + final ASTWHILE_Stmt astWhileStatement = astCompoundStmt.getWHILE_Stmt().get(); + printWhileStatement(astWhileStatement); + } + CommentPrettyPrinter.printPostComments(astCompoundStmt, printer); } + + private void printWhileStatement(ASTWHILE_Stmt astWhileStatement) { + CommentPrettyPrinter.printPreComments(astWhileStatement, printer); + printer.print("while "); + printer.print(expressionsPrinter.print(astWhileStatement.getExpr())); + printer.println(BLOCK_OPEN); + printer.indent(); + printNode(astWhileStatement.getBlock()); + printer.unindent(); + printer.println(BLOCK_CLOSE); + CommentPrettyPrinter.printPostComments(astWhileStatement, printer); + } + + private void printForStatement(ASTFOR_Stmt astForStmt) { + CommentPrettyPrinter.printPreComments(astForStmt, printer); + printer.print("for "); + printer.print(astForStmt.getVar()); + printer.print(" in "); + printer.print(expressionsPrinter.print(astForStmt.getFrom())); + printer.print(" ... "); + printer.print(expressionsPrinter.print(astForStmt.getTo())); + printer.print(" step "); + printer.print(typesPrinter().prettyprint(astForStmt.getStep())); + + printer.println(BLOCK_OPEN); + printer.indent(); + printNode(astForStmt.getBlock()); + printer.unindent(); + printer.println(BLOCK_CLOSE); + CommentPrettyPrinter.printPostComments(astForStmt, printer); + } + + private void printIfStatement(ASTIF_Stmt ifStatement) { + CommentPrettyPrinter.printPreComments(ifStatement, printer); + final String ifCondition = expressionsPrinter.print(ifStatement.getIF_Clause().getExpr()); + + CommentPrettyPrinter.printPreComments(ifStatement.getIF_Clause(), printer); + CommentPrettyPrinter.printPostComments(ifStatement.getIF_Clause(), printer); + printer.println("if " + ifCondition + BLOCK_OPEN); + printer.indent(); + printNode(ifStatement.getIF_Clause().getBlock()); + printer.unindent(); + + if (!ifStatement.getELSE_Clause().isPresent() && + ifStatement.getELIF_Clauses().isEmpty()) { + printer.println(BLOCK_CLOSE); + } + + for (final ASTELIF_Clause astElifClause:ifStatement.getELIF_Clauses()) { + CommentPrettyPrinter.printPreComments(astElifClause, printer); + CommentPrettyPrinter.printPostComments(astElifClause, printer); + final String elifCondition = expressionsPrinter.print(astElifClause.getExpr()); + printer.println("elif " + elifCondition + BLOCK_OPEN); + printer.indent(); + printNode(astElifClause.getBlock()); + printer.unindent(); + } + if (!ifStatement.getELSE_Clause().isPresent() && + !ifStatement.getELIF_Clauses().isEmpty()) { + printer.println(BLOCK_CLOSE); + } + + if (ifStatement.getELSE_Clause().isPresent()) { + final ASTELSE_Clause elseClause = ifStatement.getELSE_Clause().get(); + CommentPrettyPrinter.printPreComments(elseClause, printer); + CommentPrettyPrinter.printPostComments(elseClause, printer); + + printNode(elseClause.getBlock()); + printer.println(BLOCK_CLOSE); + } + CommentPrettyPrinter.printPostComments(ifStatement, printer); + } + + private TypesPrettyPrinterConcreteVisitor typesPrinter() { + final IndentPrinter printer = new IndentPrinter(); + return new TypesPrettyPrinterConcreteVisitor(printer); + } + + private void printNodes(final List nodes) { + for (ASTNESTMLNode node:nodes) { + printNode(node); + } + } + + private void printNode(ASTNESTMLNode node) { + node.accept(this); + } + } diff --git a/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl b/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl index 0ace18593..3470597e9 100644 --- a/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl +++ b/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl @@ -15,7 +15,7 @@ ${neuronName}_dynamics( double, const double y[], double f[], void* pnode ) // y[] here is---and must be---the state vector supplied by the integrator, // not the state vector in the node, node.S_.y[]. - <#list body.getOdeBlock().get().getODEs() as ode> + <#list body.findEquationsBlock().get().getODEs() as ode> <#assign simpleOde = odeTransformer.replaceSumCalls(ode)> <#list astUtils.getAliasSymbols(ode) as function> <#if !function.isInEquation()> diff --git a/src/main/resources/org/nest/spl/small_statement/FunctionCall.ftl b/src/main/resources/org/nest/spl/small_statement/FunctionCall.ftl index a110c547c..b871b3838 100644 --- a/src/main/resources/org/nest/spl/small_statement/FunctionCall.ftl +++ b/src/main/resources/org/nest/spl/small_statement/FunctionCall.ftl @@ -7,7 +7,7 @@ @result TODO --> <#if functions.isIntegrate(ast)> -${tc.include("org.nest.spl.small_statement.GSLIntegrator", body.getOdeBlock().get())} +${tc.include("org.nest.spl.small_statement.GSLIntegrator", body)} <#else> ${expressionsPrinter.printMethodCall(ast)}; diff --git a/src/test/java/org/nest/codegeneration/sympy/SolverInputTest.java b/src/test/java/org/nest/codegeneration/sympy/SolverInputTest.java index f6aa50415..61b81888a 100644 --- a/src/test/java/org/nest/codegeneration/sympy/SolverInputTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/SolverInputTest.java @@ -24,7 +24,7 @@ import org.junit.Test; import org.nest.base.ModelbasedTest; import org.nest.nestml._ast.ASTNESTMLCompilationUnit; -import org.nest.nestml._ast.ASTOdeDeclaration; +import org.nest.nestml._ast.ASTEquationsBlock; import static org.junit.Assert.*; @@ -41,7 +41,7 @@ public class SolverInputTest extends ModelbasedTest { public void test_cond_model() { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(COND_MODEL_FILE_PATH); - final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getOdeBlock().get(); + final ASTEquationsBlock odeBlock = root.getNeurons().get(0).findEquationsBlock().get(); SolverInput solverInput = new SolverInput(odeBlock); String result = solverInput.toJSON(); System.out.println(result); @@ -53,7 +53,7 @@ public void test_cond_model() { public void test_psc_model() { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(PSC_MODEL_FILE_PATH); - final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getOdeBlock().get(); + final ASTEquationsBlock odeBlock = root.getNeurons().get(0).findEquationsBlock().get(); SolverInput solverInput = new SolverInput(odeBlock); String result = solverInput.toJSON(); System.out.println(result); @@ -65,7 +65,7 @@ public void test_psc_model() { public void test_shapes_only() { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(PSC_MODEL_FILE_PATH); - final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getOdeBlock().get(); + final ASTEquationsBlock odeBlock = root.getNeurons().get(0).findEquationsBlock().get(); SolverInput solverInput = new SolverInput(odeBlock.getShapes()); String result = solverInput.toJSON(); System.out.println(result); @@ -77,7 +77,7 @@ public void test_shapes_only() { public void test_delta_shape() { ASTNESTMLCompilationUnit root = parseAndBuildSymboltable(DELTA_MODEL_FILE_PATH); - final ASTOdeDeclaration odeBlock = root.getNeurons().get(0).getOdeBlock().get(); + final ASTEquationsBlock odeBlock = root.getNeurons().get(0).findEquationsBlock().get(); SolverInput solverInput = new SolverInput(odeBlock); String result = solverInput.toJSON(); System.out.println(result); diff --git a/src/test/java/org/nest/codegeneration/sympy/SymPySolverTest.java b/src/test/java/org/nest/codegeneration/sympy/SymPySolverTest.java index 817e55d08..1cdff7065 100644 --- a/src/test/java/org/nest/codegeneration/sympy/SymPySolverTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/SymPySolverTest.java @@ -23,7 +23,7 @@ import org.junit.Test; import org.nest.base.ModelbasedTest; import org.nest.nestml._ast.ASTNESTMLCompilationUnit; -import org.nest.nestml._ast.ASTOdeDeclaration; +import org.nest.nestml._ast.ASTEquationsBlock; import org.nest.nestml._symboltable.NESTMLScopeCreator; import org.nest.utils.FilesHelper; @@ -86,7 +86,7 @@ private SolverOutput executeSolver(final String pathToModel) throws IOException FilesHelper.deleteFilesInFolder(SYMPY_OUTPUT); final SymPySolver symPySolver = new SymPySolver(); - final ASTOdeDeclaration astOdeDeclaration = root.get().getNeurons().get(0).getOdeBlock().get(); + final ASTEquationsBlock astOdeDeclaration = root.get().getNeurons().get(0).findEquationsBlock().get(); return symPySolver.solveOdeWithShapes(astOdeDeclaration, SYMPY_OUTPUT); } diff --git a/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java b/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java index 3eb3f87ba..1391593da 100644 --- a/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java +++ b/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java @@ -595,7 +595,7 @@ public void testVariableBlockDefinedMultipleTimes() { @Test public void testUndefinedVariablesInEquations() { final UsageOfAmbiguousName usageOfAmbiguousName = new UsageOfAmbiguousName(); - nestmlCoCoChecker.addCoCo((NESTMLASTOdeDeclarationCoCo) usageOfAmbiguousName); + nestmlCoCoChecker.addCoCo((NESTMLASTEquationsBlockCoCo) usageOfAmbiguousName); nestmlCoCoChecker.addCoCo((NESTMLASTCompound_StmtCoCo) usageOfAmbiguousName); nestmlCoCoChecker.addCoCo((NESTMLASTAssignmentCoCo) usageOfAmbiguousName); nestmlCoCoChecker.addCoCo((NESTMLASTDeclarationCoCo) usageOfAmbiguousName); diff --git a/src/test/java/org/nest/nestml/_parser/ODEParsingTest.java b/src/test/java/org/nest/nestml/_parser/ODEParsingTest.java index b9a6fdf52..e5a8357da 100644 --- a/src/test/java/org/nest/nestml/_parser/ODEParsingTest.java +++ b/src/test/java/org/nest/nestml/_parser/ODEParsingTest.java @@ -26,7 +26,7 @@ import org.junit.Test; import org.nest.base.ModelbasedTest; import org.nest.nestml._ast.ASTEquation; -import org.nest.nestml._ast.ASTOdeDeclaration; +import org.nest.nestml._ast.ASTEquationsBlock; import java.io.IOException; import java.io.StringReader; @@ -46,9 +46,11 @@ public class ODEParsingTest extends ModelbasedTest { @Test public void testOdeDefinition() throws IOException { final String odeDeclarationAsString = - "I = w * (E/tau_in) * t * exp(-1/tau_in*t)\n" + - "V' = -1/Tau * V + 1/C*I\n" ; - Optional res = parseOdeDeclaration(odeDeclarationAsString); + "equations:\n" + + " I = w * (E/tau_in) * t * exp(-1/tau_in*t)\n" + + " V' = -1/Tau * V + 1/C*I\n" + + "end\n"; + Optional res = parseOdeDeclaration(odeDeclarationAsString); assertTrue(res.isPresent()); } @@ -73,9 +75,9 @@ private Optional parseEquation(String input) throws RecognitionExce } - private Optional parseOdeDeclaration(String input) throws RecognitionException, IOException { + private Optional parseOdeDeclaration(String input) throws RecognitionException, IOException { - return parser.parseOdeDeclaration(new StringReader(input)); + return parser.parseEquationsBlock(new StringReader(input)); } diff --git a/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java b/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java index cf3cbf955..479484fb4 100644 --- a/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java +++ b/src/test/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinterTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertTrue; /** - * Processes all NESTML modles. Then, prettyprints them and parses again, to check the soundness of + * Processes all NESTML models. Then, prettyprints them and parses again, to check the soundness of * the printed models. * * @author plotnikov @@ -39,7 +39,7 @@ public static void BeforeTestsuite() { @Test public void testThatPrettyPrinterProducesParsableOutput() throws IOException { - parseAndCheckNestmlModel("models/iaf_cond_alpha.nestml"); + parseAndCheckNestmlModel("src/test/resources/org/nest/nestml/parsing/comment.nestml"); } @Test @@ -76,7 +76,7 @@ private void parseAndCheckNestmlModel(String pathToModel) throws IOException { final Optional modelRoot = nestmlParser.parse(pathToModel); assertTrue("Cannot parse the model: " + pathToModel, modelRoot.isPresent()); - System.out.printf(NESTMLPrettyPrinter.print(modelRoot.get())); + System.out.println(NESTMLPrettyPrinter.print(modelRoot.get())); final Optional prettyPrintedRoot = parseString(NESTMLPrettyPrinter.print(modelRoot.get())); assertTrue(prettyPrintedRoot.isPresent()); } @@ -86,13 +86,9 @@ public void testPrintingComment() throws IOException { final ASTNESTMLCompilationUnit root = parseNestmlModel("src/test/resources/org/nest/nestml/parsing/comment.nestml"); - - final String printedModel = NESTMLPrettyPrinter.print(root.getNeurons().get(0).getFunctions().get(0).getBlock()); - System.out.println("!!!"); System.out.println(printedModel); - System.out.println("!!!"); Optional prettyPrintedRoot = nestmlParser.parseBlock(new StringReader(printedModel)); assertTrue(prettyPrintedRoot.isPresent()); diff --git a/src/test/java/org/nest/utils/AstUtilsTest.java b/src/test/java/org/nest/utils/AstUtilsTest.java index fecfbe591..6807caab1 100644 --- a/src/test/java/org/nest/utils/AstUtilsTest.java +++ b/src/test/java/org/nest/utils/AstUtilsTest.java @@ -23,9 +23,9 @@ public class AstUtilsTest extends ModelbasedTest { @Test public void testComputationAliases() { final ASTNESTMLCompilationUnit astCompilationUnit = parseAndBuildSymboltable(PSC_MODEL_WITH_ODE); - Assert.assertTrue(astCompilationUnit.getNeurons().get(0).getOdeBlock().isPresent()); + Assert.assertTrue(astCompilationUnit.getNeurons().get(0).findEquationsBlock().isPresent()); - final List aliasesIn = AstUtils.getAliasSymbols(astCompilationUnit.getNeurons().get(0).getOdeBlock().get()); + final List aliasesIn = AstUtils.getAliasSymbols(astCompilationUnit.getNeurons().get(0).findEquationsBlock().get()); final Optional testant = aliasesIn.stream().filter(alias -> alias.getName().equals("I_syn_ampa")).findAny(); Assert.assertTrue(testant.isPresent()); } diff --git a/src/test/resources/org/nest/nestml/parsing/comment.nestml b/src/test/resources/org/nest/nestml/parsing/comment.nestml index cca6acc43..7f582b6f5 100644 --- a/src/test/resources/org/nest/nestml/parsing/comment.nestml +++ b/src/test/resources/org/nest/nestml/parsing/comment.nestml @@ -1,7 +1,8 @@ neuron Dummy: function f(): # Comment 1 - if 1 > 2:# Comment 2 + if 1 > 2: + # Comment 2 # Comment 3 if 3 > 4: # Comment 4 @@ -12,7 +13,8 @@ neuron Dummy: else: # Comment 6 cc integer - end # Comment 7 + end + # Comment 7 if true: # Comment 8 @@ -20,7 +22,8 @@ neuron Dummy: end # Comment 9 # Comment 10 - a integer = 11 # comment 11 + a integer = 11 + # comment 11 end end From b2cd0667b2190471eb401c750c51a03e57f5f548 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Mon, 11 Sep 2017 14:26:58 +0200 Subject: [PATCH 03/17] Fix the printing of the else-branch. This fixes the generated code. --- .../prettyprinter/NESTMLPrettyPrinter.java | 4 +- .../org/nest/frontend/NestmlFrontendTest.java | 3 +- src/test/resources/neuron_tester.py | 129 ++++++++++++++++++ 3 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 src/test/resources/neuron_tester.py diff --git a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java index 46850c403..f929c5283 100644 --- a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java +++ b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java @@ -535,8 +535,10 @@ private void printIfStatement(ASTIF_Stmt ifStatement) { final ASTELSE_Clause elseClause = ifStatement.getELSE_Clause().get(); CommentPrettyPrinter.printPreComments(elseClause, printer); CommentPrettyPrinter.printPostComments(elseClause, printer); - + printer.println("else " + BLOCK_OPEN); + printer.indent(); printNode(elseClause.getBlock()); + printer.unindent(); printer.println(BLOCK_CLOSE); } CommentPrettyPrinter.printPostComments(ifStatement, printer); diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index 19386b804..fcd03ec93 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -127,8 +127,9 @@ public void testTutorialModels() { @Test public void manually() { final String[] args = new String[] { - "models/terub_neuron_stn.nestml", + "models/iaf_psc_alpha.nestml", "--json_log", "model_issues", + "--enable_tracing", "--target", outputPath.toString()}; new NestmlFrontend().start(args); diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py new file mode 100644 index 000000000..e03a0993d --- /dev/null +++ b/src/test/resources/neuron_tester.py @@ -0,0 +1,129 @@ + +import nest +import pylab + +nest.Install("models") +nest.set_verbosity("M_WARNING") + +def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): + nest.ResetKernel() + neuron1=nest.Create (referenceModel) + neuron2=nest.Create (testant) + + if not (gsl_error_tol is None): + nest.SetStatus(neuron2, {"gsl_error_tol": gsl_error_tol}) + + spikegenerator=nest.Create('spike_generator',params={'spike_times':[100.0, 200.0], 'spike_weights':[1.0, -1.0]}) + + nest.Connect(spikegenerator, neuron1) + nest.Connect(spikegenerator, neuron2) + + multimeter1=nest.Create('multimeter') + multimeter2=nest.Create('multimeter') + + V_m_specifier = 'V_m'# 'delta_V_m' + nest.SetStatus (multimeter1, {"withtime":True, "record_from":[V_m_specifier]}) + nest.SetStatus (multimeter2, {"withtime":True, "record_from":[V_m_specifier]}) + + nest.Connect (multimeter1, neuron1) + nest.Connect (multimeter2, neuron2) + + nest.Simulate (400.0) + dmm1=nest.GetStatus(multimeter1)[0] + Vms1=dmm1["events"][V_m_specifier] + ts1=dmm1["events"]["times"] + + events1=dmm1["events"] + pylab.figure(1) + + dmm2=nest.GetStatus(multimeter2)[0] + Vms2=dmm2["events"][V_m_specifier] + ts2=dmm2["events"]["times"] + + pylab.plot(ts1, Vms1, label = "Reference " + referenceModel) + pylab.plot(ts2, Vms2, label = "Testant " + testant) + pylab.legend(loc='upper right') + + pylab.show() + for index in range(0, len(Vms1)): + if abs(Vms1[index]-Vms2[index]) > tolerance: + print('!!!!!!!!!!!!!!!!!!!!') + print(str(Vms1[index]) + " divers from " + str(Vms2[index]) + " at iteration: " + str(index) + " of overall iterations: " + str(len(Vms1))) + print('!!!!!!!!!!!!!!!!!!!!') + raise Exception(testant + ": TEST FAILED") + elif abs(Vms1[index]-Vms2[index]) > 0: + None #print("Greater than 0 difference" + str(abs(Vms1[index]-Vms2[index])) + " at iteration: " + str(index) + " of overall iterations: " + str(len(Vms1))) + print(testant + " PASSED") + + + +def test_multysinapse(): + neuron1=nest.Create ("iaf_psc_alpha_multisynapse_neuron") + neuron2=nest.Create ("iaf_psc_alpha_multisynapse_neuron") + + nest.SetDefaults("iaf_psc_alpha_multisynapse", {"tau_syn": [1.0,2.0]}) + + + spikegenerator=nest.Create('spike_generator',params={'spike_times':[100.0, 200.0] }) + + syn_dict ={"model": "static_synapse", "weight":2.5, 'receptor_type': 1} + + nest.Connect(spikegenerator, neuron2, syn_spec= syn_dict) + nest.Connect(spikegenerator, neuron1, syn_spec= syn_dict) + + #nest.SetStatus(neuron1, {"I_e": 376.0}) + #nest.SetStatus(neuron2, {"I_e": 376.0}) + + multimeter1=nest.Create('multimeter') + multimeter2=nest.Create('multimeter') + + V_m_specifier = 'V_m'# 'delta_V_m' + nest.SetStatus (multimeter1, {"withtime":True, "record_from":[V_m_specifier]}) + nest.SetStatus (multimeter2, {"withtime":True, "record_from":[V_m_specifier]}) + + nest.Connect (multimeter1, neuron1) + nest.Connect (multimeter2, neuron2) + + nest.Simulate (400.0) + dmm1=nest.GetStatus(multimeter1)[0] + Vms1=dmm1["events"][V_m_specifier] + ts1=dmm1["events"]["times"] + + events1=dmm1["events"] + pylab.figure(1) + + dmm2=nest.GetStatus(multimeter2)[0] + Vms2=dmm2["events"][V_m_specifier] + ts2=dmm2["events"]["times"] + + pylab.plot(ts1,Vms1) + pylab.plot(ts2,Vms2) + + pylab.show() + + for index in range(0, len(Vms1)): + if abs(Vms1[index]-Vms2[index]) > 0.000001: + print('!!!!!!!!!!!!!!!!!!!!') + print(str(Vms1[index]) + " divers from " + str(Vms2[index]) + " at iteration: " + str(index) + " of overall iterations: " + str(len(Vms1))) + print('!!!!!!!!!!!!!!!!!!!!') + raise Exception("TEST FAILED") + elif abs(Vms1[index]-Vms2[index]) > 0: + print("Greater than 0 difference" + str(abs(Vms1[index]-Vms2[index])) + " at iteration: " + str(index) + " of overall iterations: " + str(len(Vms1))) + print("Test: PASSED") + + + + +if __name__ == "__main__": + # execute only if run as a script + # test_multysinapse() + models = list() + + + models.append( ("iaf_psc_alpha", "iaf_psc_alpha_neuron", None, 0.001)) + + + for reference, testant, gsl_error_tol, tollerance in models: + test(reference, testant, gsl_error_tol, tollerance) + + \ No newline at end of file From c3ff45e9d8616730380306756aa5382b1b785bd9 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Mon, 11 Sep 2017 17:02:41 +0200 Subject: [PATCH 04/17] Cleanup the grammar --- models/iaf_cond_alpha.nestml | 14 ++--- src/main/grammars/org/nest/NESTML.mc4 | 51 ++++++++++++------- .../helpers/NESTFunctionPrinter.java | 38 +++++++------- .../java/org/nest/nestml/_ast/ASTNeuron.java | 3 +- .../_cocos/FunctionParameterHasTypeName.java | 26 +++++----- .../_cocos/InvalidTypesInDeclaration.java | 34 ++++++------- .../MemberVariableDefinedMultipleTimes.java | 2 +- .../nestml/_cocos/RestrictUseOfShapes.java | 5 +- .../NESTMLSymbolTableCreator.java | 39 ++++++++------ .../_symboltable/NestmlCoCosManager.java | 2 +- .../nestml/_symboltable/NestmlSymbols.java | 13 ++--- .../prettyprinter/NESTMLPrettyPrinter.java | 19 +++---- src/main/java/org/nest/utils/AstUtils.java | 4 +- .../org/nest/frontend/NestmlFrontendTest.java | 2 +- 14 files changed, 126 insertions(+), 126 deletions(-) diff --git a/models/iaf_cond_alpha.nestml b/models/iaf_cond_alpha.nestml index 30a106cf9..9f9238492 100644 --- a/models/iaf_cond_alpha.nestml +++ b/models/iaf_cond_alpha.nestml @@ -130,20 +130,14 @@ neuron iaf_cond_alpha_implicit: state: V_m mV = E_L ## membrane potential - g_in nS = 0nS ## inputs from the inh conductance - g_ex nS = 0nS ## inputs from the exc conductance - - g_in' nS/ms = 0 ## inputs from the inh conductance - g_ex' nS/ms = 0 ## inputs from the exc conductance - r integer ## refractory counter end equations: - g_in'' = (-1)/(tau_syn_in)**(2)*g_in+(-2)/tau_syn_in*g_in' - g_in' = g_in' - g_ex'' = (-1)/(tau_syn_ex)**(2)*g_ex+(-2)/tau_syn_ex*g_ex' - g_ex' = g_ex' + shape g_in'' = (-1)/(tau_syn_in)**(2)*g_in+(-2)/tau_syn_in*g_in' + shape g_in' = g_in' + shape g_ex'' = (-1)/(tau_syn_ex)**(2)*g_ex+(-2)/tau_syn_ex*g_ex' + shape g_ex' = g_ex' function I_syn_exc pA = cond_sum(g_ex, spikeExc) * ( V_m - E_ex ) function I_syn_inh pA = cond_sum(g_in, spikeInh) * ( V_m - E_in ) diff --git a/src/main/grammars/org/nest/NESTML.mc4 b/src/main/grammars/org/nest/NESTML.mc4 index 6ee220462..d96159b05 100644 --- a/src/main/grammars/org/nest/NESTML.mc4 +++ b/src/main/grammars/org/nest/NESTML.mc4 @@ -11,14 +11,17 @@ package org.nest; */ grammar NESTML extends org.nest.Literals { - /** - Artifact entry-point - */ + /** ASTNESTMLCompilationUnit represents the complete entire file with neuron and component models. + @attribute packageName The qualified name to artifact + @attribute Import List of imported elements + @attribute Neuron The neuron representation + */ NESTMLCompilationUnit = (Neuron | NEWLINE)* EOF; BLOCK_OPEN = ":"; BLOCK_CLOSE = "end"; + /********************************************************************************************************************* * Units-Language *********************************************************************************************************************/ @@ -89,11 +92,6 @@ grammar NESTML extends org.nest.Literals { */ FunctionCall = calleeName:Name "(" args:(Expr& || ",")* ")"; - /** ASTNESTMLCompilationUnit represents the complete entire file with neuron and component models. - @attribute packageName The qualified name to artifact - @attribute Import List of imported elements - @attribute Neuron The neuron representation - */ /********************************************************************************************************************* * Equations-Language @@ -104,16 +102,15 @@ grammar NESTML extends org.nest.Literals { @attribute lhs Left hand side, e.g. a Variable. @attribute rhs Expression defining the right hand side. */ - Equation = lhs:Derivative "=" rhs:Expr (";")?; + Equation = lhs:Derivative "=" rhs:Expr (";")?; Derivative = name:Name (differentialOrder:"\'")*; - Shape = "shape" lhs:Variable "=" rhs:Expr (";")?; + Shape = "shape" lhs:Derivative "=" rhs:Expr (";")?; /********************************************************************************************************************* * Procedural-Language *********************************************************************************************************************/ - Block = ( Stmt | NEWLINE )*; Stmt = Small_Stmt | Compound_Stmt; @@ -185,7 +182,14 @@ grammar NESTML extends org.nest.Literals { */ Neuron = "neuron" Name BLOCK_OPEN - (NEWLINE | BlockWithVariables | UpdateBlock | EquationsBlock | InputBlock | OutputBlock | Function)* + ( NEWLINE | + BlockWithVariables | + UpdateBlock | + InitialValuesBlock | + EquationsBlock | + InputBlock | + OutputBlock | + Function)* BLOCK_CLOSE; /** ASTBlockWithVariables represent a block with variables, e.g.: @@ -218,6 +222,20 @@ grammar NESTML extends org.nest.Literals { Block BLOCK_CLOSE; + /** ASTInitialValues a special function definition: + initial_values: + g_in nS = 0nS + g_ex nS = 0nS + g_ex' nS/ms = nS * e / tau_syn_ex + g_in' nS/ms = nS * e / tau_syn_in + end + */ + InitialValuesBlock = + "initial_values" + BLOCK_OPEN + (Declaration | NEWLINE)* + BLOCK_CLOSE; + /** ASTEquations a special function definition: equations: G = (e/tau_syn) * t * exp(-1/tau_syn*t) @@ -228,7 +246,7 @@ grammar NESTML extends org.nest.Literals { EquationsBlock = "equations" BLOCK_OPEN - (Equation | Shape | OdeFunction | NEWLINE)+ + (Equation | Shape | OdeFunction | NEWLINE)* BLOCK_CLOSE; /** ASTInput represents the input block: @@ -281,16 +299,11 @@ grammar NESTML extends org.nest.Literals { @attribute primitiveType Primitive return type, e.g. int @attribute block Implementation of the function. */ - Function = "function" Name "(" Parameters? ")" (returnType:Datatype)? + Function = "function" Name "(" (Parameter ("," Parameter)*)? ")" (returnType:Datatype)? BLOCK_OPEN Block BLOCK_CLOSE; - /** ASTParameters models parameter list in function declaration. - @attribute parameters List with parameters. - */ - Parameters = Parameter ("," Parameter)*; - /** ASTParameter represents singe: output: spike @attribute compartments Lists with compartments. diff --git a/src/main/java/org/nest/codegeneration/helpers/NESTFunctionPrinter.java b/src/main/java/org/nest/codegeneration/helpers/NESTFunctionPrinter.java index 92bb5f1d6..ecd62695b 100644 --- a/src/main/java/org/nest/codegeneration/helpers/NESTFunctionPrinter.java +++ b/src/main/java/org/nest/codegeneration/helpers/NESTFunctionPrinter.java @@ -37,17 +37,15 @@ public String printFunctionDeclaration(final ASTFunction astFunction) { // TODO names and concept is misleading List parameterNestmlTypes = Lists.newArrayList(); List parameterNestTypes = Lists.newArrayList(); - if (astFunction.getParameters().isPresent()) { - for (int i = 0; i < astFunction.getParameters().get().getParameters().size(); ++i) { - String parameterTypeFqn = AstUtils.computeTypeName(astFunction.getParameters().get().getParameters().get(i).getDatatype()); + for (int i = 0; i < astFunction.getParameters().size(); ++i) { + String parameterTypeFqn = AstUtils.computeTypeName(astFunction.getParameters().get(i).getDatatype()); - Optional parameterType = scope.resolve(parameterTypeFqn, TypeSymbol.KIND); - checkState(parameterType.isPresent(), - "Cannot resolve the parameter type: " + parameterTypeFqn + ". In function: " + astFunction - .getName()); - parameterNestmlTypes.add(parameterTypeFqn); - parameterNestTypes.add(new NESTML2NESTTypeConverter().convert(parameterType.get())); - } + Optional parameterType = scope.resolve(parameterTypeFqn, TypeSymbol.KIND); + checkState(parameterType.isPresent(), + "Cannot resolve the parameter type: " + parameterTypeFqn + ". In function: " + astFunction + .getName()); + parameterNestmlTypes.add(parameterTypeFqn); + parameterNestTypes.add(new NESTML2NESTTypeConverter().convert(parameterType.get())); } final Optional method = NestmlSymbols.resolveMethod( @@ -79,17 +77,15 @@ public String printFunctionDefinition(final ASTFunction astFunction, final Strin // TODO names and concept is misleading List parameterNestmlTypes = Lists.newArrayList(); List parameterNestTypes = Lists.newArrayList(); - if (astFunction.getParameters().isPresent()) { - for (int i = 0; i < astFunction.getParameters().get().getParameters().size(); ++i) { - final ASTParameter functionParameter = astFunction.getParameters().get().getParameters().get(i); - String parameterTypeFqn = AstUtils.computeTypeName(functionParameter.getDatatype()); - Optional parameterType = scope.resolve(parameterTypeFqn, TypeSymbol.KIND); - checkState(parameterType.isPresent(), - "Cannot resolve the parameter type: " + parameterTypeFqn + ". In function: " + astFunction - .getName()); - parameterNestmlTypes.add(parameterTypeFqn); - parameterNestTypes.add(new NESTML2NESTTypeConverter().convert(parameterType.get()) + " " + functionParameter.getName()); // TODO misleading name - } + for (int i = 0; i < astFunction.getParameters().size(); ++i) { + final ASTParameter functionParameter = astFunction.getParameters().get(i); + String parameterTypeFqn = AstUtils.computeTypeName(functionParameter.getDatatype()); + Optional parameterType = scope.resolve(parameterTypeFqn, TypeSymbol.KIND); + checkState(parameterType.isPresent(), + "Cannot resolve the parameter type: " + parameterTypeFqn + ". In function: " + astFunction + .getName()); + parameterNestmlTypes.add(parameterTypeFqn); + parameterNestTypes.add(new NESTML2NESTTypeConverter().convert(parameterType.get()) + " " + functionParameter.getName()); // TODO misleading name } final Optional method = NestmlSymbols.resolveMethod( diff --git a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java index c5f9e8466..e2e8ba400 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java +++ b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java @@ -38,12 +38,13 @@ public ASTNeuron( final List nEWLINEs, final List blockWithVariabless, final List updateBlocks, + final List astInitialValuesBlocks, final List equationss, final List inputs, final List outputs, final List functions, final ASTBLOCK_CLOSE bLOCK_close) { - super(name, bLOCK_open, nEWLINEs, blockWithVariabless, updateBlocks, equationss, inputs, outputs, functions, bLOCK_close); + super(name, bLOCK_open, nEWLINEs, blockWithVariabless, updateBlocks, astInitialValuesBlocks, equationss, inputs, outputs, functions, bLOCK_close); } public Optional getUpdateBlock() { diff --git a/src/main/java/org/nest/nestml/_cocos/FunctionParameterHasTypeName.java b/src/main/java/org/nest/nestml/_cocos/FunctionParameterHasTypeName.java index f1bfd6a1f..b94ca8251 100644 --- a/src/main/java/org/nest/nestml/_cocos/FunctionParameterHasTypeName.java +++ b/src/main/java/org/nest/nestml/_cocos/FunctionParameterHasTypeName.java @@ -43,24 +43,22 @@ public class FunctionParameterHasTypeName implements NESTMLASTFunctionCoCo { public void check(final ASTFunction astDeclaration) { checkArgument(astDeclaration.getEnclosingScope().isPresent(), "Declaration hast no scope. Run symboltable creator."); final Scope scope = astDeclaration.getEnclosingScope().get(); - if (astDeclaration.getParameters().isPresent()) { - final List parameterNames = astDeclaration.getParameters().get().getParameters() - .stream() - .map(ASTParameter::getName) - .collect(Collectors.toList()); + final List parameterNames = astDeclaration.getParameters() + .stream() + .map(ASTParameter::getName) + .collect(Collectors.toList()); - for (String varName : parameterNames) { - // tries to resolve the variable name as type. if it is possible, then the variable name clashes with type name is reported as an error - final Optional res = scope.resolve(varName, TypeSymbol.KIND); - // could resolve type as variable, report an error - res.ifPresent(typeSymbol -> Log.error( - NestmlErrorStrings.message(this, varName), - astDeclaration.get_SourcePositionEnd())); - - } + for (String varName : parameterNames) { + // tries to resolve the variable name as type. if it is possible, then the variable name clashes with type name is reported as an error + final Optional res = scope.resolve(varName, TypeSymbol.KIND); + // could resolve type as variable, report an error + res.ifPresent(typeSymbol -> Log.error( + NestmlErrorStrings.message(this, varName), + astDeclaration.get_SourcePositionEnd())); } + } } diff --git a/src/main/java/org/nest/nestml/_cocos/InvalidTypesInDeclaration.java b/src/main/java/org/nest/nestml/_cocos/InvalidTypesInDeclaration.java index 16a3a9bf2..ce5d5ff78 100644 --- a/src/main/java/org/nest/nestml/_cocos/InvalidTypesInDeclaration.java +++ b/src/main/java/org/nest/nestml/_cocos/InvalidTypesInDeclaration.java @@ -40,33 +40,31 @@ public void check(final ASTDeclaration astDeclaration) { public void check(final ASTFunction astFunction) { String typeName; // check parameter types - if (astFunction.getParameters().isPresent()) { - for (ASTParameter par : astFunction.getParameters().get().getParameters()) { - typeName = computeTypeName(par.getDatatype()); + for (ASTParameter par : astFunction.getParameters()) { + typeName = computeTypeName(par.getDatatype()); - Optional enclosingScope = astFunction.getEnclosingScope(); - Preconditions.checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node: " + astFunction); - Optional type = enclosingScope.get().resolve(typeName, TypeSymbol.KIND); + Optional enclosingScope = astFunction.getEnclosingScope(); + Preconditions.checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node: " + astFunction); + Optional type = enclosingScope.get().resolve(typeName, TypeSymbol.KIND); - checkIfValidType(astFunction, typeName, type); + checkIfValidType(astFunction, typeName, type); - } + } - // check return type - if (astFunction.getReturnType().isPresent()) { - typeName = computeTypeName(astFunction.getReturnType().get()); + // check return type + if (astFunction.getReturnType().isPresent()) { + typeName = computeTypeName(astFunction.getReturnType().get()); - final Optional enclosingScope = astFunction.getEnclosingScope(); - Preconditions.checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node: " + astFunction); - final Optional type = enclosingScope.get().resolve(typeName, TypeSymbol.KIND); - checkIfValidType(astFunction, typeName, type); + final Optional enclosingScope = astFunction.getEnclosingScope(); + Preconditions.checkState(enclosingScope.isPresent(), "There is no scope assigned to the AST node: " + astFunction); + final Optional type = enclosingScope.get().resolve(typeName, TypeSymbol.KIND); + checkIfValidType(astFunction, typeName, type); - //doCheck(type.get(), fun.getReturnType().get(), true); - } + //doCheck(type.get(), fun.getReturnType().get(), true); } - } + private void checkIfValidType(ASTNode astNode, String typeName, Optional type) { if (!type.isPresent() || type.isPresent() && type.get().getName().endsWith("Logger")) { NestmlErrorStrings errorStrings = NestmlErrorStrings.getInstance(); diff --git a/src/main/java/org/nest/nestml/_cocos/MemberVariableDefinedMultipleTimes.java b/src/main/java/org/nest/nestml/_cocos/MemberVariableDefinedMultipleTimes.java index 7d4786c1e..2cc9b7288 100644 --- a/src/main/java/org/nest/nestml/_cocos/MemberVariableDefinedMultipleTimes.java +++ b/src/main/java/org/nest/nestml/_cocos/MemberVariableDefinedMultipleTimes.java @@ -39,7 +39,7 @@ public void check(ASTNeuron body) { body.getInternalDeclarations().forEach(declaration -> addNames(varNames, declaration)); body.getODEAliases().forEach(odeAlias -> addName(varNames, odeAlias.getName(), odeAlias.getAstNode().get())); body.getInputLines().forEach(inputLine -> addVariable(inputLine.getName(), varNames, inputLine) ); - body.getShapes().forEach(astShape -> addVariable(AstUtils.getNameOfLHS(astShape), varNames, astShape)); + body.getShapes().forEach(astShape -> addVariable(AstUtils.getNameOfDerivedVariable(astShape), varNames, astShape)); } private void addNames(final Map names, final ASTDeclaration decl) { diff --git a/src/main/java/org/nest/nestml/_cocos/RestrictUseOfShapes.java b/src/main/java/org/nest/nestml/_cocos/RestrictUseOfShapes.java index 322f572f9..5233a0d8f 100644 --- a/src/main/java/org/nest/nestml/_cocos/RestrictUseOfShapes.java +++ b/src/main/java/org/nest/nestml/_cocos/RestrictUseOfShapes.java @@ -30,8 +30,9 @@ List collectShapes(ASTNeuron node){ return shapeNames; } - @Override public void visit(ASTShape node) { - ASTVariable shapeVar = node.getLhs(); + @Override + public void visit(ASTShape node) { + ASTDerivative shapeVar = node.getLhs(); shapeNames.add(shapeVar.getName().toString()); } } diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java index 5cc9a798a..788ff8ebe 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java @@ -18,6 +18,7 @@ import org.nest.nestml._symboltable.symbols.VariableSymbol; import org.nest.nestml._visitor.NESTMLVisitor; import org.nest.nestml._visitor.UnitsSIVisitor; +import org.nest.utils.AstUtils; import java.util.Collection; import java.util.List; @@ -33,6 +34,7 @@ import static org.nest.nestml._symboltable.symbols.NeuronSymbol.Type.NEURON; import static org.nest.nestml._symboltable.symbols.VariableSymbol.BlockType.STATE; import static org.nest.utils.AstUtils.computeTypeName; +import static org.nest.utils.AstUtils.getNameOfDerivedVariable; /** * Creates NESTML symbols. @@ -297,26 +299,24 @@ public void visit(final ASTFunction funcAst) { addToScopeAndLinkWithNode(methodSymbol, funcAst); // Parameters - if (funcAst.getParameters().isPresent()) { - for (ASTParameter p : funcAst.getParameters().get().getParameters()) { - String typeName = computeTypeName(p.getDatatype()); - Optional type = PredefinedTypes.getTypeIfExists(typeName); - - checkState(type.isPresent()); + for (ASTParameter p : funcAst.getParameters()) { + String typeName = computeTypeName(p.getDatatype()); + Optional type = PredefinedTypes.getTypeIfExists(typeName); - methodSymbol.addParameterType(type.get()); + checkState(type.isPresent()); - // add a var entry for method body - VariableSymbol var = new VariableSymbol(p.getName()); - var.setAstNode(p); - var.setType(type.get()); + methodSymbol.addParameterType(type.get()); - var.setBlockType(VariableSymbol.BlockType.LOCAL); - addToScopeAndLinkWithNode(var, p); + // add a var entry for method body + VariableSymbol var = new VariableSymbol(p.getName()); + var.setAstNode(p); + var.setType(type.get()); - } + var.setBlockType(VariableSymbol.BlockType.LOCAL); + addToScopeAndLinkWithNode(var, p); } + // return type if (funcAst.getReturnType().isPresent()) { final String returnTypeName = computeTypeName(funcAst.getReturnType().get()); @@ -464,11 +464,18 @@ private void addVariablesFromDeclaration( @Override public void visit(final ASTShape astShape) { final TypeSymbol type = PredefinedTypes.getType("real"); - final VariableSymbol var = new VariableSymbol(astShape.getLhs().toString()); + final String shapeVariableName; + if (astShape.getLhs().getDifferentialOrder().size() > 0) { + shapeVariableName = AstUtils.getNameOfDerivedVariable(astShape.getLhs()); + } + else { + shapeVariableName = astShape.getLhs().toString(); + } + final VariableSymbol var = new VariableSymbol(shapeVariableName); var.setAstNode(astShape); var.setType(type); - var.setRecordable(true); + var.setRecordable(false); var.setFunction(false); var.setDeclaringExpression(astShape.getRhs()); var.setBlockType(VariableSymbol.BlockType.SHAPE); diff --git a/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java b/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java index b9e277132..8ebdb06cf 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java +++ b/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java @@ -145,7 +145,7 @@ private void registerCocos() { nestmlCoCoChecker.addCoCo(neuronWithMultipleOrNoInput); final RestrictUseOfShapes restrictUseOfShapes = new RestrictUseOfShapes(); - nestmlCoCoChecker.addCoCo(restrictUseOfShapes); + // TODO nestmlCoCoChecker.addCoCo(restrictUseOfShapes); final FunctionReturnsIncorrectValue functionReturnsIncorrectValue = new FunctionReturnsIncorrectValue(); nestmlCoCoChecker.addCoCo(functionReturnsIncorrectValue); diff --git a/src/main/java/org/nest/nestml/_symboltable/NestmlSymbols.java b/src/main/java/org/nest/nestml/_symboltable/NestmlSymbols.java index 658297711..16f7313aa 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NestmlSymbols.java +++ b/src/main/java/org/nest/nestml/_symboltable/NestmlSymbols.java @@ -57,15 +57,10 @@ public static Optional resolveMethod(final ASTFunction astFunction checkArgument(astFunction.getEnclosingScope().isPresent(), "Run symbol table creator"); final List callTypes; - if (astFunction.getParameters().isPresent()) { - callTypes = astFunction.getParameters().get().getParameters() - .stream() - .map(astParameter -> AstUtils.computeTypeName(astParameter.getDatatype())) - .collect(toList()); - } - else { - callTypes = Lists.newArrayList(); - } + callTypes = astFunction.getParameters() + .stream() + .map(astParameter -> AstUtils.computeTypeName(astParameter.getDatatype())) + .collect(toList()); return resolveMethod(astFunction.getName(), callTypes, astFunction.getEnclosingScope().get()); } diff --git a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java index f929c5283..b429e538e 100644 --- a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java +++ b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java @@ -175,21 +175,18 @@ public void handle(final ASTFunction astFunction) { } - private void printParameters(final Optional functionParameters) { + private void printParameters(final List astParameters) { printer.print("("); - if (functionParameters.isPresent()) { - final List astParameters = functionParameters.get().getParameters(); - for (int curParameterIndex = 0; curParameterIndex < astParameters.size(); ++curParameterIndex) { - boolean isLastParameter = (curParameterIndex + 1) == astParameters.size(); - final ASTParameter curParameter = astParameters.get(curParameterIndex); - printer.print(curParameter.getName() + " " + deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(curParameter.getDatatype()))); - if (!isLastParameter) { - printer.print(", "); - } - + for (int curParameterIndex = 0; curParameterIndex < astParameters.size(); ++curParameterIndex) { + boolean isLastParameter = (curParameterIndex + 1) == astParameters.size(); + final ASTParameter curParameter = astParameters.get(curParameterIndex); + printer.print(curParameter.getName() + " " + deserializeUnitIfNotPrimitive(AstUtils.computeTypeName(curParameter.getDatatype()))); + if (!isLastParameter) { + printer.print(", "); } } + printer.print(")"); } diff --git a/src/main/java/org/nest/utils/AstUtils.java b/src/main/java/org/nest/utils/AstUtils.java index d0f8476e6..574ac9a2c 100644 --- a/src/main/java/org/nest/utils/AstUtils.java +++ b/src/main/java/org/nest/utils/AstUtils.java @@ -338,7 +338,7 @@ Optional getFunctionCall() { * If the variable is ues as a RHS of an equation, e.g. g_in'' = exp(t) then a variable g_in' should be added. * */ - public static String getNameOfLHS(final ASTDerivative astVariable) { + public static String getNameOfDerivedVariable(final ASTDerivative astVariable) { checkArgument(astVariable.getDifferentialOrder().size() > 0); return astVariable.getName() + Strings.repeat("'", astVariable.getDifferentialOrder().size() - 1); } @@ -347,7 +347,7 @@ public static String getNameOfLHS(final ASTDerivative astVariable) { * Returns the name of the shape, 'shape g_in = t' -> g_n * */ - public static String getNameOfLHS(ASTShape astShape) { + public static String getNameOfDerivedVariable(ASTShape astShape) { return astShape.getLhs().toString(); } diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index fcd03ec93..c82cf9e5e 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -127,7 +127,7 @@ public void testTutorialModels() { @Test public void manually() { final String[] args = new String[] { - "models/iaf_psc_alpha.nestml", + "models/iaf_cond_alpha.nestml", "--json_log", "model_issues", "--enable_tracing", "--target", outputPath.toString()}; From f1a39f328e27e5098b492b4f95dd693a89ec17a0 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Tue, 12 Sep 2017 14:16:15 +0200 Subject: [PATCH 05/17] Cleanup prettyprinter --- models/iaf_cond_alpha.nestml | 115 ++---------------- src/main/grammars/org/nest/NESTML.mc4 | 23 +--- .../codegeneration/NestCodeGenerator.java | 16 ++- .../converters/GslReferenceConverter.java | 2 +- .../NESTParameterBlockReferenceConverter.java | 49 -------- .../NESTStateBlockReferenceConverter.java | 41 ------- .../nest/codegeneration/helpers/GslNames.java | 2 +- .../helpers/VariableHelper.java | 4 +- .../sympy/EquationsBlockProcessor.java | 20 +-- .../codegeneration/sympy/SolverOutput.java | 2 +- .../codegeneration/sympy/SymPySolver.java | 2 +- .../frontend/CliConfigurationExecutor.java | 7 +- .../java/org/nest/nestml/_ast/ASTNeuron.java | 9 +- .../nestml/_cocos/BufferNotAssignable.java | 8 +- .../EquationsOnlyForStateVariables.java | 4 +- .../_cocos/FunctionParameterHasTypeName.java | 1 - .../nestml/_cocos/NestmlErrorStrings.java | 6 +- .../NESTMLSymbolTableCreator.java | 95 +++++---------- .../predefined/PredefinedVariables.java | 6 +- .../_symboltable/symbols/NeuronSymbol.java | 8 +- .../_symboltable/symbols/VariableSymbol.java | 68 ++++++----- .../prettyprinter/NESTMLPrettyPrinter.java | 3 + .../org/nest/nestml/neuron/NeuronClass.ftl | 4 +- .../NESTMLSymbolTableCreatorTest.java | 10 +- 24 files changed, 135 insertions(+), 370 deletions(-) delete mode 100644 src/main/java/org/nest/codegeneration/converters/NESTParameterBlockReferenceConverter.java delete mode 100644 src/main/java/org/nest/codegeneration/converters/NESTStateBlockReferenceConverter.java diff --git a/models/iaf_cond_alpha.nestml b/models/iaf_cond_alpha.nestml index 9f9238492..d834902ed 100644 --- a/models/iaf_cond_alpha.nestml +++ b/models/iaf_cond_alpha.nestml @@ -1,97 +1,3 @@ -/* -Name: iaf_cond_alpha_neuron - Simple conductance based leaky integrate-and-fire neuron - model. - -Description: -iaf_cond_alpha is an implementation of a spiking neuron using IAF dynamics with -conductance-based synapses. Incoming spike events induce a post-synaptic change -of conductance modelled by an alpha function. The alpha function -is normalised such that an event of weight 1.0 results in a peak current of 1 nS -at t = tau_syn. - -Sends: SpikeEvent - -Receives: SpikeEvent, CurrentEvent, DataLoggingRequest - -References: - -Meffin, H., Burkitt, A. N., & Grayden, D. B. (2004). An analytical -model for the large, fluctuating synaptic conductance state typical of -neocortical neurons in vivo. J. Comput. Neurosci., 16, 159-175. - -Bernander, O ., Douglas, R. J., Martin, K. A. C., & Koch, C. (1991). -Synaptic background activity influences spatiotemporal integration in -single pyramidal cells. Proc. Natl. Acad. Sci. USA, 88(24), -11569-11573. - -Kuhn, Aertsen, Rotter (2004) Neuronal Integration of Synaptic Input in -the Fluctuation- Driven Regime. Jneurosci 24(10) 2345-2356 - -Author: Schrader, Plesser - -SeeAlso: iaf_cond_exp, iaf_cond_alpha_mc -*/ -neuron iaf_cond_alpha_neuron: - - state: - V_m mV = E_L ## membrane potential - r integer ## counts number of tick during the refractory period - end - - equations: - shape g_in = (e/tau_syn_in) * t * exp(-t/tau_syn_in) - shape g_ex = (e/tau_syn_ex) * t * exp(-t/tau_syn_ex) - - function I_syn_exc pA = cond_sum(g_ex, spikeExc) * ( V_m - E_ex ) - function I_syn_inh pA = cond_sum(g_in, spikeInh) * ( V_m - E_in ) - function I_leak pA = g_L * ( V_m - E_L ) - - V_m' = ( -I_leak - I_syn_exc - I_syn_inh + currents + I_e ) / C_m - end - - parameters: - V_th mV = -55.0mV ## Threshold Potential in mV - V_reset mV = -60.0mV ## Reset Potential in mV - t_ref ms = 2.ms ## Refractory period in ms - g_L nS = 16.6667nS ## Leak Conductance in nS - C_m pF = 250.0 pF ## Membrane Capacitance in pF - E_ex mV = 0mV ## Excitatory reversal Potential in mV - E_in mV = -85.0mV ## Inhibitory reversal Potential in mV - E_L mV = -70.0mV ## Leak reversal Potential (aka resting potential) in mV - tau_syn_ex ms = 0.2ms ## Synaptic Time Constant Excitatory Synapse in ms - tau_syn_in ms = 2.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - I_e pA = 0pA ## Constant Current in pA - ## Input current injected by CurrentEvent. - ## This variable is used to transport the current applied into the - ## _dynamics function computing the derivative of the state vector. - end - - internals: - RefractoryCounts integer = steps(t_ref) # refractory time in steps - end - - input: - spikeInh <- inhibitory spike - spikeExc <- excitatory spike - currents <- current - end - - output: spike - - update: - integrate_odes() - if r != 0: # neuron is absolute refractory - r = r - 1 - V_m = V_reset # clamp potential - elif V_m >= V_th: # neuron is not absolute refractory - r = RefractoryCounts - V_m = V_reset # clamp potential - emit_spike() - end - end - -end - /* Name: iaf_cond_alpha_implicit - Simple conductance based leaky integrate-and-fire neuron model. @@ -128,14 +34,21 @@ SeeAlso: iaf_cond_exp, iaf_cond_alpha_mc neuron iaf_cond_alpha_implicit: state: - V_m mV = E_L ## membrane potential - r integer ## refractory counter end + initial_values: + V_m mV = E_L ## membrane potential + g_in nS = 0nS + g_in' nS/ms = nS * e / tau_syn_in + g_ex nS = 0nS + g_ex' nS/ms = nS * e / tau_syn_ex + end + equations: shape g_in'' = (-1)/(tau_syn_in)**(2)*g_in+(-2)/tau_syn_in*g_in' shape g_in' = g_in' + shape g_ex'' = (-1)/(tau_syn_ex)**(2)*g_ex+(-2)/tau_syn_ex*g_ex' shape g_ex' = g_ex' @@ -161,13 +74,6 @@ neuron iaf_cond_alpha_implicit: end internals: - ## Impulse to add to DG_EXC on spike arrival to evoke unit-amplitude - ## conductance excursion. - PSConInit_E nS/ms = nS * e / tau_syn_ex - - ## Impulse to add to DG_INH on spike arrival to evoke unit-amplitude - ## conductance excursion. - PSConInit_I nS/ms = nS * e / tau_syn_in RefractoryCounts integer = steps(t_ref) ## refractory time in steps end @@ -191,9 +97,6 @@ neuron iaf_cond_alpha_implicit: emit_spike() end - # add incoming spikes - g_ex' += spikeExc * PSConInit_E - g_in' += spikeInh * PSConInit_I end end diff --git a/src/main/grammars/org/nest/NESTML.mc4 b/src/main/grammars/org/nest/NESTML.mc4 index d96159b05..d2740aa8b 100644 --- a/src/main/grammars/org/nest/NESTML.mc4 +++ b/src/main/grammars/org/nest/NESTML.mc4 @@ -185,7 +185,6 @@ grammar NESTML extends org.nest.Literals { ( NEWLINE | BlockWithVariables | UpdateBlock | - InitialValuesBlock | EquationsBlock | InputBlock | OutputBlock | @@ -203,7 +202,7 @@ grammar NESTML extends org.nest.Literals { @attribute AliasDecl a list with variable declarations. */ BlockWithVariables = - (["state"]|["parameters"]|["internals"]) + (["state"] | ["parameters"] | ["internals"] | ["initial_values"]) BLOCK_OPEN (Declaration | NEWLINE)* BLOCK_CLOSE; @@ -222,20 +221,6 @@ grammar NESTML extends org.nest.Literals { Block BLOCK_CLOSE; - /** ASTInitialValues a special function definition: - initial_values: - g_in nS = 0nS - g_ex nS = 0nS - g_ex' nS/ms = nS * e / tau_syn_ex - g_in' nS/ms = nS * e / tau_syn_in - end - */ - InitialValuesBlock = - "initial_values" - BLOCK_OPEN - (Declaration | NEWLINE)* - BLOCK_CLOSE; - /** ASTEquations a special function definition: equations: G = (e/tau_syn) * t * exp(-1/tau_syn*t) @@ -270,11 +255,7 @@ grammar NESTML extends org.nest.Literals { @attribute spike true iff the neuron is a spike. @attribute current true iff. the neuron is a current. */ - InputLine = - Name - ("[" sizeParameter:Name "]")? - "<-" InputType* - (["spike"] | ["current"]); + InputLine = Name ("[" sizeParameter:Name "]")? "<-" InputType* (["spike"] | ["current"]); /** ASTInputType represents the type of the inputline e.g.: inhibitory or excitatory: @attribute inhibitory true iff the neuron is a inhibitory. diff --git a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java index 357e8fa8f..46925ec61 100644 --- a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java +++ b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java @@ -15,6 +15,7 @@ import org.nest.nestml._ast.ASTNeuron; import org.nest.nestml._ast.ASTNESTMLCompilationUnit; import org.nest.nestml._ast.ASTEquationsBlock; +import org.nest.nestml._ast.ASTShape; import org.nest.nestml._symboltable.NESTMLLanguage; import org.nest.nestml._symboltable.NestmlSymbols; import org.nest.nestml.prettyprinter.ExpressionsPrettyPrinter; @@ -72,7 +73,7 @@ private void analyseAndGenerate( generateNestCode(workingVersion, outputBase); - final String msg = "Successfully generated NEST code for: '" + astNeuron.getName() + "' in: '" + final String msg = "Successfully generated NEST code for the neuron: '" + astNeuron.getName() + "' in: '" + outputBase.toAbsolutePath().toString() + "'"; reporter.reportProgress(msg); } @@ -185,7 +186,7 @@ public void generateNESTModuleCode( initSLI, neurons.get(0)); // an arbitrary AST to match the signature - reporter.reportProgress("Successfully generated NEST module code in " + outputDirectory); + reporter.reportProgress("Successfully generated NEST module code in " + outputDirectory.toAbsolutePath()); } private GlobalExtensionManagement getGlexConfiguration() { @@ -193,19 +194,13 @@ private GlobalExtensionManagement getGlexConfiguration() { final NESTReferenceConverter converter = new NESTReferenceConverter(); final ExpressionsPrettyPrinter expressionsPrinter = new LegacyExpressionPrinter(converter); - final IReferenceConverter parameterBlockConverter = new NESTParameterBlockReferenceConverter(); - final ExpressionsPrettyPrinter parameterBlockPrinter = new LegacyExpressionPrinter(parameterBlockConverter); - final IReferenceConverter stateBlockReferenceConverter = new NESTStateBlockReferenceConverter(); - final ExpressionsPrettyPrinter stateBlockPrettyPrinter = new LegacyExpressionPrinter(stateBlockReferenceConverter); glex.setGlobalValue("expressionsPrinter", expressionsPrinter); glex.setGlobalValue("functionCallConverter", converter); glex.setGlobalValue("idemPrinter", new LegacyExpressionPrinter()); // this printer is used in one of the variable blocks. there, S_, V_, B_ structs are not defined and getters // setters must be used instead. - glex.setGlobalValue("printerWithGetters", parameterBlockPrinter); - glex.setGlobalValue("stateBlockPrettyPrinter", stateBlockPrettyPrinter); return glex; } @@ -249,7 +244,7 @@ private void defineSolverType(final GlobalExtensionManagement glex, final ASTNeu glex.setGlobalValue("useGSL", false); if (neuron.findEquationsBlock().isPresent()) { - if (neuron.findEquationsBlock().get().getShapes().size() == 0 || + if (!functionShapeExists(neuron.findEquationsBlock().get().getShapes()) || neuron.findEquationsBlock().get().getODEs().size() > 1) { glex.setGlobalValue("names", new GslNames()); glex.setGlobalValue("useGSL", true); @@ -263,4 +258,7 @@ private void defineSolverType(final GlobalExtensionManagement glex, final ASTNeu } + private boolean functionShapeExists(final List shapes) { + return shapes.stream().anyMatch(shape -> shape.getLhs().getDifferentialOrder().size() == 0); + } } diff --git a/src/main/java/org/nest/codegeneration/converters/GslReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/GslReferenceConverter.java index f5fd9e243..5b9d37502 100644 --- a/src/main/java/org/nest/codegeneration/converters/GslReferenceConverter.java +++ b/src/main/java/org/nest/codegeneration/converters/GslReferenceConverter.java @@ -111,7 +111,7 @@ public String convertNameReference(final ASTVariable astVariable) { return siUnitAsLiteral.get(); } - if (variableSymbol.definedByODE()) { + if (variableSymbol.isInInitialValues()) { return GslNames.name(variableSymbol); } else if (variableSymbol.isBuffer()) { diff --git a/src/main/java/org/nest/codegeneration/converters/NESTParameterBlockReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/NESTParameterBlockReferenceConverter.java deleted file mode 100644 index a9d032cc0..000000000 --- a/src/main/java/org/nest/codegeneration/converters/NESTParameterBlockReferenceConverter.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2015 RWTH Aachen. All rights reserved. - * - * http://www.se-rwth.de/ - */ -package org.nest.codegeneration.converters; - -import de.monticore.symboltable.Scope; -import org.nest.nestml._ast.ASTVariable; -import org.nest.nestml._symboltable.predefined.PredefinedVariables; -import org.nest.nestml._symboltable.symbols.VariableSymbol; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.nest.nestml._symboltable.symbols.VariableSymbol.resolve; -import static org.nest.utils.AstUtils.convertSiName; - -import java.util.Optional; - -/** - * Converts constants, names and functions the NEST equivalents. - * - * @author plotnikov - */ -public class NESTParameterBlockReferenceConverter extends NESTReferenceConverter { - - - @Override - public String convertNameReference(final ASTVariable astVariable) { - checkArgument(astVariable.getEnclosingScope().isPresent(), "Run symboltable creator"); - final String variableName = astVariable.toString(); - final Scope scope = astVariable.getEnclosingScope().get(); - - Optional siUnitAsLiteral = convertSiName(astVariable.toString()); - if(siUnitAsLiteral.isPresent()){ - return siUnitAsLiteral.get(); - } - - if (PredefinedVariables.E_CONSTANT.equals(variableName)) { - return "numerics::e"; - } - else { - final VariableSymbol variableSymbol = resolve(variableName, scope); - - return "get_" + variableName + "()" + (variableSymbol.isVector()?"[i]":"") ; - } - - } - -} diff --git a/src/main/java/org/nest/codegeneration/converters/NESTStateBlockReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/NESTStateBlockReferenceConverter.java deleted file mode 100644 index f8b728a65..000000000 --- a/src/main/java/org/nest/codegeneration/converters/NESTStateBlockReferenceConverter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2015 RWTH Aachen. All rights reserved. - * - * http://www.se-rwth.de/ - */ -package org.nest.codegeneration.converters; - -import de.monticore.symboltable.Scope; -import org.nest.codegeneration.helpers.Names; -import org.nest.nestml._ast.ASTVariable; -import org.nest.nestml._symboltable.symbols.VariableSymbol; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.nest.nestml._symboltable.symbols.VariableSymbol.resolve; -import static org.nest.utils.AstUtils.convertSiName; - -import java.util.Optional; - -/** - * Converts constants, names and functions the NEST equivalents. - * - * @author plotnikov - */ -public class NESTStateBlockReferenceConverter extends NESTReferenceConverter { - - @Override - public String convertNameReference(final ASTVariable astVariable) { - checkArgument(astVariable.getEnclosingScope().isPresent(), "Run symboltable creator"); - final String variableName = astVariable.toString(); - final Scope scope = astVariable.getEnclosingScope().get(); - final VariableSymbol variableSymbol = resolve(variableName, scope); - - Optional siUnitAsLiteral = convertSiName(astVariable.toString()); - if(siUnitAsLiteral.isPresent()){ - return siUnitAsLiteral.get(); - } - - return (variableSymbol.isParameter()?"__p.":"") + Names.getter(variableSymbol) + "()"; - } - -} diff --git a/src/main/java/org/nest/codegeneration/helpers/GslNames.java b/src/main/java/org/nest/codegeneration/helpers/GslNames.java index 65b8a6648..d3fd61ee1 100644 --- a/src/main/java/org/nest/codegeneration/helpers/GslNames.java +++ b/src/main/java/org/nest/codegeneration/helpers/GslNames.java @@ -14,7 +14,7 @@ public static String arrayIndex(final VariableSymbol variableSymbol) { } public static String name(final VariableSymbol variableSymbol) { - if (variableSymbol.definedByODE()) { + if (variableSymbol.isInInitialValues()) { return "y[State_::" + Names.convertToCPPName(variableSymbol.getName()) + "]"; } else { diff --git a/src/main/java/org/nest/codegeneration/helpers/VariableHelper.java b/src/main/java/org/nest/codegeneration/helpers/VariableHelper.java index e60ea50db..27004bdb4 100644 --- a/src/main/java/org/nest/codegeneration/helpers/VariableHelper.java +++ b/src/main/java/org/nest/codegeneration/helpers/VariableHelper.java @@ -10,13 +10,13 @@ public class VariableHelper { static public String printOrigin(final VariableSymbol variableSymbol) { switch (variableSymbol.getBlockType()) { case STATE: - case EQUATION: + case EQUATIONS: return "S_."; case PARAMETERS: return "P_."; case INTERNALS: return "V_."; - case INPUT_BUFFER_CURRENT: case INPUT_BUFFER_SPIKE: + case INPUT: return "B_."; default: return ""; diff --git a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java index 3d3020c41..08050e222 100644 --- a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java +++ b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java @@ -6,16 +6,13 @@ package org.nest.codegeneration.sympy; import org.nest.nestml._ast.ASTNeuron; -import org.nest.nestml._ast.ASTFunctionCall; +import org.nest.nestml._ast.ASTShape; import org.nest.reporting.Reporter; import java.nio.file.Path; -import java.util.Optional; +import java.util.List; -import static com.google.common.base.Preconditions.checkState; -import static org.nest.nestml._symboltable.predefined.PredefinedFunctions.DELTA; import static org.nest.utils.AstUtils.deepCloneNeuronAndBuildSymbolTable; -import static org.nest.utils.AstUtils.getFunctionCall; /** * Analyzes a neuron for defined ODE. If an ode is defined, it produces a temporary NESTML model @@ -44,6 +41,7 @@ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path output final ASTNeuron deepCopy = deepCloneNeuronAndBuildSymbolTable(astNeuron, outputBase); // this function is called only for neurons with an ode block. thus, retrieving it is safe. if (deepCopy.findEquationsBlock().get().getShapes().size() > 0 && + !odeShapeExists(deepCopy.findEquationsBlock().get().getShapes()) && deepCopy.findEquationsBlock().get().getODEs().size() == 1) { final SolverOutput solverOutput = evaluator.solveOdeWithShapes(deepCopy.findEquationsBlock().get(), outputBase); @@ -52,7 +50,8 @@ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path output if (!solverOutput.status.equals("success")) { reporter.reportProgress(astNeuron.getName() + - ": Equations or shapes could not be solved. The model remains unchanged."); + ": Equations or shapes could not be solved. The model remains unchanged.", + Reporter.Level.ERROR); return astNeuron; } @@ -64,15 +63,18 @@ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path output case "numeric": reporter.reportProgress("Shapes will be solved with GLS."); return shapesToOdesTransformer.transformShapesToOdeForm(astNeuron, solverOutput); + case "delta": return deltaSolutionTransformer.addExactSolution(solverOutput, astNeuron); + default: reporter.reportProgress(astNeuron.getName() + ": Equations or shapes could not be solved. The model remains unchanged."); return astNeuron; } } - else if (deepCopy.findEquationsBlock().get().getShapes().size() > 0) { + else if (deepCopy.findEquationsBlock().get().getShapes().size() > 0 && + !odeShapeExists(deepCopy.findEquationsBlock().get().getShapes())) { reporter.reportProgress("Shapes will be solved with GLS."); final SolverOutput solverOutput = evaluator.solveShapes(deepCopy.findEquationsBlock().get().getShapes(), outputBase); return shapesToOdesTransformer.transformShapesToOdeForm(astNeuron, solverOutput); @@ -84,4 +86,8 @@ else if (deepCopy.findEquationsBlock().get().getShapes().size() > 0) { return astNeuron; } + private boolean odeShapeExists(final List shapes) { + return shapes.stream().anyMatch(shape -> shape.getLhs().getDifferentialOrder().size() > 0); + } + } diff --git a/src/main/java/org/nest/codegeneration/sympy/SolverOutput.java b/src/main/java/org/nest/codegeneration/sympy/SolverOutput.java index 504d1dc66..334ff2ee2 100644 --- a/src/main/java/org/nest/codegeneration/sympy/SolverOutput.java +++ b/src/main/java/org/nest/codegeneration/sympy/SolverOutput.java @@ -63,7 +63,7 @@ static SolverOutput fromJSON(final Path solverResult) { return fromJSON(Joiner.on("\n").join(tmp)); } catch (IOException e) { - throw new RuntimeException("Cannot read the solver's evaluation result", e); + return ERROR_RESULT; } } diff --git a/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java b/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java index 4d3e618c9..cf835ba57 100644 --- a/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java +++ b/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java @@ -81,7 +81,7 @@ private SolverOutput executeSolver(final SolverInput solverInput, final Path out getStreamAsListOfStrings(res.getErrorStream()).forEach(reporter::reportProgress); long elapsedTime = end - start; - final String msg = "Successfully evaluated the SymPy script. Elapsed time: " + final String msg = "SymPy script was evaluated. Elapsed time: " + (double)elapsedTime / 1000000000.0 + " [s]"; reporter.reportProgress(msg); diff --git a/src/main/java/org/nest/frontend/CliConfigurationExecutor.java b/src/main/java/org/nest/frontend/CliConfigurationExecutor.java index 114d82119..a0be60fb4 100644 --- a/src/main/java/org/nest/frontend/CliConfigurationExecutor.java +++ b/src/main/java/org/nest/frontend/CliConfigurationExecutor.java @@ -53,10 +53,10 @@ void execute(final NestCodeGenerator generator, final CliConfiguration config) { final List modelFilenames = collectNESTMLModelFilenames(config.getInputPath()); final List modelRoots = parseModels(modelFilenames, parser); + reporter.reportProgress("Finished parsing nestml mdoels..."); + if (!modelRoots.isEmpty()) { final NESTMLScopeCreator scopeCreator = new NESTMLScopeCreator(); - reporter.reportProgress("Finished parsing nestml mdoels..."); - reporter.reportProgress("Remove temporary files..."); if (!Files.exists(config.getTargetPath())) { try { Files.createDirectories(config.getTargetPath()); @@ -65,6 +65,7 @@ void execute(final NestCodeGenerator generator, final CliConfiguration config) { Log.error("Cannot create the output foder: " + config.getTargetPath().toString(), e); } } + cleanUpWorkingFolder(config.getTargetPath()); processNestmlModels(modelRoots, config, scopeCreator, generator); @@ -145,7 +146,7 @@ private void reportParserError(Path modelFile, Optional parserError) { } private void cleanUpWorkingFolder(final Path targetPath) { - FilesHelper.deleteFilesInFolder(targetPath, file -> file.endsWith(".tmp") || file.endsWith(".nestml")); + FilesHelper.deleteFilesInFolder(targetPath, file -> file.toString().endsWith(".tmp")); } private void processNestmlModels( diff --git a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java index e2e8ba400..b395a8100 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java +++ b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java @@ -38,13 +38,12 @@ public ASTNeuron( final List nEWLINEs, final List blockWithVariabless, final List updateBlocks, - final List astInitialValuesBlocks, final List equationss, final List inputs, final List outputs, final List functions, final ASTBLOCK_CLOSE bLOCK_close) { - super(name, bLOCK_open, nEWLINEs, blockWithVariabless, updateBlocks, astInitialValuesBlocks, equationss, inputs, outputs, functions, bLOCK_close); + super(name, bLOCK_open, nEWLINEs, blockWithVariabless, updateBlocks, equationss, inputs, outputs, functions, bLOCK_close); } public Optional getUpdateBlock() { @@ -136,7 +135,7 @@ public List getShapes() { public List variablesDefinedByODE() { return getStateSymbols() .stream() - .filter(VariableSymbol::definedByODE) + .filter(VariableSymbol::isInInitialValues) .collect(toList()); } @@ -166,7 +165,7 @@ public List getOdeDefinedSymbols() { .stream() .map(stateSymbol -> (VariableSymbol) stateSymbol) .filter(VariableSymbol::isState) - .filter(VariableSymbol::definedByODE) + .filter(VariableSymbol::isInInitialValues) .collect(toList()); } @@ -176,7 +175,7 @@ public List getStateSymbolsWithoutOde() { .stream() .map(stateSymbol -> (VariableSymbol) stateSymbol) .filter(VariableSymbol::isState) - .filter(variableSymbol -> !variableSymbol.definedByODE()) + .filter(variableSymbol -> !variableSymbol.isInInitialValues()) .collect(toList()); } diff --git a/src/main/java/org/nest/nestml/_cocos/BufferNotAssignable.java b/src/main/java/org/nest/nestml/_cocos/BufferNotAssignable.java index 2e8c5cbee..ab4b43cd4 100644 --- a/src/main/java/org/nest/nestml/_cocos/BufferNotAssignable.java +++ b/src/main/java/org/nest/nestml/_cocos/BufferNotAssignable.java @@ -14,8 +14,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static de.se_rwth.commons.logging.Log.error; -import static org.nest.nestml._symboltable.symbols.VariableSymbol.BlockType.INPUT_BUFFER_CURRENT; -import static org.nest.nestml._symboltable.symbols.VariableSymbol.BlockType.INPUT_BUFFER_SPIKE; /** * Checks that buffers cannot be assigned a value. @@ -34,10 +32,8 @@ public void check(final ASTAssignment astAssignment) { if (!var.isPresent()) { Log.trace("Cannot resolve the variable: " + varName + " . Thereofore, the coco is skipped.", BufferNotAssignable.class.getSimpleName()); } - else if (var.get().getBlockType() == INPUT_BUFFER_CURRENT || - var.get().getBlockType() == INPUT_BUFFER_SPIKE) { - NestmlErrorStrings errorStrings = NestmlErrorStrings.getInstance(); - String msg = errorStrings.message(this,var.get().getName()); + else if (var.get().getBlockType() == VariableSymbol.BlockType.INPUT) { + String msg = NestmlErrorStrings.message(this,var.get().getName()); error(msg, astAssignment.get_SourcePositionStart()); diff --git a/src/main/java/org/nest/nestml/_cocos/EquationsOnlyForStateVariables.java b/src/main/java/org/nest/nestml/_cocos/EquationsOnlyForStateVariables.java index 5cad70b7e..c37716842 100644 --- a/src/main/java/org/nest/nestml/_cocos/EquationsOnlyForStateVariables.java +++ b/src/main/java/org/nest/nestml/_cocos/EquationsOnlyForStateVariables.java @@ -44,8 +44,8 @@ public void check(final ASTEquation astEq) { if (astEq.getLhs().getDifferentialOrder().size() > 0) { final Optional variableSymbol = scope.resolve(astEq.getLhs().getSimpleName(), VariableSymbol.KIND); if (variableSymbol.isPresent()) { - if (!variableSymbol.get().isState()) { - final String msg = NestmlErrorStrings.getErrorMsgAssignToNonState(this,variableSymbol.get().getName()); + if (!variableSymbol.get().isInInitialValues()) { + final String msg = NestmlErrorStrings.message(this,variableSymbol.get().getName()); Log.error(msg, astEq.get_SourcePositionStart()); } diff --git a/src/main/java/org/nest/nestml/_cocos/FunctionParameterHasTypeName.java b/src/main/java/org/nest/nestml/_cocos/FunctionParameterHasTypeName.java index b94ca8251..3b776c1a3 100644 --- a/src/main/java/org/nest/nestml/_cocos/FunctionParameterHasTypeName.java +++ b/src/main/java/org/nest/nestml/_cocos/FunctionParameterHasTypeName.java @@ -58,7 +58,6 @@ public void check(final ASTFunction astDeclaration) { } - } } diff --git a/src/main/java/org/nest/nestml/_cocos/NestmlErrorStrings.java b/src/main/java/org/nest/nestml/_cocos/NestmlErrorStrings.java index a295710eb..62975cfe2 100644 --- a/src/main/java/org/nest/nestml/_cocos/NestmlErrorStrings.java +++ b/src/main/java/org/nest/nestml/_cocos/NestmlErrorStrings.java @@ -143,11 +143,11 @@ static String code(final CurrentPortIsInhOrExc coco) { return "NESTML_CURRENT_PORT_IS_INH_OR_EXC"; } - static public String getErrorMsgAssignToNonState( + static public String message( final EquationsOnlyForStateVariables coco, final String variableName) { - final String ERROR_MSG_FORMAT = "The variable '" + variableName + "' is not a state" - + " variable and, therefore, cannot be used on the left side of an equation."; + final String ERROR_MSG_FORMAT = "The variable " + variableName + " must defined in the 'initial_values' block" + + " for being used on the left side of an ODE."; return code(coco) + SEPARATOR + ERROR_MSG_FORMAT; } diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java index 788ff8ebe..28c399bc2 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java @@ -18,7 +18,6 @@ import org.nest.nestml._symboltable.symbols.VariableSymbol; import org.nest.nestml._visitor.NESTMLVisitor; import org.nest.nestml._visitor.UnitsSIVisitor; -import org.nest.utils.AstUtils; import java.util.Collection; import java.util.List; @@ -32,9 +31,9 @@ import static java.util.Optional.of; import static org.nest.codegeneration.sympy.OdeTransformer.getCondSumFunctionCall; import static org.nest.nestml._symboltable.symbols.NeuronSymbol.Type.NEURON; -import static org.nest.nestml._symboltable.symbols.VariableSymbol.BlockType.STATE; +import static org.nest.nestml._symboltable.symbols.VariableSymbol.BlockType.*; +import static org.nest.nestml._symboltable.symbols.VariableSymbol.VariableType.*; import static org.nest.utils.AstUtils.computeTypeName; -import static org.nest.utils.AstUtils.getNameOfDerivedVariable; /** * Creates NESTML symbols. @@ -111,24 +110,16 @@ public void endVisit(final ASTNeuron astNeuron) { if (undefinedVariables.isEmpty()) { final List undefinedMethods = nestmlCoCosManager.checkThatMethodDefinedAtLeastOnce(astNeuron); + if (undefinedMethods.isEmpty()) { final List multipleDefinitions = nestmlCoCosManager.checkThatElementDefinedAtMostOnce(astNeuron); if (multipleDefinitions.isEmpty()) { if (astNeuron.findEquationsBlock().isPresent()) { - final List afterAddingDerivedVariables = nestmlCoCosManager.checkThatElementDefinedAtMostOnce(astNeuron); - - if (afterAddingDerivedVariables.isEmpty()) { assignOdeToVariables(astNeuron.findEquationsBlock().get()); markConductanceBasedBuffers(astNeuron.findEquationsBlock().get(), astNeuron.getInputLines()); - } - else { - final String msg = LOGGER_NAME + " : Cannot correctly build the symboltable, at least one variable is " + - "defined multiple times"; - Log.error(msg); - } - } + } else { final String msg = LOGGER_NAME + " : Cannot correctly build the symboltable, at least one variable is " + @@ -163,7 +154,7 @@ public void endVisit(final ASTNeuron astNeuron) { */ private void addFunctionVariables(final ASTEquationsBlock astOdeDeclaration) { for (final ASTOdeFunction astOdeAlias:astOdeDeclaration.getOdeFunctions()) { - final VariableSymbol var = new VariableSymbol(astOdeAlias.getVariableName()); + final VariableSymbol var = new VariableSymbol(astOdeAlias.getVariableName(), EQUATIONS, VARIABLE); var.setAstNode(astOdeAlias); final String typeName = computeTypeName(astOdeAlias.getDatatype()); Optional type = PredefinedTypes.getTypeIfExists(typeName); @@ -173,8 +164,6 @@ private void addFunctionVariables(final ASTEquationsBlock astOdeDeclaration) { var.setFunction(true); var.setDeclaringExpression(astOdeAlias.getExpr()); - var.setBlockType(VariableSymbol.BlockType.EQUATION); - addToScopeAndLinkWithNode(var, astOdeAlias); trace("Adds new variable '" + var.getFullName() + "'.", LOGGER_NAME); @@ -267,17 +256,10 @@ public void visit(final ASTInputLine inputLineAst) { checkState(this.currentScope().isPresent()); checkState(currentTypeSymbol.isPresent()); final TypeSymbol bufferType = PredefinedTypes.getBufferType(); - final VariableSymbol var = new VariableSymbol(inputLineAst.getName()); + final VariableSymbol var = new VariableSymbol(inputLineAst.getName(), INPUT, BUFFER); var.setType(bufferType); - if (inputLineAst.isCurrent()) { - var.setBlockType(VariableSymbol.BlockType.INPUT_BUFFER_CURRENT); - } - else { - var.setBlockType(VariableSymbol.BlockType.INPUT_BUFFER_SPIKE); - } - if (inputLineAst.getSizeParameter().isPresent()) { var.setVectorParameter(inputLineAst.getSizeParameter().get()); } @@ -308,11 +290,10 @@ public void visit(final ASTFunction funcAst) { methodSymbol.addParameterType(type.get()); // add a var entry for method body - VariableSymbol var = new VariableSymbol(p.getName()); + VariableSymbol var = new VariableSymbol(p.getName(), LOCAL, VARIABLE); var.setAstNode(p); var.setType(type.get()); - var.setBlockType(VariableSymbol.BlockType.LOCAL); addToScopeAndLinkWithNode(var, p); } @@ -388,24 +369,19 @@ public void visit(final ASTDeclaration astDeclaration) { if (this.varBlock.isPresent()) { if (varBlock.get().isState()) { - addVariablesFromDeclaration( - astDeclaration, - STATE); + addVariablesFromDeclaration(astDeclaration, STATE); } - else if (varBlock.get().isParameters ()) { - addVariablesFromDeclaration( - astDeclaration, - VariableSymbol.BlockType.PARAMETERS); + else if (varBlock.get().isParameters()) { + addVariablesFromDeclaration(astDeclaration, VariableSymbol.BlockType.PARAMETERS); } else if (varBlock.get().isInternals()) { - addVariablesFromDeclaration( - astDeclaration, - VariableSymbol.BlockType.INTERNALS); + addVariablesFromDeclaration(astDeclaration, VariableSymbol.BlockType.INTERNALS); + } + else if (varBlock.get().isInitial_values()) { + addVariablesFromDeclaration(astDeclaration, VariableSymbol.BlockType.INITIAL_VALUES); } else { - addVariablesFromDeclaration( - astDeclaration, - VariableSymbol.BlockType.LOCAL); + checkState(false, "This branch is by grammar construction unreachable."); } } @@ -422,19 +398,17 @@ else if (varBlock.get().isInternals()) { * Adds variables from a declaration. Distinguishes between the place of the declaration, e.g. * local, state, ... */ - private void addVariablesFromDeclaration( - final ASTDeclaration astDeclaration, - final VariableSymbol.BlockType blockType) { + private void addVariablesFromDeclaration(final ASTDeclaration astDeclaration, + final VariableSymbol.BlockType blockType) { for (final ASTVariable variable : astDeclaration.getVars()) { // multiple vars in one decl possible - final VariableSymbol var = new VariableSymbol(variable.toString()); + final VariableSymbol var = new VariableSymbol(variable.toString(), blockType, VARIABLE); var.setAstNode(astDeclaration); final String typeName = computeTypeName(astDeclaration.getDatatype()); var.setType(PredefinedTypes.getType(typeName)); boolean isRecordableVariable = blockType == STATE || astDeclaration.isRecordable(); - if (isRecordableVariable) { // otherwise is set to false. var.setRecordable(true); @@ -452,10 +426,9 @@ private void addVariablesFromDeclaration( var.setVectorParameter(astDeclaration.getSizeParameter().get()); } - var.setBlockType(blockType); addToScopeAndLinkWithNode(var, astDeclaration); - trace("Adds new variable '" + var.getFullName() + "'.", LOGGER_NAME); + trace("Adds new variable: " + var.getName(), LOGGER_NAME); } @@ -463,26 +436,22 @@ private void addVariablesFromDeclaration( @Override public void visit(final ASTShape astShape) { - final TypeSymbol type = PredefinedTypes.getType("real"); - final String shapeVariableName; - if (astShape.getLhs().getDifferentialOrder().size() > 0) { - shapeVariableName = AstUtils.getNameOfDerivedVariable(astShape.getLhs()); - } - else { - shapeVariableName = astShape.getLhs().toString(); - } - final VariableSymbol var = new VariableSymbol(shapeVariableName); + // in this case the shape is defined is a function. no initialvalues are necessary + if (astShape.getLhs().getDifferentialOrder().size() == 0) { + final TypeSymbol type = PredefinedTypes.getType("real"); + final VariableSymbol var = new VariableSymbol(astShape.getLhs().toString(), EQUATIONS, SHAPE); - var.setAstNode(astShape); - var.setType(type); - var.setRecordable(false); - var.setFunction(false); - var.setDeclaringExpression(astShape.getRhs()); - var.setBlockType(VariableSymbol.BlockType.SHAPE); + var.setAstNode(astShape); + var.setType(type); + var.setRecordable(false); + var.setFunction(false); + var.setDeclaringExpression(astShape.getRhs()); - addToScopeAndLinkWithNode(var, astShape); + addToScopeAndLinkWithNode(var, astShape); + + trace("Adds new shape variable '" + var.getFullName() + "'.", LOGGER_NAME); + } - trace("Adds new shape variable '" + var.getFullName() + "'.", LOGGER_NAME); } } diff --git a/src/main/java/org/nest/nestml/_symboltable/predefined/PredefinedVariables.java b/src/main/java/org/nest/nestml/_symboltable/predefined/PredefinedVariables.java index 73f17d897..135d863c7 100644 --- a/src/main/java/org/nest/nestml/_symboltable/predefined/PredefinedVariables.java +++ b/src/main/java/org/nest/nestml/_symboltable/predefined/PredefinedVariables.java @@ -36,11 +36,9 @@ public class PredefinedVariables { } } - private static void registerVariable( - final String variableName, final TypeSymbol type) { - final VariableSymbol variableSymbol = new VariableSymbol(variableName); + private static void registerVariable(final String variableName, final TypeSymbol type) { + final VariableSymbol variableSymbol = new VariableSymbol(variableName, VariableSymbol.BlockType.PREDEFINED, VariableSymbol.VariableType.VARIABLE); variableSymbol.setType(type); - variableSymbol.setPredefined(true); name2VariableSymbol.put(variableName, variableSymbol); } diff --git a/src/main/java/org/nest/nestml/_symboltable/symbols/NeuronSymbol.java b/src/main/java/org/nest/nestml/_symboltable/symbols/NeuronSymbol.java index 0cf90c503..3c50cc950 100644 --- a/src/main/java/org/nest/nestml/_symboltable/symbols/NeuronSymbol.java +++ b/src/main/java/org/nest/nestml/_symboltable/symbols/NeuronSymbol.java @@ -8,16 +8,12 @@ import de.monticore.ast.Comment; import de.monticore.symboltable.CommonScopeSpanningSymbol; import de.monticore.symboltable.SymbolKind; -import org.nest.nestml._symboltable.symbols.references.NeuronSymbolReference; import java.util.Collection; import java.util.List; import java.util.Optional; -import static com.google.common.base.Preconditions.checkNotNull; import static java.util.stream.Collectors.toList; -import static org.nest.nestml._symboltable.symbols.VariableSymbol.BlockType.INPUT_BUFFER_CURRENT; -import static org.nest.nestml._symboltable.symbols.VariableSymbol.BlockType.INPUT_BUFFER_SPIKE; /** * Represents the entire neuron or component, e.g. iaf_neuron. @@ -62,7 +58,7 @@ public List getCurrentBuffers() { final Collection variableSymbols = getSpannedScope().resolveLocally(VariableSymbol.KIND); return variableSymbols.stream() - .filter(variable -> variable.getBlockType().equals(INPUT_BUFFER_CURRENT)) + .filter(VariableSymbol::isCurrentBuffer) .collect(toList()); } @@ -70,7 +66,7 @@ public List getCurrentBuffers() { public List getSpikeBuffers() { final Collection variableSymbols = getSpannedScope().resolveLocally(VariableSymbol.KIND); return variableSymbols.stream() - .filter(variable -> variable.getBlockType().equals(INPUT_BUFFER_SPIKE)) + .filter(VariableSymbol::isSpikeBuffer) .collect(toList()); } diff --git a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java index c937eced4..731587964 100644 --- a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java +++ b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java @@ -10,9 +10,9 @@ import de.monticore.symboltable.SymbolKind; import org.nest.codegeneration.helpers.ASTBuffers; import org.nest.codegeneration.sympy.OdeTransformer; +import org.nest.nestml._ast.ASTDeclaration; import org.nest.nestml._ast.ASTExpr; import org.nest.nestml._ast.ASTInputLine; -import org.nest.nestml._ast.ASTDeclaration; import org.nest.utils.AstUtils; import java.util.Objects; @@ -30,20 +30,25 @@ */ public class VariableSymbol extends CommonSymbol { public static final VariableSymbolKind KIND = new VariableSymbolKind(); - private ASTExpr declaringExpression = null; + private final VariableType variableType; + private BlockType blockType; + private ASTExpr declaringExpression = null; private ASTExpr odeDeclaration = null; - private TypeSymbol type; - private boolean isPredefined; private boolean isFunction; private boolean isRecordable; - private BlockType blockType; private String arraySizeParameter = null; private boolean conductanceBased = false; + public VariableSymbol(final String name, final BlockType blockType, final VariableType variableType) { + super(name, KIND); + this.blockType = blockType; + this.variableType = variableType; + } + public boolean isBuffer() { - return blockType == BlockType.INPUT_BUFFER_CURRENT || blockType == BlockType.INPUT_BUFFER_SPIKE; + return blockType == BlockType.INPUT; } @SuppressWarnings({"unused"}) // used in templates @@ -52,6 +57,8 @@ public boolean isRecordable() { // generator. return isRecordable && !isVector(); } + + @SuppressWarnings({"unused"}) // used in templates public Optional getOdeDeclaration() { return Optional.ofNullable(odeDeclaration); } @@ -60,10 +67,6 @@ public void setOdeDeclaration(final ASTExpr odeDeclaration) { this.odeDeclaration = odeDeclaration; } - public boolean definedByODE() { - return odeDeclaration != null; - } - public void setRecordable(boolean loggable) { isRecordable = loggable; } @@ -74,13 +77,8 @@ public void setDeclaringExpression(final ASTExpr declaringExpression) { this.declaringExpression = declaringExpression; } - public VariableSymbol(String name) { - super(name, KIND); - setBlockType(BlockType.LOCAL); - } - + @SuppressWarnings({"unused"}) // used in templates. must be public. public Optional getDeclaringExpression() { - return Optional.ofNullable(declaringExpression); } @@ -140,7 +138,7 @@ public boolean isInhAndExc() { } public boolean isVector() { - if (blockType == BlockType.SHAPE) { + if (blockType == BlockType.EQUATIONS) { // declaring expression exists by construction from symbol table creator // there no shape without declaring expression @@ -153,15 +151,12 @@ public boolean isVector() { } public boolean isPredefined() { - return isPredefined; + return this.blockType == BlockType.PREDEFINED; } - public void setPredefined(boolean predefined) { - isPredefined = predefined; - } public Optional getVectorParameter() { - if (blockType != BlockType.SHAPE) { + if (blockType != BlockType.EQUATIONS) { return Optional.ofNullable(arraySizeParameter); } else { @@ -185,14 +180,19 @@ public boolean isState() { return blockType == BlockType.STATE; } + public boolean isInInitialValues() { + return blockType == BlockType.INITIAL_VALUES; + } + public boolean isInternal() { return blockType == BlockType.INTERNALS; } public boolean isInEquation() { - return blockType == BlockType.EQUATION; + return blockType == BlockType.EQUATIONS; } + @SuppressWarnings({"unused"}) // used in templates public boolean containsSumCall() { return declaringExpression != null && OdeTransformer.containsSumFunctionCall(declaringExpression); } @@ -213,10 +213,6 @@ public BlockType getBlockType() { return blockType; } - public void setBlockType(BlockType blockType) { - this.blockType = blockType; - } - @SuppressWarnings({"unused"}) // used in templates public boolean hasSetter() { checkState(getAstNode().isPresent(), "Symbol table must set the AST node."); @@ -238,12 +234,13 @@ public String printComment(final String prefix) { final StringBuffer output = new StringBuffer(); if(getAstNode().isPresent() && getAstNode().get() instanceof ASTDeclaration) { final ASTDeclaration astDeclaration = (ASTDeclaration) getAstNode().get(); - astDeclaration.getDocStrings().forEach(comment -> output.append(prefix + " " + comment)); + astDeclaration.getDocStrings().forEach(comment -> output.append(prefix).append(" ").append(comment)); } return output.toString(); } + @SuppressWarnings({"unused"}) // used in templates public Boolean hasComment() { if(getAstNode().isPresent() && getAstNode().get() instanceof ASTDeclaration) { final ASTDeclaration astDeclaration = (ASTDeclaration) getAstNode().get(); @@ -282,16 +279,23 @@ static private class VariableSymbolKind implements SymbolKind { } + public enum VariableType { + SHAPE, + VARIABLE, + BUFFER, + EQUATION + } + public enum BlockType { STATE, PARAMETERS, INTERNALS, - EQUATION, + INITIAL_VALUES, + EQUATIONS, LOCAL, - INPUT_BUFFER_CURRENT, - INPUT_BUFFER_SPIKE, OUTPUT, - SHAPE + INPUT, + PREDEFINED } } diff --git a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java index b429e538e..e189e8ca6 100644 --- a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java +++ b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java @@ -98,6 +98,9 @@ else if (astVarBlock.isInternals()) { else if (astVarBlock.isParameters ()) { printer.println("parameters" + BLOCK_OPEN); } + else if (astVarBlock.isInitial_values ()) { + printer.println("initial_values" + BLOCK_OPEN); + } } diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl index 903ce09ae..a48fc3797 100644 --- a/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl +++ b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl @@ -128,11 +128,11 @@ ${neuronName}::${neuronName}():Archiving_Node(), P_(), S_(), B_(*this) <#list body.getParameterNonAliasSymbols() as parameter> - ${tc.includeArgs("org.nest.nestml.neuron.function.MemberInitialization", [parameter, printerWithGetters])} + ${tc.includeArgs("org.nest.nestml.neuron.function.MemberInitialization", [parameter, expressionsPrinter])} <#list body.getStateNonAliasSymbols() as state> - ${tc.includeArgs("org.nest.nestml.neuron.function.MemberInitialization", [state, printerWithGetters])} + ${tc.includeArgs("org.nest.nestml.neuron.function.MemberInitialization", [state, expressionsPrinter])} } diff --git a/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java b/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java index d3a42e945..28c8f9f3b 100644 --- a/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java +++ b/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java @@ -55,17 +55,19 @@ public void testCreationOfSymtabAndResolvingOfSymbols() throws IOException { final Optional y0TVariable = neuronTypeOptional.get().getSpannedScope().resolve("y0", VariableSymbol.KIND); final Optional y1Varialbe = neuronTypeOptional.get().getSpannedScope().resolve("y1", VariableSymbol.KIND); assertTrue(y0TVariable.isPresent()); - assertTrue(y0TVariable.get().definedByODE()); + assertTrue(y0TVariable.get().isInInitialValues()); + assertTrue(y0TVariable.get().getOdeDeclaration().isPresent()); assertTrue(y0TVariable.get().isRecordable()); assertTrue(y1Varialbe.isPresent()); - assertFalse(y1Varialbe.get().definedByODE()); - assertTrue(y1Varialbe.get().isRecordable()); + assertTrue(y1Varialbe.get().isInInitialValues()); + assertTrue(y1Varialbe.get().getOdeDeclaration().isPresent()); // Checks that the derived variable is also resolvable final Optional Dy0Varialbe = neuronTypeOptional.get().getSpannedScope().resolve("y0'", VariableSymbol.KIND); assertTrue(Dy0Varialbe.isPresent()); - assertTrue(Dy0Varialbe.get().definedByODE()); + assertTrue(Dy0Varialbe.get().isInInitialValues()); + assertTrue(Dy0Varialbe.get().getOdeDeclaration().isPresent()); final Optional C_mVarialbe = neuronTypeOptional.get().getSpannedScope().resolve("C_m", VariableSymbol.KIND); assertTrue(C_mVarialbe.isPresent()); From 525fadcf9c7166f082c319183e9b38ebb4754187 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Fri, 15 Sep 2017 13:43:45 +0200 Subject: [PATCH 06/17] Adopt new grammar in the codegenerator --- models/iaf_cond_alpha.nestml | 98 +++++++++++++++++++ .../codegeneration/NestCodeGenerator.java | 10 +- .../NESTArrayStateReferenceConverter.java | 69 ------------- .../converters/NESTML2NESTTypeConverter.java | 1 - .../converters/NESTReferenceConverter.java | 19 +++- .../nest/codegeneration/helpers/GslNames.java | 2 +- .../helpers/VariableHelper.java | 1 + .../sympy/DeltaSolutionTransformer.java | 10 +- .../sympy/EquationsBlockProcessor.java | 39 +++++++- .../sympy/ExactSolutionTransformer.java | 24 +++-- .../sympy/ShapesToOdesTransformer.java | 30 ++---- .../codegeneration/sympy/SolverInput.java | 2 +- .../codegeneration/sympy/TransformerBase.java | 89 +++++++++-------- .../nest/nestml/_ast/ASTEquationsBlock.java | 3 - .../java/org/nest/nestml/_ast/ASTNeuron.java | 24 +---- .../NESTMLSymbolTableCreator.java | 50 +++++++--- .../_symboltable/symbols/VariableSymbol.java | 10 +- .../prettyprinter/NESTMLPrettyPrinter.java | 2 +- .../java/org/nest/reporting/Reporter.java | 10 +- .../org/nest/nestml/neuron/NeuronClass.ftl | 10 +- .../org/nest/nestml/neuron/NeuronHeader.ftl | 10 +- .../function/GSLDifferentiationFunction.ftl | 10 +- .../neuron/function/MemberInitialization.ftl | 2 +- .../spl/small_statement/GSLIntegrator.ftl | 2 +- .../sympy/ExactSolutionTransformerTest.java | 2 +- src/test/resources/neuron_tester.py | 2 +- 26 files changed, 313 insertions(+), 218 deletions(-) delete mode 100644 src/main/java/org/nest/codegeneration/converters/NESTArrayStateReferenceConverter.java diff --git a/models/iaf_cond_alpha.nestml b/models/iaf_cond_alpha.nestml index d834902ed..c1c02c624 100644 --- a/models/iaf_cond_alpha.nestml +++ b/models/iaf_cond_alpha.nestml @@ -1,3 +1,101 @@ +/* +Name: iaf_cond_alpha_neuron - Simple conductance based leaky integrate-and-fire neuron + model. + +Description: +iaf_cond_alpha is an implementation of a spiking neuron using IAF dynamics with +conductance-based synapses. Incoming spike events induce a post-synaptic change +of conductance modelled by an alpha function. The alpha function +is normalised such that an event of weight 1.0 results in a peak current of 1 nS +at t = tau_syn. + +Sends: SpikeEvent + +Receives: SpikeEvent, CurrentEvent, DataLoggingRequest + +References: + +Meffin, H., Burkitt, A. N., & Grayden, D. B. (2004). An analytical +model for the large, fluctuating synaptic conductance state typical of +neocortical neurons in vivo. J. Comput. Neurosci., 16, 159-175. + +Bernander, O ., Douglas, R. J., Martin, K. A. C., & Koch, C. (1991). +Synaptic background activity influences spatiotemporal integration in +single pyramidal cells. Proc. Natl. Acad. Sci. USA, 88(24), +11569-11573. + +Kuhn, Aertsen, Rotter (2004) Neuronal Integration of Synaptic Input in +the Fluctuation- Driven Regime. Jneurosci 24(10) 2345-2356 + +Author: Schrader, Plesser + +SeeAlso: iaf_cond_exp, iaf_cond_alpha_mc +*/ +neuron iaf_cond_alpha_neuron: + + state: + r integer ## counts number of tick during the refractory period + end + + initial_values: + V_m mV = E_L ## membrane potential + end + + equations: + shape g_in = (e/tau_syn_in) * t * exp(-t/tau_syn_in) + shape g_ex = (e/tau_syn_ex) * t * exp(-t/tau_syn_ex) + + function I_syn_exc pA = cond_sum(g_ex, spikeExc) * ( V_m - E_ex ) + function I_syn_inh pA = cond_sum(g_in, spikeInh) * ( V_m - E_in ) + function I_leak pA = g_L * ( V_m - E_L ) + + V_m' = ( -I_leak - I_syn_exc - I_syn_inh + currents + I_e ) / C_m + end + + parameters: + V_th mV = -55.0mV ## Threshold Potential in mV + V_reset mV = -60.0mV ## Reset Potential in mV + t_ref ms = 2.ms ## Refractory period in ms + g_L nS = 16.6667nS ## Leak Conductance in nS + C_m pF = 250.0 pF ## Membrane Capacitance in pF + E_ex mV = 0mV ## Excitatory reversal Potential in mV + E_in mV = -85.0mV ## Inhibitory reversal Potential in mV + E_L mV = -70.0mV ## Leak reversal Potential (aka resting potential) in mV + tau_syn_ex ms = 0.2ms ## Synaptic Time Constant Excitatory Synapse in ms + tau_syn_in ms = 2.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms + I_e pA = 0pA ## Constant Current in pA + ## Input current injected by CurrentEvent. + ## This variable is used to transport the current applied into the + ## _dynamics function computing the derivative of the state vector. + end + + internals: + RefractoryCounts integer = steps(t_ref) # refractory time in steps + end + + input: + spikeInh <- inhibitory spike + spikeExc <- excitatory spike + currents <- current + end + + output: spike + + update: + integrate_odes() + if r != 0: # neuron is absolute refractory + r = r - 1 + V_m = V_reset # clamp potential + elif V_m >= V_th: # neuron is not absolute refractory + r = RefractoryCounts + V_m = V_reset # clamp potential + emit_spike() + end + end + +end + + /* Name: iaf_cond_alpha_implicit - Simple conductance based leaky integrate-and-fire neuron model. diff --git a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java index 46925ec61..9675213f3 100644 --- a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java +++ b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java @@ -84,7 +84,7 @@ private ASTNeuron solveOdesAndShapes( final Optional odesBlock = astNeuron.findEquationsBlock(); if (odesBlock.isPresent()) { - if (odesBlock.get().getShapes().size() == 0 && odesBlock.get().getODEs().size() > 1) { + if (odesBlock.get().getShapes().size() == 0 && odesBlock.get().getEquations().size() > 1) { final String msg = String.format( "The neuron %s will be solved numerically with GSL solver without modification.", astNeuron.getName()); @@ -191,11 +191,9 @@ public void generateNESTModuleCode( private GlobalExtensionManagement getGlexConfiguration() { final GlobalExtensionManagement glex = new GlobalExtensionManagement(); - final NESTReferenceConverter converter = new NESTReferenceConverter(); + final NESTReferenceConverter converter = new NESTReferenceConverter(false); final ExpressionsPrettyPrinter expressionsPrinter = new LegacyExpressionPrinter(converter); - - glex.setGlobalValue("expressionsPrinter", expressionsPrinter); glex.setGlobalValue("functionCallConverter", converter); glex.setGlobalValue("idemPrinter", new LegacyExpressionPrinter()); @@ -245,11 +243,11 @@ private void defineSolverType(final GlobalExtensionManagement glex, final ASTNeu if (neuron.findEquationsBlock().isPresent()) { if (!functionShapeExists(neuron.findEquationsBlock().get().getShapes()) || - neuron.findEquationsBlock().get().getODEs().size() > 1) { + neuron.findEquationsBlock().get().getEquations().size() > 1) { glex.setGlobalValue("names", new GslNames()); glex.setGlobalValue("useGSL", true); - final IReferenceConverter converter = new NESTArrayStateReferenceConverter(); + final NESTReferenceConverter converter = new NESTReferenceConverter(true); final ExpressionsPrettyPrinter expressionsPrinter = new LegacyExpressionPrinter(converter); glex.setGlobalValue("expressionsPrinter", expressionsPrinter); } diff --git a/src/main/java/org/nest/codegeneration/converters/NESTArrayStateReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/NESTArrayStateReferenceConverter.java deleted file mode 100644 index 9d2a9df07..000000000 --- a/src/main/java/org/nest/codegeneration/converters/NESTArrayStateReferenceConverter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2015 RWTH Aachen. All rights reserved. - * - * http://www.se-rwth.de/ - */ -package org.nest.codegeneration.converters; - -import de.monticore.symboltable.Scope; -import org.nest.codegeneration.helpers.GslNames; -import org.nest.nestml._ast.ASTVariable; -import org.nest.nestml._symboltable.predefined.PredefinedVariables; -import org.nest.nestml._symboltable.symbols.VariableSymbol; -import org.nest.utils.AstUtils; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.nest.codegeneration.helpers.VariableHelper.printOrigin; -import static org.nest.nestml._symboltable.symbols.VariableSymbol.resolve; -import static org.nest.utils.AstUtils.convertSiName; - -import java.util.Optional; - -/** - * Converts constants, names and functions the NEST equivalents. - * - * @author plotnikov - */ -public class NESTArrayStateReferenceConverter extends NESTReferenceConverter { - - @Override - public String convertNameReference(final ASTVariable astVariable) { - checkArgument(astVariable.getEnclosingScope().isPresent(), "Run symboltable creator"); - final String variableName = AstUtils.convertDevrivativeNameToSimpleName(astVariable); - final Scope scope = astVariable.getEnclosingScope().get(); - - Optional siUnitAsLiteral = convertSiName(astVariable.toString()); - if(siUnitAsLiteral.isPresent()){ - return siUnitAsLiteral.get(); - } - - if (PredefinedVariables.E_CONSTANT.equals(variableName)) { - return "numerics::e"; - } - else { - final VariableSymbol variableSymbol = resolve(variableName, scope); - if (variableSymbol.isState()) { - return "S_." + GslNames.name(variableSymbol); // TODO refactor me - } - else if (variableSymbol.getBlockType().equals(VariableSymbol.BlockType.LOCAL)) { - return variableName + (variableSymbol.isVector()?"[i]":""); - } - else if(variableSymbol.isBuffer()) { - return printOrigin(variableSymbol) + org.nest.codegeneration.helpers.Names.bufferValue(variableSymbol) ; - } - else { - if (variableSymbol.isFunction()) { - return "get_" + variableName + "()" + (variableSymbol.isVector()?"[i]":"") ; - } - else { - - return printOrigin(variableSymbol) + variableName + (variableSymbol.isVector()?"[i]":""); - } - - } - - } - - } - -} diff --git a/src/main/java/org/nest/codegeneration/converters/NESTML2NESTTypeConverter.java b/src/main/java/org/nest/codegeneration/converters/NESTML2NESTTypeConverter.java index 8a3849bbd..2afe02704 100644 --- a/src/main/java/org/nest/codegeneration/converters/NESTML2NESTTypeConverter.java +++ b/src/main/java/org/nest/codegeneration/converters/NESTML2NESTTypeConverter.java @@ -44,7 +44,6 @@ private String doConvert(final TypeSymbol nestmlType) { return "nest::Time"; } final String name = nestmlType.getName(); - PredefinedTypes.getRealType().equals(nestmlType); return name.replaceAll("\\.", "::"); } } diff --git a/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java b/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java index 1c2690bc1..a4838f5c8 100644 --- a/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java +++ b/src/main/java/org/nest/codegeneration/converters/NESTReferenceConverter.java @@ -6,13 +6,13 @@ package org.nest.codegeneration.converters; import de.monticore.symboltable.Scope; +import org.nest.codegeneration.helpers.GslNames; +import org.nest.codegeneration.helpers.Names; import org.nest.nestml._ast.ASTFunctionCall; import org.nest.nestml._ast.ASTVariable; import org.nest.nestml.prettyprinter.IReferenceConverter; -import org.nest.nestml._symboltable.NestmlSymbols; import org.nest.nestml._symboltable.predefined.PredefinedFunctions; import org.nest.nestml._symboltable.predefined.PredefinedVariables; -import org.nest.nestml._symboltable.symbols.MethodSymbol; import org.nest.nestml._symboltable.symbols.VariableSymbol; import org.nest.utils.AstUtils; @@ -30,6 +30,11 @@ * @author plotnikov */ public class NESTReferenceConverter implements IReferenceConverter { + private final boolean usesGSL; + + public NESTReferenceConverter(boolean usesGSL) { + this.usesGSL = usesGSL; + } @Override public String convertBinaryOperator(final String binaryOperator) { @@ -125,15 +130,21 @@ public String convertNameReference(final ASTVariable astVariable) { return variableName + (variableSymbol.isVector()?"[i]":""); } else if(variableSymbol.isBuffer()) { - return printOrigin(variableSymbol) + org.nest.codegeneration.helpers.Names.bufferValue(variableSymbol) + (variableSymbol.isVector()?"[i]":""); + return printOrigin(variableSymbol) + Names.bufferValue(variableSymbol) + (variableSymbol.isVector()?"[i]":""); } else { if (variableSymbol.isFunction()) { return "get_" + variableName + "()" + (variableSymbol.isVector()?"[i]":"") ; } else { + if (variableSymbol.isInInitialValues()) { + return printOrigin(variableSymbol) + + (usesGSL? GslNames.name(variableSymbol): Names.name(variableSymbol)) + + (variableSymbol.isVector()?"[i]":""); + } else { + return printOrigin(variableSymbol) + Names.name(variableSymbol) + (variableSymbol.isVector()?"[i]":""); + } - return printOrigin(variableSymbol) + variableName + (variableSymbol.isVector()?"[i]":""); } } diff --git a/src/main/java/org/nest/codegeneration/helpers/GslNames.java b/src/main/java/org/nest/codegeneration/helpers/GslNames.java index d3fd61ee1..590501c69 100644 --- a/src/main/java/org/nest/codegeneration/helpers/GslNames.java +++ b/src/main/java/org/nest/codegeneration/helpers/GslNames.java @@ -15,7 +15,7 @@ public static String arrayIndex(final VariableSymbol variableSymbol) { public static String name(final VariableSymbol variableSymbol) { if (variableSymbol.isInInitialValues()) { - return "y[State_::" + Names.convertToCPPName(variableSymbol.getName()) + "]"; + return "ode_state[State_::" + Names.convertToCPPName(variableSymbol.getName()) + "]"; } else { return Names.name(variableSymbol); diff --git a/src/main/java/org/nest/codegeneration/helpers/VariableHelper.java b/src/main/java/org/nest/codegeneration/helpers/VariableHelper.java index 27004bdb4..c3f9ab754 100644 --- a/src/main/java/org/nest/codegeneration/helpers/VariableHelper.java +++ b/src/main/java/org/nest/codegeneration/helpers/VariableHelper.java @@ -11,6 +11,7 @@ static public String printOrigin(final VariableSymbol variableSymbol) { switch (variableSymbol.getBlockType()) { case STATE: case EQUATIONS: + case INITIAL_VALUES: return "S_."; case PARAMETERS: return "P_."; diff --git a/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java b/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java index ad6d57f7d..cd5b861d7 100644 --- a/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/DeltaSolutionTransformer.java @@ -22,7 +22,7 @@ * * @author plotnikov */ -class DeltaSolutionTransformer extends TransformerBase { +class DeltaSolutionTransformer { ASTNeuron addExactSolution( final SolverOutput solverOutput, final ASTNeuron astNeuron) { @@ -30,8 +30,8 @@ ASTNeuron addExactSolution( ASTNeuron workingVersion = astNeuron; //addVariableToInternals(astNeuron, p30File); workingVersion.addToInternalBlock(createDeclaration("__h ms = resolution()")); - workingVersion = addVariableToInternals(workingVersion, solverOutput.const_input); - workingVersion = addVariableToInternals(workingVersion, solverOutput.ode_var_factor); + workingVersion = TransformerBase.addVariableToInternals(workingVersion, solverOutput.const_input); + workingVersion = TransformerBase.addVariableToInternals(workingVersion, solverOutput.ode_var_factor); final List i_sumCalls = AstUtils.getAll(astNeuron.findEquationsBlock().get(), ASTFunctionCall.class) .stream() @@ -44,7 +44,9 @@ ASTNeuron addExactSolution( solverOutput.ode_var_update_instructions.add(astNeuron.getEquations().get(0).getLhs().getName() + "+=" + bufferName); } - workingVersion = replaceIntegrateCallThroughPropagation(workingVersion, solverOutput.ode_var_update_instructions); + workingVersion = TransformerBase.replaceIntegrateCallThroughPropagation( + workingVersion, + solverOutput.ode_var_update_instructions); return workingVersion; } diff --git a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java index 08050e222..c9e7c3146 100644 --- a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java +++ b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java @@ -5,12 +5,18 @@ */ package org.nest.codegeneration.sympy; +import com.google.common.collect.Lists; +import org.nest.nestml._ast.ASTAssignment; +import org.nest.nestml._ast.ASTFunctionCall; import org.nest.nestml._ast.ASTNeuron; import org.nest.nestml._ast.ASTShape; +import org.nest.nestml._symboltable.symbols.VariableSymbol; +import org.nest.nestml.prettyprinter.ExpressionsPrettyPrinter; import org.nest.reporting.Reporter; import java.nio.file.Path; import java.util.List; +import java.util.stream.Collectors; import static org.nest.utils.AstUtils.deepCloneNeuronAndBuildSymbolTable; @@ -42,7 +48,7 @@ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path output // this function is called only for neurons with an ode block. thus, retrieving it is safe. if (deepCopy.findEquationsBlock().get().getShapes().size() > 0 && !odeShapeExists(deepCopy.findEquationsBlock().get().getShapes()) && - deepCopy.findEquationsBlock().get().getODEs().size() == 1) { + deepCopy.findEquationsBlock().get().getEquations().size() == 1) { final SolverOutput solverOutput = evaluator.solveOdeWithShapes(deepCopy.findEquationsBlock().get(), outputBase); reporter.reportProgress("The model ODE with shapes will be analyzed."); @@ -82,10 +88,39 @@ else if (deepCopy.findEquationsBlock().get().getShapes().size() > 0 && } } - reporter.reportProgress(String.format("The %s remains unchanged", astNeuron.getName())); + + applyIncomingSpikes(astNeuron); + return astNeuron; } + private void applyIncomingSpikes(ASTNeuron astNeuron) { + reporter.reportProgress("Apply spikes to buffers..."); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + final List convCalls = OdeTransformer.get_sumFunctionCalls(astNeuron); + final ExpressionsPrettyPrinter printer = new ExpressionsPrettyPrinter(); + + final List spikesUpdates = Lists.newArrayList(); + for (ASTFunctionCall convCall:convCalls) { + String shape = convCall.getArgs().get(0).getVariable().get().toString(); + String buffer = convCall.getArgs().get(1).getVariable().get().toString(); + + List shapeSymbols = astNeuron.getInitialValuesSymbols() + .stream() + .filter(variableSymbol -> variableSymbol.getName().matches(shape + "(')*")) + .collect(Collectors.toList()); + + spikesUpdates.addAll(shapeSymbols + .stream() + .map(shapeSymbol -> AstCreator.createAssignment( + shapeSymbol.getName() + " += " + buffer + " * " + printer.print(shapeSymbol.getDeclaringExpression().get()))) + .collect(Collectors.toList())); + + } + final TransformerBase transformerBase = new TransformerBase(); + spikesUpdates.forEach(update -> transformerBase.addAssignmentToUpdateBlock(update, astNeuron)); + } + private boolean odeShapeExists(final List shapes) { return shapes.stream().anyMatch(shape -> shape.getLhs().getDifferentialOrder().size() > 0); } diff --git a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java index da460047d..80cd24e74 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java @@ -26,7 +26,7 @@ * * @author plotnikov */ -class ExactSolutionTransformer extends TransformerBase { +class ExactSolutionTransformer { ASTNeuron addExactSolution( @@ -35,24 +35,28 @@ ASTNeuron addExactSolution( ASTNeuron workingVersion = astNeuron; workingVersion.addToInternalBlock(createDeclaration("__h ms = resolution()")); - workingVersion = addVariableToInternals(workingVersion, solverOutput.ode_var_factor); - workingVersion = addVariableToInternals(workingVersion, solverOutput.const_input); - workingVersion = addVariablesToInternals(workingVersion, solverOutput.initial_values); - workingVersion = addVariablesToInternals(workingVersion, solverOutput.propagator_elements); - workingVersion = addVariablesToState(workingVersion, solverOutput.shape_state_variables); + workingVersion = TransformerBase.addVariableToInternals(workingVersion, solverOutput.ode_var_factor); + workingVersion = TransformerBase.addVariableToInternals(workingVersion, solverOutput.const_input); + workingVersion = TransformerBase.addVariablesToInternals(workingVersion, solverOutput.initial_values); + workingVersion = TransformerBase.addVariablesToInternals(workingVersion, solverOutput.propagator_elements); + workingVersion = TransformerBase.addVariablesToState(workingVersion, solverOutput.shape_state_variables); workingVersion = addShapeStateUpdatesToUpdateBlock(workingVersion, solverOutput); workingVersion.removeEquationsBlock(); // oder is important, otherwise addShapeStateUpdatesToUpdateBlock will try to resolve state variables, // for which nor symbol are added. TODO filter them - workingVersion = replaceIntegrateCallThroughPropagation(workingVersion, solverOutput.ode_var_update_instructions); + workingVersion = TransformerBase.replaceIntegrateCallThroughPropagation(workingVersion, solverOutput.ode_var_update_instructions); return workingVersion; } private ASTNeuron addShapeStateUpdatesToUpdateBlock(final ASTNeuron astNeuron, final SolverOutput solverOutput) { addStateUpdates(solverOutput, astNeuron); - addUpdatesWithPSCInitialValues(solverOutput, astNeuron, variableNameExtracter, shapeNameExtracter); + TransformerBase.addShapeVariableUpdatesWithIncomingSpikes( + solverOutput, + astNeuron, + TransformerBase.variableNameExtracter, + TransformerBase.shapeNameExtracter); return astNeuron; } @@ -68,13 +72,13 @@ private void addStateUpdates(final SolverOutput solverOutput, final ASTNeuron as .stream() .map(update -> update + " real") .map(AstCreator::createDeclaration) - .forEach(astAssignment -> addDeclrationToUpdateBlock(astAssignment, astNeuron)); + .forEach(astAssignment -> TransformerBase.addDeclarationToUpdateBlock(astAssignment, astNeuron)); solverOutput.updates_to_shape_state_variables .stream() .map(update -> update.getKey() + " = " + update.getValue()) .map(AstCreator::createAssignment) - .forEach(astAssignment -> addAssignmentToUpdateBlock(astAssignment, astNeuron)); + .forEach(astAssignment -> TransformerBase.addAssignmentToUpdateBlock(astAssignment, astNeuron)); } // TODO: enable the optimization diff --git a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java index a1f73c8e0..7e0c2d32a 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java @@ -5,7 +5,6 @@ */ package org.nest.codegeneration.sympy; -import org.nest.nestml._ast.ASTDeclaration; import org.nest.nestml._ast.ASTEquation; import org.nest.nestml._ast.ASTEquationsBlock; import org.nest.nestml._ast.ASTNeuron; @@ -22,19 +21,19 @@ * * @author plotnikov */ -class ShapesToOdesTransformer extends TransformerBase { +class ShapesToOdesTransformer { ASTNeuron transformShapesToOdeForm(final ASTNeuron astNeuron, final SolverOutput solverOutput) { checkArgument(astNeuron.findEquationsBlock().isPresent()); - ASTNeuron workingVersion = addVariablesToState(astNeuron, solverOutput.shape_state_variables); - workingVersion = addVariablesToInternals(workingVersion, solverOutput.initial_values); - workingVersion = removeShapes(workingVersion); - addUpdatesWithPSCInitialValues( + ASTNeuron workingVersion = TransformerBase.addVariablesToState(astNeuron, solverOutput.shape_state_variables); + workingVersion = TransformerBase.addVariablesToInternals(workingVersion, solverOutput.initial_values); + workingVersion = TransformerBase.removeShapes(workingVersion); + TransformerBase.addShapeVariableUpdatesWithIncomingSpikes( solverOutput, workingVersion, - variableNameExtracter, - shapeNameExtracter); + TransformerBase.variableNameExtracter, + TransformerBase.shapeNameExtracter); addStateShapeEquationsToEquationsBlock(solverOutput.shape_state_odes, workingVersion.findEquationsBlock().get()); @@ -48,20 +47,7 @@ private void addStateShapeEquationsToEquationsBlock( .map(ode -> ode.getKey() + "' = " + ode.getValue()) .map(AstCreator::createEquation) .collect(toList()); - astOdeDeclaration.getODEs().addAll(equations); - } - - private List shapesToStateVariables(final ASTEquationsBlock astOdeDeclaration) { - final List stateVariables = astOdeDeclaration.getShapes() - .stream() - .map(shape -> shape.getLhs().toString()) - .collect(toList()); - - return stateVariables - .stream() - .map(variable -> variable + " real") - .map(AstCreator::createDeclaration) - .collect(toList()); + astOdeDeclaration.getEquations().addAll(equations); } } diff --git a/src/main/java/org/nest/codegeneration/sympy/SolverInput.java b/src/main/java/org/nest/codegeneration/sympy/SolverInput.java index 8186c6ac8..8a1b64593 100644 --- a/src/main/java/org/nest/codegeneration/sympy/SolverInput.java +++ b/src/main/java/org/nest/codegeneration/sympy/SolverInput.java @@ -47,7 +47,7 @@ class SolverInput { ASTEquationsBlock tmp = odeBlock.deepClone(); tmp = OdeTransformer.replaceSumCalls(tmp); - ode = printEquation(tmp.getODEs().get(0)); + ode = printEquation(tmp.getEquations().get(0)); functions = tmp.getOdeFunctions() .stream() diff --git a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java index 33f8c84b4..37ed35297 100644 --- a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java +++ b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java @@ -1,9 +1,7 @@ package org.nest.codegeneration.sympy; import de.monticore.ast.ASTNode; -import de.monticore.symboltable.Scope; import de.se_rwth.commons.logging.Log; -import org.nest.nestml._ast.ASTFunctionCall; import org.nest.nestml._ast.*; import org.nest.nestml._parser.NESTMLParser; import org.nest.nestml._symboltable.predefined.PredefinedFunctions; @@ -16,27 +14,26 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; -import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkState; import static java.util.stream.Collectors.toList; import static org.nest.codegeneration.sympy.AstCreator.createAssignment; import static org.nest.codegeneration.sympy.AstCreator.createDeclaration; -import static org.nest.nestml._symboltable.symbols.VariableSymbol.resolve; /** * Provides common methods for AST transformations which are performed after SymPy analysis. * * @author plotnikov */ -public class TransformerBase { +final public class TransformerBase { + // example initial value iv__I_shape_in // example initial value iv__I_shape_in__1 // the shape state variable is `I_shape_in__1` // the shape name is `I_shape_in` - final Function variableNameExtracter = initialValue -> initialValue.substring("iv__".length()); + final static Function variableNameExtracter = initialValue -> initialValue.substring("iv__".length()); - final Function shapeNameExtracter = initialValue -> { + final static Function shapeNameExtracter = initialValue -> { final String tmp = initialValue.substring("iv__".length()); if (tmp.lastIndexOf("__") == -1) { return tmp; @@ -46,20 +43,20 @@ public class TransformerBase { } }; - private final NESTMLParser parser = new NESTMLParser(); + private static final NESTMLParser parser = new NESTMLParser(); - ASTNeuron addVariablesToState(final ASTNeuron astNeuron, final List shapeStateVariables) { + static ASTNeuron addVariablesToState(final ASTNeuron astNeuron, final List shapeStateVariables) { //final List correspondingShapeSymbols = shapeStateVariables // .stream() // .map(this::getShapeNameFromStateVariable) // .collect(Collectors.toList()); - for (int i = 0; i < shapeStateVariables.size(); ++i) { + for (String shapeStateVariable : shapeStateVariables) { // final Scope scope = astNeuron.getEnclosingScope().get(); //checkState(astNeuron.getEnclosingScope().isPresent()); //final String vectorDatatype = correspondingShapeSymbols.get(i).isVector()?"[" + correspondingShapeSymbols.get(i).getVectorParameter().get() + "]":""; - final String stateVarDeclaration = shapeStateVariables.get(i) + " real"; + final String stateVarDeclaration = shapeStateVariable + " real"; astNeuron.addToStateBlock(createDeclaration(stateVarDeclaration)); } @@ -68,24 +65,44 @@ ASTNeuron addVariablesToState(final ASTNeuron astNeuron, final List shap } /** - * For every oder of the shape a variable of the typ shape_name__order is created. This function extracts the shape - * name. - * @param shapeStateVariable Statevariable name generated by the solver script - * @return Shapename as a string + * Add a list with declarations to the internals block in the neuron. */ - private String getShapeNameFromStateVariable(final String shapeStateVariable) { - if (shapeStateVariable.lastIndexOf("__") == -1) { - return shapeStateVariable; + static ASTNeuron addVariablesToInternals( + final ASTNeuron astNeuron, + final List> declarationsFile) { + declarationsFile.forEach(declaration -> addVariableToInternals(astNeuron, declaration)); + return astNeuron; + } + + /** + * Adds the declaration of the P00 value to the nestml model. Note: very NEST specific. + */ + static ASTNeuron addVariableToInternals( + final ASTNeuron astNeuron, + final Map.Entry declaration) { + try { + ASTExpr tmp = parser.parseExpr(new StringReader(declaration.getValue())).get(); // must not fail by construction + final Optional vectorVariable = AstUtils.getVectorizedVariable(tmp, astNeuron.getSpannedScope().get()); + + final String declarationString = declaration.getKey() + " real" + + vectorVariable.map(variableSymbol -> "[" + variableSymbol.getVectorParameter().get() + "]").orElse("") + + " = " + declaration.getValue(); + final ASTDeclaration astDeclaration = parser.parseDeclaration(new StringReader(declarationString)).get(); + vectorVariable.ifPresent(var -> astDeclaration.setSizeParameter(var.getVectorParameter().get())); + astNeuron.addToInternalBlock(astDeclaration); + return astNeuron; } - else { - return shapeStateVariable.substring(0, shapeStateVariable.lastIndexOf("__")); + catch (IOException e) { + throw new RuntimeException("Must not fail by construction."); } + } + /** * Add a list with declarations to the internals block in the neuron. */ - ASTNeuron addVariablesToInternals( + static ASTNeuron addVariablesToInitialValues( final ASTNeuron astNeuron, final List> declarationsFile) { declarationsFile.forEach(declaration -> addVariableToInternals(astNeuron, declaration)); @@ -95,11 +112,11 @@ ASTNeuron addVariablesToInternals( /** * Adds the declaration of the P00 value to the nestml model. Note: very NEST specific. */ - ASTNeuron addVariableToInternals( + static ASTNeuron addVariableToInitialValue( final ASTNeuron astNeuron, final Map.Entry declaration) { try { - ASTExpr tmp = parser.parseExpr(new StringReader(declaration.getValue())).get(); // must not fail by constuction + ASTExpr tmp = parser.parseExpr(new StringReader(declaration.getValue())).get(); // must not fail by construction final Optional vectorVariable = AstUtils.getVectorizedVariable(tmp, astNeuron.getSpannedScope().get()); final String declarationString = declaration.getKey() + " real" + @@ -107,8 +124,9 @@ ASTNeuron addVariableToInternals( + " = " + declaration.getValue(); final ASTDeclaration astDeclaration = parser.parseDeclaration(new StringReader(declarationString)).get(); vectorVariable.ifPresent(var -> astDeclaration.setSizeParameter(var.getVectorParameter().get())); - astNeuron.addToInternalBlock(astDeclaration); - return astNeuron; + //astNeuron.addToInitialValuesBlock(astDeclaration); + throw new RuntimeException(); + //return astNeuron; } catch (IOException e) { throw new RuntimeException("Must not fail by construction."); @@ -116,7 +134,8 @@ ASTNeuron addVariableToInternals( } - ASTNeuron replaceIntegrateCallThroughPropagation(final ASTNeuron astNeuron, List propagatorSteps) { + + static ASTNeuron replaceIntegrateCallThroughPropagation(final ASTNeuron astNeuron, List propagatorSteps) { // It must work for multiple integrate calls! final Optional integrateCall = AstUtils.getFunctionCall( PredefinedFunctions.INTEGRATE_ODES, @@ -147,7 +166,7 @@ ASTNeuron replaceIntegrateCallThroughPropagation(final ASTNeuron astNeuron, List } else { Log.trace( "The model has defined an ODE. But its solution is not used in the update state.", - this.getClass().getSimpleName()); + TransformerBase.class.getSimpleName()); return astNeuron; } @@ -156,7 +175,7 @@ ASTNeuron replaceIntegrateCallThroughPropagation(final ASTNeuron astNeuron, List /** * Add updates of state variables with the PSC initial value and corresponding inputs from buffers. */ - void addUpdatesWithPSCInitialValues( + static void addShapeVariableUpdatesWithIncomingSpikes( final SolverOutput solverOutput, final ASTNeuron body, final Function stateVariableNameExtracter, @@ -190,7 +209,7 @@ void addUpdatesWithPSCInitialValues( } - void addAssignmentToUpdateBlock(final ASTAssignment astAssignment, final ASTNeuron astNeuron) { + static void addAssignmentToUpdateBlock(final ASTAssignment astAssignment, final ASTNeuron astNeuron) { final ASTStmt astStmt = NESTMLNodeFactory.createASTStmt(); final ASTSmall_Stmt astSmall_stmt = NESTMLNodeFactory.createASTSmall_Stmt(); @@ -202,7 +221,7 @@ void addAssignmentToUpdateBlock(final ASTAssignment astAssignment, final ASTNeur astNeuron.getUpdateBlocks().get(0).getBlock().getStmts().add(astStmt); } - void addDeclrationToUpdateBlock(final ASTDeclaration astDeclaration, final ASTNeuron astNeuron) { + static void addDeclarationToUpdateBlock(final ASTDeclaration astDeclaration, final ASTNeuron astNeuron) { final ASTStmt astStmt = NESTMLNodeFactory.createASTStmt(); final ASTSmall_Stmt astSmall_stmt = NESTMLNodeFactory.createASTSmall_Stmt(); @@ -214,15 +233,7 @@ void addDeclrationToUpdateBlock(final ASTDeclaration astDeclaration, final ASTNe astNeuron.getUpdateBlocks().get(0).getBlock().getStmts().add(astStmt); } - ASTStmt statement(final ASTAssignment astAssignment) { - final ASTSmall_Stmt astSmall_stmt = NESTMLNodeFactory.createASTSmall_Stmt(); - final ASTStmt astStmt = NESTMLNodeFactory.createASTStmt(); - astSmall_stmt.setAssignment(astAssignment); - astStmt.setSmall_Stmt(astSmall_stmt); - return astStmt; - } - - ASTNeuron removeShapes(ASTNeuron astNeuron) { + static ASTNeuron removeShapes(ASTNeuron astNeuron) { astNeuron.findEquationsBlock().get().getShapes().clear(); return astNeuron; } diff --git a/src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java b/src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java index 6daae7bcf..7476afb37 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java +++ b/src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java @@ -52,7 +52,4 @@ public List getShapes() { return shapes; } - public List getODEs() { - return equations; - } } diff --git a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java index b395a8100..a36af6596 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java +++ b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java @@ -115,7 +115,7 @@ public String printInternalComment() { public List getEquations() { final Optional equations = findEquationsBlock(); if (equations.isPresent()) { - return equations.get().getODEs(); + return equations.get().getEquations(); } else { return Lists.newArrayList(); @@ -132,13 +132,6 @@ public List getShapes() { } } - public List variablesDefinedByODE() { - return getStateSymbols() - .stream() - .filter(VariableSymbol::isInInitialValues) - .collect(toList()); - } - public Optional findEquationsBlock() { return this.getEquationsBlocks() .stream() @@ -160,25 +153,14 @@ public List getStateSymbols() { } - public List getOdeDefinedSymbols() { + public List getInitialValuesSymbols() { return this.getSpannedScope().get().resolveLocally(VariableSymbol.KIND) .stream() - .map(stateSymbol -> (VariableSymbol) stateSymbol) - .filter(VariableSymbol::isState) + .map(variable -> (VariableSymbol) variable) .filter(VariableSymbol::isInInitialValues) .collect(toList()); - } - public List getStateSymbolsWithoutOde() { - return this.getSpannedScope().get().resolveLocally(VariableSymbol.KIND) - .stream() - .map(stateSymbol -> (VariableSymbol) stateSymbol) - .filter(VariableSymbol::isState) - .filter(variableSymbol -> !variableSymbol.isInInitialValues()) - .collect(toList()); - - } public List getStateAliasSymbols() { return getVariableSymbols(getDeclarationsFromBlock(ASTBlockWithVariables::isState), getSpannedScope().get()) diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java index 28c399bc2..e9fcbb6d3 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java @@ -116,7 +116,7 @@ public void endVisit(final ASTNeuron astNeuron) { if (multipleDefinitions.isEmpty()) { if (astNeuron.findEquationsBlock().isPresent()) { - assignOdeToVariables(astNeuron.findEquationsBlock().get()); + connectOdesToInitialValues(astNeuron.findEquationsBlock().get()); markConductanceBasedBuffers(astNeuron.findEquationsBlock().get(), astNeuron.getInputLines()); } @@ -170,31 +170,51 @@ private void addFunctionVariables(final ASTEquationsBlock astOdeDeclaration) { } } - private void assignOdeToVariables(final ASTEquationsBlock astOdeDeclaration) { - astOdeDeclaration.getODEs().forEach(this::addOdeToVariable); + private void connectOdesToInitialValues(final ASTEquationsBlock astOdeDeclaration) { + astOdeDeclaration.getEquations().forEach(equation -> connectOdeToVariable(equation.getLhs(), equation.getRhs())); + + astOdeDeclaration.getShapes() + .stream() + .filter(astShape -> astShape.getLhs().getDifferentialOrder().size() > 0) + .forEach(astShape -> connectOdeToVariable(astShape.getLhs(), astShape.getRhs())); + + astOdeDeclaration.getShapes() + .stream() + .map(ASTShape::getLhs) + .forEach(this::markShapeVariables); } - private void addOdeToVariable(final ASTEquation ode) { + private void connectOdeToVariable(final ASTDerivative derivedVariable, final ASTExpr astExpr) { checkState(this.currentScope().isPresent()); final Scope scope = currentScope().get(); - if (ode.getLhs().getDifferentialOrder().size() > 0) { - final String variableName = ode.getLhs().getNameOfDerivedVariable(); - final Optional stateVariable = scope.resolve(variableName, VariableSymbol.KIND); + final String variableName = derivedVariable.getNameOfDerivedVariable(); + final Optional variable = scope.resolve(variableName, VariableSymbol.KIND); - if (stateVariable.isPresent()) { - stateVariable.get().setOdeDeclaration(ode.getRhs()); + if (variable.isPresent()) { + variable.get().setOdeDeclaration(astExpr); } else { - Log.warn("NESTMLSymbolTableCreator: The left side of the ode is undefined. Cannot assign its definition: " + variableName, ode.get_SourcePositionStart()); + Log.warn("NESTMLSymbolTableCreator: The left side of the ode is undefined. Cannot assign its definition: " + + variableName, derivedVariable.get_SourcePositionStart()); } + + } + + private void markShapeVariables(final ASTDerivative derivedVariable) { + checkState(this.currentScope().isPresent()); + final Scope scope = currentScope().get(); + final String variableName = derivedVariable.getNameOfDerivedVariable(); + final Optional variable = scope.resolve(variableName, VariableSymbol.KIND); + + if (variable.isPresent()) { + variable.get().markShape(); } else { - Log.warn("NESTMLSymbolTableCreator: The lefthandside of an equation must be a derivative, e.g. " + ode.getLhs().toString() + "'", ode.get_SourcePositionStart()); + Log.warn("NESTMLSymbolTableCreator: The left side of the ode is undefined. Cannot assign its definition: " + + variableName, derivedVariable.get_SourcePositionStart()); } - } - /** * For each buffer, if it is used in the Cond_sum function, a conductance flag is added. E.g. in * equations: @@ -219,7 +239,7 @@ private void markConductanceBasedBuffers(final ASTEquationsBlock astOdeDeclarati .collect(Collectors.toList()); final List equations = Lists.newArrayList(); - equations.addAll(astOdeDeclaration.getODEs()); + equations.addAll(astOdeDeclaration.getEquations()); equations.addAll(astOdeDeclaration.getOdeFunctions()); for (VariableSymbol spikeBuffer:spikeBuffers) { @@ -408,7 +428,7 @@ private void addVariablesFromDeclaration(final ASTDeclaration astDeclaration, final String typeName = computeTypeName(astDeclaration.getDatatype()); var.setType(PredefinedTypes.getType(typeName)); - boolean isRecordableVariable = blockType == STATE || astDeclaration.isRecordable(); + boolean isRecordableVariable = blockType == STATE || blockType == INITIAL_VALUES || astDeclaration.isRecordable(); if (isRecordableVariable) { // otherwise is set to false. var.setRecordable(true); diff --git a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java index 731587964..880613bc5 100644 --- a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java +++ b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java @@ -30,7 +30,7 @@ */ public class VariableSymbol extends CommonSymbol { public static final VariableSymbolKind KIND = new VariableSymbolKind(); - private final VariableType variableType; + private VariableType variableType; private BlockType blockType; private ASTExpr declaringExpression = null; @@ -184,6 +184,14 @@ public boolean isInInitialValues() { return blockType == BlockType.INITIAL_VALUES; } + public void markShape() { + this.variableType = VariableType.SHAPE; + } + + public boolean isShape() { + return variableType == VariableType.SHAPE; + } + public boolean isInternal() { return blockType == BlockType.INTERNALS; } diff --git a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java index e189e8ca6..6cb864acc 100644 --- a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java +++ b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java @@ -232,7 +232,7 @@ public void handle(final ASTEquationsBlock astOdeDeclaration) { astOdeDeclaration.getShapes().forEach(astShape -> printShape(astShape, printer)); astOdeDeclaration.getOdeFunctions().forEach(astOdeFunction -> printOdeFunctions(astOdeFunction, printer)); - astOdeDeclaration.getODEs().forEach(astEquation -> printEquation(astEquation, printer)); + astOdeDeclaration.getEquations().forEach(astEquation -> printEquation(astEquation, printer)); printer.unindent(); printer.println(BLOCK_CLOSE); diff --git a/src/main/java/org/nest/reporting/Reporter.java b/src/main/java/org/nest/reporting/Reporter.java index c4ac24230..0c676013d 100644 --- a/src/main/java/org/nest/reporting/Reporter.java +++ b/src/main/java/org/nest/reporting/Reporter.java @@ -85,16 +85,16 @@ public void printReports(final PrintStream info, final PrintStream err) { .filter(message -> message.severity.equals(Level.ERROR)) .findAny(); - info.println("----------------------------------------------------------"); - info.println("-----------------Execution summary------------------------"); + info.println("------------------------------------------------"); + if (error.isPresent()) { err.println(printFindingsAsJsonString()); - err.println("ERROR: Code generation was canceled."); + err.println("------------------FAILURE------------------------"); } else { - info.println("The model analysis and code generation were successfully executed."); + info.println("-----------------SUCCESS------------------------"); } - + info.println("------------------------------------------------"); } public void addNeuronReports( diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl index a48fc3797..7333f6473 100644 --- a/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl +++ b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl @@ -40,7 +40,7 @@ #include "${neuronName}.h" -<#assign stateSize = body.getEquations()?size> +<#assign stateSize = body.getInitialValuesSymbols()?size> /* ---------------------------------------------------------------- * Recordables map * ---------------------------------------------------------------- */ @@ -63,6 +63,9 @@ namespace nest <#list body.getParameterSymbols() as parameter> ${tc.includeArgs("org.nest.nestml.neuron.function.RecordCallback", [parameter])} + <#list body.getInitialValuesSymbols() as parameter> + ${tc.includeArgs("org.nest.nestml.neuron.function.RecordCallback", [parameter])} + <#list body.getODEAliases() as odeAlias> ${tc.includeArgs("org.nest.nestml.neuron.function.RecordCallback", [odeAlias])} @@ -135,6 +138,11 @@ ${neuronName}::${neuronName}():Archiving_Node(), P_(), S_(), B_(*this) ${tc.includeArgs("org.nest.nestml.neuron.function.MemberInitialization", [state, expressionsPrinter])} + <#list body.getInitialValuesSymbols() as initial_value> + ${tc.includeArgs("org.nest.nestml.neuron.function.MemberInitialization", [initial_value, expressionsPrinter])} + + + } ${neuronName}::${neuronName}(const ${neuronName}& __n): Archiving_Node(), P_(__n.P_), S_(__n.S_), B_(__n.B_, *this) diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl index f212dbc5a..7ec18f67e 100644 --- a/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl +++ b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl @@ -245,14 +245,14 @@ private: //! Symbolic indices to the elements of the state vector y enum StateVecElems { - <#list body.getOdeDefinedSymbols() as variable> + <#list body.getInitialValuesSymbols() as variable> ${names.convertToCPPName(variable.getName())}, ${variable.printComment("// ")} STATE_VEC_SIZE }; //! state vector, must be C-array for GSL solver - double y[ STATE_VEC_SIZE ]; - <#list body.getStateSymbolsWithoutOde() as variable> + double ode_state[ STATE_VEC_SIZE ]; + <#list body.getStateSymbols() as variable> ${tc.includeArgs("org.nest.nestml.neuron.function.MemberDeclaration", [variable])} @@ -345,6 +345,10 @@ private: ${tc.includeArgs("org.nest.nestml.neuron.function.MemberVariableGetterSetter", [state])} + <#list body.getInitialValuesSymbols() as initial_value> + ${tc.includeArgs("org.nest.nestml.neuron.function.MemberVariableGetterSetter", [initial_value])} + + <#list body.getParameterSymbols() as parameter> ${tc.includeArgs("org.nest.nestml.neuron.function.MemberVariableGetterSetter", [parameter])} diff --git a/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl b/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl index 3470597e9..20d0b90fa 100644 --- a/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl +++ b/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl @@ -5,17 +5,17 @@ @result C++ Function --> extern "C" inline int -${neuronName}_dynamics( double, const double y[], double f[], void* pnode ) +${neuronName}_dynamics( double, const double ode_state[], double f[], void* pnode ) { typedef ${neuronName}::State_ State_; // get access to node so we can almost work as in a member function assert( pnode ); const ${neuronName}& node = *( reinterpret_cast< ${neuronName}* >( pnode ) ); - // y[] here is---and must be---the state vector supplied by the integrator, - // not the state vector in the node, node.S_.y[]. + // ode_state[] here is---and must be---the state vector supplied by the integrator, + // not the state vector in the node, node.S_.ode_state[]. - <#list body.findEquationsBlock().get().getODEs() as ode> + <#list body.findEquationsBlock().get().getEquations() as ode> <#assign simpleOde = odeTransformer.replaceSumCalls(ode)> <#list astUtils.getAliasSymbols(ode) as function> <#if !function.isInEquation()> @@ -30,7 +30,7 @@ ${neuronName}_dynamics( double, const double y[], double f[], void* pnode ) double ${names.name(function)} = ${expressionsPrinterForGSL.print(declaringExpression)}; - <#list ast.variablesDefinedByODE() as odeVariable> + <#list ast.getInitialValuesSymbols() as odeVariable> <#assign simpleOde = odeTransformer.replaceSumCalls(odeVariable.getOdeDeclaration().get())> f[ ${names.arrayIndex(odeVariable)} ] = ${expressionsPrinterForGSL.print(simpleOde)}; diff --git a/src/main/resources/org/nest/nestml/neuron/function/MemberInitialization.ftl b/src/main/resources/org/nest/nestml/neuron/function/MemberInitialization.ftl index 61ee1cbb1..711186e03 100644 --- a/src/main/resources/org/nest/nestml/neuron/function/MemberInitialization.ftl +++ b/src/main/resources/org/nest/nestml/neuron/function/MemberInitialization.ftl @@ -6,7 +6,7 @@ variable is declared (inside a struct or in another method) --> ${signature("variable", "printer")} -<#if variable.getDeclaringExpression().isPresent()> +<#if variable.getDeclaringExpression().isPresent() && !variable.isShape()> <#if variable.isVector()> ${variableHelper.printOrigin(variable)}${names.name(variable)}.resize(P_.${variable.getVectorParameter().get()}, ${printer.print(variable.getDeclaringExpression().get())}); <#else> diff --git a/src/main/resources/org/nest/spl/small_statement/GSLIntegrator.ftl b/src/main/resources/org/nest/spl/small_statement/GSLIntegrator.ftl index 1863f796f..b54e7cd1e 100644 --- a/src/main/resources/org/nest/spl/small_statement/GSLIntegrator.ftl +++ b/src/main/resources/org/nest/spl/small_statement/GSLIntegrator.ftl @@ -25,7 +25,7 @@ while ( __t < B_.__step ) &__t, // from t B_.__step, // to t <= step &B_.__integration_step, // integration step size - S_.y); // neuronal state + S_.ode_state); // neuronal state if ( status != GSL_SUCCESS ) { throw nest::GSLSolverFailure( get_name(), status ); diff --git a/src/test/java/org/nest/codegeneration/sympy/ExactSolutionTransformerTest.java b/src/test/java/org/nest/codegeneration/sympy/ExactSolutionTransformerTest.java index 9028e7655..3d361afce 100644 --- a/src/test/java/org/nest/codegeneration/sympy/ExactSolutionTransformerTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/ExactSolutionTransformerTest.java @@ -67,7 +67,7 @@ public void testReplaceODEThroughMatrixMultiplication() { final ExactSolutionTransformer exactSolutionTransformer = new ExactSolutionTransformer(); // false abstraction level ASTNESTMLCompilationUnit modelRoot = parseNestmlModel(MODEL_FILE_PATH); - exactSolutionTransformer.replaceIntegrateCallThroughPropagation( + TransformerBase.replaceIntegrateCallThroughPropagation( modelRoot.getNeurons().get(0), Lists.newArrayList()); printModelToFile(modelRoot, TARGET_TMP_MODEL_PATH); diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index e03a0993d..fcf9046e3 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -120,7 +120,7 @@ def test_multysinapse(): models = list() - models.append( ("iaf_psc_alpha", "iaf_psc_alpha_neuron", None, 0.001)) + models.append( ("iaf_cond_alpha", "iaf_cond_alpha_implicit", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: From e13e22364445975922dd4b4daff67df2247835b4 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Tue, 19 Sep 2017 11:31:37 +0200 Subject: [PATCH 07/17] Fixes the shapetransformer, and the non-linear case transformer. --- models/iaf_cond_alpha.nestml | 58 +++++----- models/iaf_psc_alpha.nestml | 7 +- .../codegeneration/NestCodeGenerator.java | 2 + .../nest/codegeneration/sympy/AstCreator.java | 19 ++++ .../sympy/EquationsBlockProcessor.java | 58 +++------- .../sympy/ExactSolutionTransformer.java | 23 ++-- .../sympy/ShapesToOdesTransformer.java | 26 ++--- .../codegeneration/sympy/TransformerBase.java | 104 +++++++++--------- .../nest/nestml/_ast/ASTEquationsBlock.java | 55 --------- .../java/org/nest/nestml/_ast/ASTNeuron.java | 28 +++++ .../org/nest/nestml/_parser/NESTMLParser.java | 4 +- .../prettyprinter/NESTMLPrettyPrinter.java | 2 +- src/main/resources/org/nest/sympy/shapes.py | 4 +- .../codegeneration/sympy/SolverJsonData.java | 8 +- .../org/nest/frontend/NestmlFrontendTest.java | 3 +- src/test/resources/neuron_tester.py | 2 +- 16 files changed, 191 insertions(+), 212 deletions(-) delete mode 100644 src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java diff --git a/models/iaf_cond_alpha.nestml b/models/iaf_cond_alpha.nestml index c1c02c624..5682db94b 100644 --- a/models/iaf_cond_alpha.nestml +++ b/models/iaf_cond_alpha.nestml @@ -34,11 +34,11 @@ SeeAlso: iaf_cond_exp, iaf_cond_alpha_mc neuron iaf_cond_alpha_neuron: state: - r integer ## counts number of tick during the refractory period + r integer # counts number of tick during the refractory period end initial_values: - V_m mV = E_L ## membrane potential + V_m mV = E_L # membrane potential end equations: @@ -53,20 +53,17 @@ neuron iaf_cond_alpha_neuron: end parameters: - V_th mV = -55.0mV ## Threshold Potential in mV - V_reset mV = -60.0mV ## Reset Potential in mV - t_ref ms = 2.ms ## Refractory period in ms - g_L nS = 16.6667nS ## Leak Conductance in nS - C_m pF = 250.0 pF ## Membrane Capacitance in pF - E_ex mV = 0mV ## Excitatory reversal Potential in mV - E_in mV = -85.0mV ## Inhibitory reversal Potential in mV - E_L mV = -70.0mV ## Leak reversal Potential (aka resting potential) in mV - tau_syn_ex ms = 0.2ms ## Synaptic Time Constant Excitatory Synapse in ms - tau_syn_in ms = 2.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - I_e pA = 0pA ## Constant Current in pA - ## Input current injected by CurrentEvent. - ## This variable is used to transport the current applied into the - ## _dynamics function computing the derivative of the state vector. + V_th mV = -55.0mV # Threshold Potential in mV + V_reset mV = -60.0mV # Reset Potential in mV + t_ref ms = 2.ms # Refractory period in ms + g_L nS = 16.6667nS # Leak Conductance in nS + C_m pF = 250.0 pF # Membrane Capacitance in pF + E_ex mV = 0mV # Excitatory reversal Potential in mV + E_in mV = -85.0mV # Inhibitory reversal Potential in mV + E_L mV = -70.0mV # Leak reversal Potential (aka resting potential) in mV + tau_syn_ex ms = 0.2ms # Synaptic Time Constant Excitatory Synapse in ms + tau_syn_in ms = 2.0ms # Synaptic Time Constant for Inhibitory Synapse in ms + I_e pA = 0pA # Constant Current in pA end internals: @@ -95,7 +92,6 @@ neuron iaf_cond_alpha_neuron: end - /* Name: iaf_cond_alpha_implicit - Simple conductance based leaky integrate-and-fire neuron model. @@ -132,11 +128,11 @@ SeeAlso: iaf_cond_exp, iaf_cond_alpha_mc neuron iaf_cond_alpha_implicit: state: - r integer ## refractory counter + r integer # refractory counter end initial_values: - V_m mV = E_L ## membrane potential + V_m mV = E_L # membrane potential g_in nS = 0nS g_in' nS/ms = nS * e / tau_syn_in g_ex nS = 0nS @@ -158,21 +154,21 @@ neuron iaf_cond_alpha_implicit: end parameters: - V_th mV = -55.0mV ## Threshold Potential in mV - V_reset mV = -60.0mV ## Reset Potential in mV - t_ref ms = 2.0ms ## Refractory period in ms - g_L nS = 16.6667nS ## Leak Conductance in nS - C_m pF = 250.0pF ## Membrane Capacitance in pF - E_ex mV = 0mV ## Excitatory reversal Potential in mV - E_in mV = -85.0mV ## Inhibitory reversal Potential in mV - E_L mV = -70.0mV ## Leak reversal Potential (aka resting potential) in mV - tau_syn_ex ms = 0.2ms ## Synaptic Time Constant Excitatory Synapse in ms - tau_syn_in ms = 2.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - I_e pA = 0pA ## Constant Current in pA + V_th mV = -55.0mV # Threshold Potential in mV + V_reset mV = -60.0mV # Reset Potential in mV + t_ref ms = 2.0ms # Refractory period in ms + g_L nS = 16.6667nS # Leak Conductance in nS + C_m pF = 250.0pF # Membrane Capacitance in pF + E_ex mV = 0mV # Excitatory reversal Potential in mV + E_in mV = -85.0mV # Inhibitory reversal Potential in mV + E_L mV = -70.0mV # Leak reversal Potential (aka resting potential) in mV + tau_syn_ex ms = 0.2ms # Synaptic Time Constant Excitatory Synapse in ms + tau_syn_in ms = 2.0ms # Synaptic Time Constant for Inhibitory Synapse in ms + I_e pA = 0pA # Constant Current in pA end internals: - RefractoryCounts integer = steps(t_ref) ## refractory time in steps + RefractoryCounts integer = steps(t_ref) # refractory time in steps end input: diff --git a/models/iaf_psc_alpha.nestml b/models/iaf_psc_alpha.nestml index 2b1480772..796b5031b 100644 --- a/models/iaf_psc_alpha.nestml +++ b/models/iaf_psc_alpha.nestml @@ -75,9 +75,12 @@ SeeAlso: iaf_psc_delta, iaf_psc_exp, iaf_cond_exp neuron iaf_psc_alpha_neuron: state: - V_abs mV + r integer # counts number of tick during the refractory period + end + + initial_values: + V_abs mV = 0mV function V_m mV = V_abs + E_L # Membrane potential. - r integer # counts number of tick during the refractory period end equations: diff --git a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java index 9675213f3..dc7e5be6a 100644 --- a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java +++ b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java @@ -69,6 +69,8 @@ private void analyseAndGenerate( ASTNeuron workingVersion = deepCloneNeuronAndBuildSymbolTable(astNeuron, outputBase); workingVersion = solveOdesAndShapes(workingVersion, outputBase); + // this is the only way to get fresh symbol table now! + // TODO add functionality to refresh symboltable based on the commonvisitor workingVersion = AstUtils.deepCloneNeuronAndBuildSymbolTable(workingVersion, outputBase); generateNestCode(workingVersion, outputBase); diff --git a/src/main/java/org/nest/codegeneration/sympy/AstCreator.java b/src/main/java/org/nest/codegeneration/sympy/AstCreator.java index 729720af3..ce5f9ffa0 100644 --- a/src/main/java/org/nest/codegeneration/sympy/AstCreator.java +++ b/src/main/java/org/nest/codegeneration/sympy/AstCreator.java @@ -86,4 +86,23 @@ static public ASTBlockWithVariables createStateBlock() { return astVar_block; } + + static public ASTBlockWithVariables createInitialValuesBlock() { + final ASTBlockWithVariables astVar_block = NESTMLNodeFactory.createASTBlockWithVariables(); + astVar_block.setInitial_values(true); + + return astVar_block; + } + + public static ASTShape createShape(final String shapeAsString) { + + try { + // it is ok to call get, since otherwise it is an error in the file structure + return PARSER.parseShape(new StringReader(shapeAsString)).get(); + } + catch (IOException e) { + final String msg = "Cannot parse assignment statement."; + throw new RuntimeException(msg, e); + } + } } diff --git a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java index c9e7c3146..eaaefb0df 100644 --- a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java +++ b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.stream.Collectors; +import static org.nest.codegeneration.sympy.TransformerBase.applyIncomingSpikes; import static org.nest.utils.AstUtils.deepCloneNeuronAndBuildSymbolTable; /** @@ -41,15 +42,17 @@ public class EquationsBlockProcessor { * @return Transformed neuron with either: exact solution or transformed shapes to its ODE notation */ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path outputBase) { - if (astNeuron.findEquationsBlock().isPresent()) { + ASTNeuron workingVersion = astNeuron; + if (workingVersion.findEquationsBlock().isPresent()) { reporter.reportProgress(String.format("The neuron %s contains an ODE block. It will be analysed.", astNeuron.getName())); - final ASTNeuron deepCopy = deepCloneNeuronAndBuildSymbolTable(astNeuron, outputBase); + final ASTNeuron deepCopy = deepCloneNeuronAndBuildSymbolTable(workingVersion, outputBase); // this function is called only for neurons with an ode block. thus, retrieving it is safe. - if (deepCopy.findEquationsBlock().get().getShapes().size() > 0 && - !odeShapeExists(deepCopy.findEquationsBlock().get().getShapes()) && - deepCopy.findEquationsBlock().get().getEquations().size() == 1) { + if (workingVersion.findEquationsBlock().get().getShapes().size() > 0 && + !odeShapeExists(workingVersion.findEquationsBlock().get().getShapes()) && + workingVersion.findEquationsBlock().get().getEquations().size() == 1) { + // this uses the copy of the AST since the python generator changes the AST during the generation final SolverOutput solverOutput = evaluator.solveOdeWithShapes(deepCopy.findEquationsBlock().get(), outputBase); reporter.reportProgress("The model ODE with shapes will be analyzed."); reporter.reportProgress("The solver script is evaluated. Results are stored under " + outputBase.toString()); @@ -64,11 +67,13 @@ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path output switch (solverOutput.solver) { case "exact": reporter.reportProgress("Equations are solved exactly."); - return exactSolutionTransformer.addExactSolution(astNeuron, solverOutput); + workingVersion = exactSolutionTransformer.addExactSolution(workingVersion, solverOutput); + break; case "numeric": reporter.reportProgress("Shapes will be solved with GLS."); - return shapesToOdesTransformer.transformShapesToOdeForm(astNeuron, solverOutput); + workingVersion = shapesToOdesTransformer.transformShapesToOdeForm(astNeuron, solverOutput); + break; case "delta": return deltaSolutionTransformer.addExactSolution(solverOutput, astNeuron); @@ -76,49 +81,22 @@ public ASTNeuron solveOdeWithShapes(final ASTNeuron astNeuron, final Path output default: reporter.reportProgress(astNeuron.getName() + ": Equations or shapes could not be solved. The model remains unchanged."); - return astNeuron; + return workingVersion; } } - else if (deepCopy.findEquationsBlock().get().getShapes().size() > 0 && - !odeShapeExists(deepCopy.findEquationsBlock().get().getShapes())) { + else if (workingVersion.findEquationsBlock().get().getShapes().size() > 0 && + !odeShapeExists(workingVersion.findEquationsBlock().get().getShapes())) { reporter.reportProgress("Shapes will be solved with GLS."); final SolverOutput solverOutput = evaluator.solveShapes(deepCopy.findEquationsBlock().get().getShapes(), outputBase); - return shapesToOdesTransformer.transformShapesToOdeForm(astNeuron, solverOutput); + workingVersion = shapesToOdesTransformer.transformShapesToOdeForm(astNeuron, solverOutput); } } - - applyIncomingSpikes(astNeuron); - - return astNeuron; - } - - private void applyIncomingSpikes(ASTNeuron astNeuron) { reporter.reportProgress("Apply spikes to buffers..."); - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - final List convCalls = OdeTransformer.get_sumFunctionCalls(astNeuron); - final ExpressionsPrettyPrinter printer = new ExpressionsPrettyPrinter(); - - final List spikesUpdates = Lists.newArrayList(); - for (ASTFunctionCall convCall:convCalls) { - String shape = convCall.getArgs().get(0).getVariable().get().toString(); - String buffer = convCall.getArgs().get(1).getVariable().get().toString(); - - List shapeSymbols = astNeuron.getInitialValuesSymbols() - .stream() - .filter(variableSymbol -> variableSymbol.getName().matches(shape + "(')*")) - .collect(Collectors.toList()); - - spikesUpdates.addAll(shapeSymbols - .stream() - .map(shapeSymbol -> AstCreator.createAssignment( - shapeSymbol.getName() + " += " + buffer + " * " + printer.print(shapeSymbol.getDeclaringExpression().get()))) - .collect(Collectors.toList())); + applyIncomingSpikes(workingVersion); - } - final TransformerBase transformerBase = new TransformerBase(); - spikesUpdates.forEach(update -> transformerBase.addAssignmentToUpdateBlock(update, astNeuron)); + return astNeuron; } private boolean odeShapeExists(final List shapes) { diff --git a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java index 80cd24e74..793b5e994 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java @@ -19,6 +19,7 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; import static org.nest.codegeneration.sympy.AstCreator.createDeclaration; +import static org.nest.codegeneration.sympy.TransformerBase.computeShapeStateVariablesWithInitialValues; /** * Takes SymPy result with the linear solution of the ODE and the source AST. @@ -28,7 +29,6 @@ */ class ExactSolutionTransformer { - ASTNeuron addExactSolution( final ASTNeuron astNeuron, final SolverOutput solverOutput) { @@ -37,26 +37,31 @@ ASTNeuron addExactSolution( workingVersion = TransformerBase.addVariableToInternals(workingVersion, solverOutput.ode_var_factor); workingVersion = TransformerBase.addVariableToInternals(workingVersion, solverOutput.const_input); - workingVersion = TransformerBase.addVariablesToInternals(workingVersion, solverOutput.initial_values); workingVersion = TransformerBase.addVariablesToInternals(workingVersion, solverOutput.propagator_elements); - workingVersion = TransformerBase.addVariablesToState(workingVersion, solverOutput.shape_state_variables); + + final List> stateShapeVariablesWithInitialValues + = computeShapeStateVariablesWithInitialValues(solverOutput); + workingVersion = TransformerBase.addVariablesToInitialValues(workingVersion, stateShapeVariablesWithInitialValues); + workingVersion = addShapeStateUpdatesToUpdateBlock(workingVersion, solverOutput); + addStateUpdates(solverOutput, workingVersion); workingVersion.removeEquationsBlock(); - // oder is important, otherwise addShapeStateUpdatesToUpdateBlock will try to resolve state variables, - // for which nor symbol are added. TODO filter them - workingVersion = TransformerBase.replaceIntegrateCallThroughPropagation(workingVersion, solverOutput.ode_var_update_instructions); + workingVersion = TransformerBase.replaceIntegrateCallThroughPropagation( + workingVersion, + solverOutput.ode_var_update_instructions); return workingVersion; } private ASTNeuron addShapeStateUpdatesToUpdateBlock(final ASTNeuron astNeuron, final SolverOutput solverOutput) { - addStateUpdates(solverOutput, astNeuron); - TransformerBase.addShapeVariableUpdatesWithIncomingSpikes( + + + /*addShapeVariableUpdatesWithIncomingSpikes( solverOutput, astNeuron, TransformerBase.variableNameExtracter, - TransformerBase.shapeNameExtracter); + TransformerBase.shapeNameExtracter);*/ return astNeuron; } diff --git a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java index 7e0c2d32a..9f76e7bf0 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java @@ -5,15 +5,20 @@ */ package org.nest.codegeneration.sympy; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import org.nest.nestml._ast.ASTEquation; import org.nest.nestml._ast.ASTEquationsBlock; import org.nest.nestml._ast.ASTNeuron; +import org.nest.nestml._ast.ASTShape; +import java.util.HashMap; import java.util.List; import java.util.Map; import static com.google.common.base.Preconditions.checkArgument; import static java.util.stream.Collectors.toList; +import static org.nest.codegeneration.sympy.TransformerBase.computeShapeStateVariablesWithInitialValues; /** * Takes SymPy result with the implicit form of ODEs (e.g replace shapes through a series of ODES) and replaces @@ -26,28 +31,23 @@ class ShapesToOdesTransformer { ASTNeuron transformShapesToOdeForm(final ASTNeuron astNeuron, final SolverOutput solverOutput) { checkArgument(astNeuron.findEquationsBlock().isPresent()); - ASTNeuron workingVersion = TransformerBase.addVariablesToState(astNeuron, solverOutput.shape_state_variables); - workingVersion = TransformerBase.addVariablesToInternals(workingVersion, solverOutput.initial_values); - workingVersion = TransformerBase.removeShapes(workingVersion); - TransformerBase.addShapeVariableUpdatesWithIncomingSpikes( - solverOutput, - workingVersion, - TransformerBase.variableNameExtracter, - TransformerBase.shapeNameExtracter); + List> stateShapeVariablesWithInitialValues = computeShapeStateVariablesWithInitialValues(solverOutput); + ASTNeuron workingVersion = TransformerBase.addVariablesToInitialValues(astNeuron, stateShapeVariablesWithInitialValues); + // TODO actually, only shapes that are solved must be reseted + astNeuron.removeShapes(); addStateShapeEquationsToEquationsBlock(solverOutput.shape_state_odes, workingVersion.findEquationsBlock().get()); - return workingVersion; } private void addStateShapeEquationsToEquationsBlock( final List> equationsFile, final ASTEquationsBlock astOdeDeclaration) { - final List equations = equationsFile.stream() - .map(ode -> ode.getKey() + "' = " + ode.getValue()) - .map(AstCreator::createEquation) + final List astShapes = equationsFile.stream() + .map(ode -> "shape " + ode.getKey() + "' = " + ode.getValue()) + .map(AstCreator::createShape) .collect(toList()); - astOdeDeclaration.getEquations().addAll(equations); + astOdeDeclaration.getShapes().addAll(astShapes); } } diff --git a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java index 37ed35297..067eb0a1c 100644 --- a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java +++ b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java @@ -1,19 +1,23 @@ package org.nest.codegeneration.sympy; +import com.google.common.collect.Lists; import de.monticore.ast.ASTNode; import de.se_rwth.commons.logging.Log; import org.nest.nestml._ast.*; import org.nest.nestml._parser.NESTMLParser; import org.nest.nestml._symboltable.predefined.PredefinedFunctions; import org.nest.nestml._symboltable.symbols.VariableSymbol; +import org.nest.nestml.prettyprinter.ExpressionsPrettyPrinter; import org.nest.utils.AstUtils; import java.io.IOException; import java.io.StringReader; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkState; import static java.util.stream.Collectors.toList; @@ -105,7 +109,7 @@ static ASTNeuron addVariableToInternals( static ASTNeuron addVariablesToInitialValues( final ASTNeuron astNeuron, final List> declarationsFile) { - declarationsFile.forEach(declaration -> addVariableToInternals(astNeuron, declaration)); + declarationsFile.forEach(declaration -> addVariableToInitialValue(astNeuron, declaration)); return astNeuron; } @@ -124,9 +128,10 @@ static ASTNeuron addVariableToInitialValue( + " = " + declaration.getValue(); final ASTDeclaration astDeclaration = parser.parseDeclaration(new StringReader(declarationString)).get(); vectorVariable.ifPresent(var -> astDeclaration.setSizeParameter(var.getVectorParameter().get())); - //astNeuron.addToInitialValuesBlock(astDeclaration); - throw new RuntimeException(); - //return astNeuron; + astNeuron.addToInitialValuesBlock(astDeclaration); + + return astNeuron; + } catch (IOException e) { throw new RuntimeException("Must not fail by construction."); @@ -134,7 +139,6 @@ static ASTNeuron addVariableToInitialValue( } - static ASTNeuron replaceIntegrateCallThroughPropagation(final ASTNeuron astNeuron, List propagatorSteps) { // It must work for multiple integrate calls! final Optional integrateCall = AstUtils.getFunctionCall( @@ -172,70 +176,70 @@ static ASTNeuron replaceIntegrateCallThroughPropagation(final ASTNeuron astNeuro } - /** - * Add updates of state variables with the PSC initial value and corresponding inputs from buffers. - */ - static void addShapeVariableUpdatesWithIncomingSpikes( - final SolverOutput solverOutput, - final ASTNeuron body, - final Function stateVariableNameExtracter, - final Function shapeNameExtracter) { - final List i_sumCalls = OdeTransformer.get_sumFunctionCalls(body.findEquationsBlock().get()); - - final List pscInitialValues = solverOutput.initial_values - .stream() - .map(initialValue -> initialValue.getKey() + " real") - .map(AstCreator::createDeclaration) - .collect(toList()); - - for (final ASTDeclaration pscInitialValueDeclaration:pscInitialValues) { - final String pscInitialValue = pscInitialValueDeclaration.getVars().get(0).toString(); - - final String shapeName = shapeNameExtracter.apply(pscInitialValue); - final String shapeStateVariable = stateVariableNameExtracter.apply(pscInitialValue); - - for (ASTFunctionCall i_sum_call:i_sumCalls) { - final String shapeNameInCall = AstUtils.toString(i_sum_call.getArgs().get(0)); - if (shapeNameInCall.equals(shapeName)) { - final String bufferName = AstUtils.toString(i_sum_call.getArgs().get(1)); - final ASTAssignment pscUpdateStep = createAssignment( - shapeStateVariable + " += " + pscInitialValue + " * "+ bufferName); - addAssignmentToUpdateBlock(pscUpdateStep, body); + static void addDeclarationToUpdateBlock(final ASTDeclaration astDeclaration, final ASTNeuron astNeuron) { + final ASTStmt astStmt = NESTMLNodeFactory.createASTStmt(); + final ASTSmall_Stmt astSmall_stmt = NESTMLNodeFactory.createASTSmall_Stmt(); + + astStmt.setSmall_Stmt(astSmall_stmt); + + // Goal: add the y-assignments at the end of the expression + astSmall_stmt.setDeclaration(astDeclaration); + + astNeuron.getUpdateBlocks().get(0).getBlock().getStmts().add(astStmt); + } + + public static List> computeShapeStateVariablesWithInitialValues(SolverOutput solverOutput) { + List> stateShapeVariablesWithInitialValues = Lists.newArrayList(); + + for (final String shapeStateVariable : solverOutput.shape_state_variables) { + for (Map.Entry initialValue:solverOutput.initial_values) { + if (initialValue.getKey().endsWith(shapeStateVariable)) { + stateShapeVariablesWithInitialValues.add(new HashMap.SimpleEntry<>(shapeStateVariable, initialValue.getValue())); } } } - + return stateShapeVariablesWithInitialValues; } - static void addAssignmentToUpdateBlock(final ASTAssignment astAssignment, final ASTNeuron astNeuron) { - final ASTStmt astStmt = NESTMLNodeFactory.createASTStmt(); - final ASTSmall_Stmt astSmall_stmt = NESTMLNodeFactory.createASTSmall_Stmt(); + static void applyIncomingSpikes(final ASTNeuron astNeuron) { + final List convCalls = OdeTransformer.get_sumFunctionCalls(astNeuron); + final ExpressionsPrettyPrinter printer = new ExpressionsPrettyPrinter(); + + final List spikesUpdates = Lists.newArrayList(); + for (ASTFunctionCall convCall:convCalls) { + String shape = convCall.getArgs().get(0).getVariable().get().toString(); + String buffer = convCall.getArgs().get(1).getVariable().get().toString(); + + // variables could be added during the current transformation and, therefore, are not a part of the AST now. + // therefore they must be found on the AST level and not via SymbolTable + for (ASTDeclaration astDeclaration:astNeuron.getInitialValuesDeclarations()) { + for (ASTVariable variable:astDeclaration.getVars()) { + if (variable.toString().matches(shape + "(')*") || // handwritten models + variable.toString().matches(shape + "__\\d+$")) { // generated models + spikesUpdates.add(AstCreator.createAssignment( + variable.toString() + " += " + buffer + " * " + printer.print(astDeclaration.getExpr().get()))); + } - astStmt.setSmall_Stmt(astSmall_stmt); + } - // Goal: add the y-assignments at the end of the expression - astSmall_stmt.setAssignment(astAssignment); + } - astNeuron.getUpdateBlocks().get(0).getBlock().getStmts().add(astStmt); + } + spikesUpdates.forEach(update -> addAssignmentToUpdateBlock(update, astNeuron)); } - static void addDeclarationToUpdateBlock(final ASTDeclaration astDeclaration, final ASTNeuron astNeuron) { + + static void addAssignmentToUpdateBlock(final ASTAssignment astAssignment, final ASTNeuron astNeuron) { final ASTStmt astStmt = NESTMLNodeFactory.createASTStmt(); final ASTSmall_Stmt astSmall_stmt = NESTMLNodeFactory.createASTSmall_Stmt(); astStmt.setSmall_Stmt(astSmall_stmt); // Goal: add the y-assignments at the end of the expression - astSmall_stmt.setDeclaration(astDeclaration); + astSmall_stmt.setAssignment(astAssignment); astNeuron.getUpdateBlocks().get(0).getBlock().getStmts().add(astStmt); } - - static ASTNeuron removeShapes(ASTNeuron astNeuron) { - astNeuron.findEquationsBlock().get().getShapes().clear(); - return astNeuron; - } - } diff --git a/src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java b/src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java deleted file mode 100644 index 7476afb37..000000000 --- a/src/main/java/org/nest/nestml/_ast/ASTEquationsBlock.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ASTEquationsBlock.java - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * NEST 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with NEST. If not, see . - */ -package org.nest.nestml._ast; - -import org.nest.nestml._ast.ASTEquation; -import org.nest.nestml._ast.ASTEquationsBlockTOP; -import org.nest.nestml._ast.ASTOdeFunction; -import org.nest.nestml._ast.ASTShape; - -import java.util.List; - -/** - * HW extension for the ODE block. Provides getter method to get shapes and equations. - * - * @author plotnikov - */ -public class ASTEquationsBlock extends ASTEquationsBlockTOP { - public ASTEquationsBlock() { - - } - - public ASTEquationsBlock( - final ASTBLOCK_OPEN bLOCK_OPEN, - final List equations, - final List shapes, - final List oDEAliass, - final List nEWLINEs, - final ASTBLOCK_CLOSE bLOCK_CLOSE ) { - super(bLOCK_OPEN, equations, shapes, oDEAliass, nEWLINEs, bLOCK_CLOSE); - } - - @Override - public List getShapes() { - return shapes; - } - -} diff --git a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java index a36af6596..3efbec6c2 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java +++ b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java @@ -153,6 +153,16 @@ public List getStateSymbols() { } + public List getInitialValuesDeclarations() { + Optional initialValuesBlock = getBlockWithVariabless() + .stream() + .filter(ASTBlockWithVariables::isInitial_values) + .findFirst(); + final List initialValuesDeclarations = Lists.newArrayList(); + initialValuesBlock.ifPresent(block -> initialValuesDeclarations.addAll(block.getDeclarations())); + return initialValuesDeclarations; + } + public List getInitialValuesSymbols() { return this.getSpannedScope().get().resolveLocally(VariableSymbol.KIND) .stream() @@ -258,6 +268,20 @@ public void addToInternalBlock(final ASTDeclaration astDeclaration) { } + public void addToInitialValuesBlock(ASTDeclaration astDeclaration) { + if (!this.getInternalBlock().isPresent()) { + final ASTBlockWithVariables internalBlock = AstCreator.createInitialValuesBlock(); + getBlockWithVariabless().add(internalBlock); + } + + this.getBlockWithVariabless().forEach(block -> { + if (block.isInitial_values()) { + block.getDeclarations().add(astDeclaration); + } + + }); + } + public void addToStateBlock(final ASTDeclaration astDeclaration) { if (!this.getInternalBlock().isPresent()) { final ASTBlockWithVariables stateBlock = AstCreator.createStateBlock(); @@ -340,4 +364,8 @@ public boolean isArrayBuffer() { .anyMatch(VariableSymbol::isVector); } + public void removeShapes() { + this.findEquationsBlock().get().getShapes().clear(); + } + } diff --git a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java index b9f056ee4..c38fa05af 100644 --- a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java +++ b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java @@ -69,7 +69,7 @@ public Optional parseNESTMLCompilationUnit(final Strin */ private List extractComments(final List sourceText, int lineIndex) { final List result = Lists.newArrayList(); - String DOC_STRING_START = "##"; + String DOC_STRING_START = "#"; if (sourceText.get(lineIndex).contains(DOC_STRING_START)) { result.add(sourceText.get(lineIndex).substring(sourceText.get(lineIndex).indexOf(DOC_STRING_START)).trim()); } @@ -90,7 +90,7 @@ private List extractComments(final List sourceText, int lineInde while (searchForwardIndex < sourceText.size()) { final String currentLine = sourceText.get(searchForwardIndex); if (currentLine.trim().startsWith(DOC_STRING_START)) { - result.add(currentLine.substring(currentLine.indexOf(DOC_STRING_START) + 1).trim()); + result.add(currentLine.substring(currentLine.indexOf(DOC_STRING_START) ).trim()); } else { break; diff --git a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java index 6cb864acc..6fe660907 100644 --- a/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java +++ b/src/main/java/org/nest/nestml/prettyprinter/NESTMLPrettyPrinter.java @@ -247,7 +247,7 @@ private void printShape(final ASTShape shape, final IndentPrinter printer) { } /** - * This method is used in freemaker template. Therefore, it must remain public. + * This method is used in freemarker template. Therefore, it must remain public. */ public String printShape(final ASTShape astShape) { return "shape " + astShape.getLhs() + " = " + expressionsPrinter.print(astShape.getRhs()); diff --git a/src/main/resources/org/nest/sympy/shapes.py b/src/main/resources/org/nest/sympy/shapes.py index 033e81e49..9560b58e8 100644 --- a/src/main/resources/org/nest/sympy/shapes.py +++ b/src/main/resources/org/nest/sympy/shapes.py @@ -294,9 +294,9 @@ def get_initial_values(self): result = [] for idx, initial_value in enumerate(self.initial_values): if idx > 0: - p = {"iv__" + str(self.name) + "__" + str(idx): str(initial_value)} + p = {str(self.name) + "__" + str(idx): str(initial_value)} else: - p = {"iv__" + str(self.name): str(initial_value)} + p = {str(self.name): str(initial_value)} result = [p] + result return result diff --git a/src/test/java/org/nest/codegeneration/sympy/SolverJsonData.java b/src/test/java/org/nest/codegeneration/sympy/SolverJsonData.java index fb20cee04..49e58bcbf 100644 --- a/src/test/java/org/nest/codegeneration/sympy/SolverJsonData.java +++ b/src/test/java/org/nest/codegeneration/sympy/SolverJsonData.java @@ -29,16 +29,16 @@ public class SolverJsonData { "\"status\": \"success\", \n" + " \"initial_values\": [\n" + " {\n" + - " \"iv__I_shape_in__0\": \"0\"\n" + + " \"I_shape_in__0\": \"0\"\n" + " }, \n" + " {\n" + - " \"iv__I_shape_in__1\": \"e*pA/tau_syn_in\"\n" + + " \"I_shape_in__1\": \"e*pA/tau_syn_in\"\n" + " }, \n" + " {\n" + - " \"iv__I_shape_ex__0\": \"0\"\n" + + " \"I_shape_ex__0\": \"0\"\n" + " }, \n" + " {\n" + - " \"iv__I_shape_ex__1\": \"e*pA/tau_syn_ex\"\n" + + " \"I_shape_ex__1\": \"e*pA/tau_syn_ex\"\n" + " }\n" + " ], \n" + " \"solver\": \"exact\", \n" + diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index c82cf9e5e..e578bdd42 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -127,9 +127,8 @@ public void testTutorialModels() { @Test public void manually() { final String[] args = new String[] { - "models/iaf_cond_alpha.nestml", + "models/iaf_psc_alpha.nestml", "--json_log", "model_issues", - "--enable_tracing", "--target", outputPath.toString()}; new NestmlFrontend().start(args); diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index fcf9046e3..c3be75df6 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -120,7 +120,7 @@ def test_multysinapse(): models = list() - models.append( ("iaf_cond_alpha", "iaf_cond_alpha_implicit", None, 0.001)) + models.append( ("iaf_cond_alpha_implicit", "iaf_cond_alpha_neuron", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: From 613d22c10d6a0e292cc142a9f955c1c3c9585a82 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Wed, 20 Sep 2017 16:49:41 +0200 Subject: [PATCH 08/17] Adopts several neuron models to the new syntax with initial models. The codegenerator better distinguishes between different constelations of ODEs. The code generator applies the spikes from buffers to shape variables more relaibly. --- models/aeif_cond_alpha.nestml | 136 ++++++++---------- models/aeif_cond_exp.nestml | 17 +-- models/hh_cond_exp_traub.nestml | 1 - pom.xml | 1 + src/main/grammars/org/nest/NESTML.mc4 | 67 +++++---- .../codegeneration/NestCodeGenerator.java | 8 +- .../sympy/EquationsBlockProcessor.java | 7 +- .../sympy/ExactSolutionTransformer.java | 40 +++--- .../sympy/ShapesToOdesTransformer.java | 4 + .../java/org/nest/nestml/_ast/ASTNeuron.java | 16 +-- .../_symboltable/symbols/VariableSymbol.java | 2 +- .../org/nest/nestml/neuron/NeuronHeader.ftl | 4 + .../org/nest/frontend/NestmlFrontendTest.java | 2 +- src/test/resources/logback-test.xml | 2 +- src/test/resources/neuron_tester.py | 67 +-------- 15 files changed, 157 insertions(+), 217 deletions(-) diff --git a/models/aeif_cond_alpha.nestml b/models/aeif_cond_alpha.nestml index 79183dab4..f4b296b9f 100644 --- a/models/aeif_cond_alpha.nestml +++ b/models/aeif_cond_alpha.nestml @@ -32,9 +32,9 @@ SeeAlso: iaf_cond_alpha, aeif_cond_exp */ neuron aeif_cond_alpha_neuron: - state: - V_m mV = E_L ## Membrane potential - w pA = 0pA ## Spike-adaptation current + initial_values: + V_m mV = E_L # Membrane potential + w pA = 0pA # Spike-adaptation current end equations: @@ -42,7 +42,7 @@ neuron aeif_cond_alpha_neuron: shape g_in = (e/tau_syn_in) * t * exp(-t/tau_syn_in) shape g_ex = (e/tau_syn_ex) * t * exp(-t/tau_syn_ex) - ## Add functions to simplify the equation definition of V_m + # Add functions to simplify the equation definition of V_m function exp_arg real = (V_bounded-V_th)/Delta_T function I_spike pA = g_L*Delta_T*exp(exp_arg) function I_syn_exc pA = cond_sum(g_ex, spikesExc) * ( V_bounded - E_ex ) @@ -55,46 +55,45 @@ neuron aeif_cond_alpha_neuron: parameters: # membrane parameters - C_m pF = 281.0pF ## Membrane Capacitance in pF - t_ref ms = 0.0ms ## Refractory period in ms - V_reset mV = -60.0mV ## Reset Potential in mV - g_L nS = 30.0nS ## Leak Conductance in nS - E_L mV = -70.6mV ## Leak reversal Potential (aka resting potential) in mV - I_e pA = 0pA ## Constant Current in pA + C_m pF = 281.0pF # Membrane Capacitance in pF + t_ref ms = 0.0ms # Refractory period in ms + V_reset mV = -60.0mV # Reset Potential in mV + g_L nS = 30.0nS # Leak Conductance in nS + E_L mV = -70.6mV # Leak reversal Potential (aka resting potential) in mV + I_e pA = 0pA # Constant Current in pA # spike adaptation parameters - a nS = 4nS ## Subthreshold adaptation - b pA = 80.5pA ## pike-triggered adaptation - Delta_T mV = 2.0mV ## Slope factor - tau_w ms = 144.0ms ## Adaptation time constant - V_th mV = -50.4mV ## Threshold Potential in mV - V_peak mV = 0mV ## Spike detection threshold + a nS = 4nS # Subthreshold adaptation + b pA = 80.5pA # pike-triggered adaptation + Delta_T mV = 2.0mV # Slope factor + tau_w ms = 144.0ms # Adaptation time constant + V_th mV = -50.4mV # Threshold Potential in mV + V_peak mV = 0mV # Spike detection threshold # synaptic parameters - E_ex mV = 0mV ## Excitatory reversal Potential in mV - tau_syn_ex ms = 0.2ms ## Synaptic Time Constant Excitatory Synapse in ms - E_in mV = -85.0mV ## Inhibitory reversal Potential in mV - tau_syn_in ms = 2.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - - ## Input current injected by CurrentEvent. - ## This variable is used to transport the current applied into the - ## _dynamics function computing the derivative of the state vector. + E_ex mV = 0mV # Excitatory reversal Potential in mV + tau_syn_ex ms = 0.2ms # Synaptic Time Constant Excitatory Synapse in ms + E_in mV = -85.0mV # Inhibitory reversal Potential in mV + tau_syn_in ms = 2.0ms # Synaptic Time Constant for Inhibitory Synapse in ms + + # Input current injected by CurrentEvent. + # This variable is used to transport the current applied into the + # _dynamics function computing the derivative of the state vector. I_stim pA = 0pA end internals: - - ## Impulse to add to DG_EXC on spike arrival to evoke unit-amplitude - ## conductance excursion. + # Impulse to add to DG_EXC on spike arrival to evoke unit-amplitude + # conductance excursion. PSConInit_E nS/ms = nS * e / tau_syn_ex - ## Impulse to add to DG_INH on spike arrival to evoke unit-amplitude - ## conductance excursion. + # Impulse to add to DG_INH on spike arrival to evoke unit-amplitude + # conductance excursion. PSConInit_I nS/ms = nS * e / tau_syn_in - ## refractory time in steps + # refractory time in steps RefractoryCounts integer = steps(t_ref) - ## counts number of tick during the refractory period + # counts number of tick during the refractory period r integer end @@ -119,7 +118,6 @@ neuron aeif_cond_alpha_neuron: emit_spike() end - end end @@ -159,24 +157,27 @@ SeeAlso: iaf_cond_alpha, aeif_cond_exp neuron aeif_cond_alpha_implicit: state: - V_m mV = E_L ## Membrane potential - w pA = 0 pA ## Spike-adaptation current - g_in nS = 0 nS ## Excitatory synaptic conductance - g_in' nS/mS = 0 nS/ms ## Excitatory synaptic conductance - g_ex nS = 0 nS ## Inhibitory synaptic conductance in nS - g_ex' nS/mS = 0 nS/ms ## Inhibitory synaptic conductance in nS - r integer ## counts number of tick during the refractory period + r integer # counts number of tick during the refractory period + end + + initial_values: + V_m mV = E_L # Membrane potential + w pA = 0 pA # Spike-adaptation current + g_in nS = 0 nS # Excitatory synaptic conductance + g_in' nS/mS = nS * e / tau_syn_in # Excitatory synaptic conductance + g_ex nS = 0 nS # Inhibitory synaptic conductance in nS + g_ex' nS/mS = nS * e / tau_syn_ex # Inhibitory synaptic conductance in nS end equations: function V_bounded mV = min(V_m, V_peak) # prevent exponential divergence - ## alpha function for the g_in - g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in - g_in' = g_in' + # alpha function for the g_in + shape g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in + shape g_in' = g_in' - ## alpha function for the g_ex - g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex - g_ex' = g_ex' + # alpha function for the g_ex + shape g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex + shape g_ex' = g_ex' # Add aliases to simplify the equation definition of V_m function exp_arg real = (V_bounded-V_th)/Delta_T @@ -190,39 +191,30 @@ neuron aeif_cond_alpha_implicit: parameters: # membrane parameters - C_m pF = 281.0 pF ## Membrane Capacitance in pF - t_ref ms = 0.0 ms ## Refractory period in ms - V_reset mV = -60.0 mV ## Reset Potential in mV - g_L nS = 30.0 nS ## Leak Conductance in nS - E_L mV = -70.6 mV ## Leak reversal Potential (aka resting potential) in mV - I_e pA = 0 pA ## Constant Current in pA + C_m pF = 281.0 pF # Membrane Capacitance in pF + t_ref ms = 0.0 ms # Refractory period in ms + V_reset mV = -60.0 mV # Reset Potential in mV + g_L nS = 30.0 nS # Leak Conductance in nS + E_L mV = -70.6 mV # Leak reversal Potential (aka resting potential) in mV + I_e pA = 0 pA # Constant Current in pA # spike adaptation parameters - a nS = 4 nS ## Subthreshold adaptation - b pA = 80.5 pA ## pike-triggered adaptation - Delta_T mV = 2.0 mV ## Slope factor - tau_w ms = 144.0 ms ## Adaptation time constant - V_th mV = -50.4 mV ## Threshold Potential in mV - V_peak mV = 0 mV ## Spike detection threshold + a nS = 4 nS # Subthreshold adaptation + b pA = 80.5 pA # pike-triggered adaptation + Delta_T mV = 2.0 mV # Slope factor + tau_w ms = 144.0 ms # Adaptation time constant + V_th mV = -50.4 mV # Threshold Potential in mV + V_peak mV = 0 mV # Spike detection threshold # synaptic parameters - E_ex mV = 0 mV ## Excitatory reversal Potential in mV - tau_syn_ex ms = 0.2 ms ## Synaptic Time Constant Excitatory Synapse in ms - E_in mV = -85.0 mV ## Inhibitory reversal Potential in mV - tau_syn_in ms = 2.0 ms ## Synaptic Time Constant for Inhibitory Synapse in ms + E_ex mV = 0 mV # Excitatory reversal Potential in mV + tau_syn_ex ms = 0.2 ms # Synaptic Time Constant Excitatory Synapse in ms + E_in mV = -85.0 mV # Inhibitory reversal Potential in mV + tau_syn_in ms = 2.0 ms # Synaptic Time Constant for Inhibitory Synapse in ms end internals: - - ## Impulse to add to DG_EXC on spike arrival to evoke unit-amplitude - ## conductance excursion. - PSConInit_E nS/ms = nS * e / tau_syn_ex - - ## Impulse to add to DG_INH on spike arrival to evoke unit-amplitude - ## conductance excursion. - PSConInit_I nS/ms = nS * e / tau_syn_in - - ## refractory time in steps + # refractory time in steps RefractoryCounts integer = steps(t_ref) end @@ -247,8 +239,6 @@ neuron aeif_cond_alpha_implicit: emit_spike() end - g_ex' += spikesExc * PSConInit_E - g_in' += spikesInh * PSConInit_I end end diff --git a/models/aeif_cond_exp.nestml b/models/aeif_cond_exp.nestml index 8a7f7bfaa..4d4055c29 100644 --- a/models/aeif_cond_exp.nestml +++ b/models/aeif_cond_exp.nestml @@ -35,7 +35,7 @@ SeeAlso: iaf_cond_alpha, aeif_cond_exp */ neuron aeif_cond_exp_neuron: - state: + initial_values: V_m mV = E_L # Membrane potential w pA = 0 pA # Spike-adaptation current end @@ -153,18 +153,21 @@ SeeAlso: iaf_cond_alpha, aeif_cond_exp neuron aeif_cond_exp_implicit: state: + r integer # counts number of tick during the refractory period + end + + initial_values: V_m mV = E_L # Membrane potential w pA = 0pA # Spike-adaptation current - g_in nS = 0nS # Inhibitory synaptic conductance - g_ex nS = 0nS # Excitatory synaptic conductance - r integer # counts number of tick during the refractory period + g_in nS = 1nS # Inhibitory synaptic conductance + g_ex nS = 1nS # Excitatory synaptic conductance end equations: function V_bounded mV = min(V_m, V_peak) # prevent exponential divergence # exp function for the g_in, g_ex - g_in' = -g_in/tau_syn_in - g_ex' = -g_ex/tau_syn_ex + shape g_in' = -g_in/tau_syn_in + shape g_ex' = -g_ex/tau_syn_ex # Add aliases to simplify the equation definition of V_m function exp_arg real = (V_bounded-V_th)/Delta_T @@ -226,8 +229,6 @@ neuron aeif_cond_exp_implicit: emit_spike() end - g_ex += spikeExc * nS - g_in += spikeInh * nS end end diff --git a/models/hh_cond_exp_traub.nestml b/models/hh_cond_exp_traub.nestml index bcb17b725..8897dc255 100644 --- a/models/hh_cond_exp_traub.nestml +++ b/models/hh_cond_exp_traub.nestml @@ -51,7 +51,6 @@ neuron hh_cond_exp_traub_neuron: Inact_n real = alpha_n_init / ( alpha_n_init + beta_n_init ) r integer # counts number of tick during the refractory period - end equations: diff --git a/pom.xml b/pom.xml index e69d9370e..656afa7ad 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,7 @@ ${monticore.version} false + diff --git a/src/main/grammars/org/nest/NESTML.mc4 b/src/main/grammars/org/nest/NESTML.mc4 index d2740aa8b..88f1cda95 100644 --- a/src/main/grammars/org/nest/NESTML.mc4 +++ b/src/main/grammars/org/nest/NESTML.mc4 @@ -12,9 +12,7 @@ package org.nest; grammar NESTML extends org.nest.Literals { /** ASTNESTMLCompilationUnit represents the complete entire file with neuron and component models. - @attribute packageName The qualified name to artifact - @attribute Import List of imported elements - @attribute Neuron The neuron representation + @attribute Neuron The neuron representation */ NESTMLCompilationUnit = (Neuron | NEWLINE)* EOF; @@ -38,6 +36,7 @@ grammar NESTML extends org.nest.Literals { | ["boolean"] | ["void"] | UnitType; + /** ASTUnitType. Represents an unit datatype. It can be a plain datatype as 'mV' or a complex data type as 'mV/s' @@ -52,32 +51,32 @@ grammar NESTML extends org.nest.Literals { * Expressions-Language *********************************************************************************************************************/ Expr = leftParentheses:["("] Expr rightParentheses:[")"] - | base:Expr pow:["**"] exponent:Expr - | (unaryPlus:["+"] | unaryMinus:["-"] | unaryTilde:["~"]) term:Expr - | left:Expr (timesOp:["*"] | divOp:["/"] | moduloOp:["%"]) right:Expr - | left:Expr (plusOp:["+"] | minusOp:["-"]) right:Expr - | left:Expr (shiftLeft:["<<"] | shiftRight:[">>"]) right:Expr - | left:Expr bitAnd:["&"] right:Expr - | left:Expr bitXor:["^"] right:Expr - | left:Expr bitOr:["|"] right:Expr - | left:Expr (lt:["<"] | - le:["<="] | - eq:["=="] | - ne:["!="] | - ne2:["<>"] | - ge:[">="] | - gt:[">"]) right:Expr - | logicalNot:["not"] Expr - | left:Expr logicalAnd:["and"] right:Expr - | left:Expr logicalOr:["or"] right:Expr - | condition:Expr "?" ifTrue:Expr ":" ifNot:Expr - | FunctionCall - | BooleanLiteral // true & false; - | NumericLiteral Variable - | NumericLiteral - | StringLiteral - | ["inf"] - | Variable; + | base:Expr pow:["**"] exponent:Expr + | (unaryPlus:["+"] | unaryMinus:["-"] | unaryTilde:["~"]) term:Expr + | left:Expr (timesOp:["*"] | divOp:["/"] | moduloOp:["%"]) right:Expr + | left:Expr (plusOp:["+"] | minusOp:["-"]) right:Expr + | left:Expr (shiftLeft:["<<"] | shiftRight:[">>"]) right:Expr + | left:Expr bitAnd:["&"] right:Expr + | left:Expr bitXor:["^"] right:Expr + | left:Expr bitOr:["|"] right:Expr + | left:Expr (lt:["<"] | + le:["<="] | + eq:["=="] | + ne:["!="] | + ne2:["<>"] | + ge:[">="] | + gt:[">"]) right:Expr + | logicalNot:["not"] Expr + | left:Expr logicalAnd:["and"] right:Expr + | left:Expr logicalOr:["or"] right:Expr + | condition:Expr "?" ifTrue:Expr ":" ifNot:Expr + | FunctionCall + | BooleanLiteral // true & false; + | NumericLiteral Variable + | NumericLiteral + | StringLiteral + | ["inf"] + | Variable; /** ASTVariable Provides a 'marker' AST node to identify variables used in expressions. @@ -131,7 +130,6 @@ grammar NESTML extends org.nest.Literals { compoundProduct:["*="] | compoundQuotient:["/="]) Expr; - /** ASTDeclaration A variable declaration. It can be a simple declaration defining one or multiple variables: 'a,b,c real = 0'. Or an function declaration 'function a = b + c'. @attribute hide is true iff. declaration is not trackable. @@ -172,7 +170,6 @@ grammar NESTML extends org.nest.Literals { WHILE_Stmt = "while" Expr BLOCK_OPEN Block BLOCK_CLOSE; - /********************************************************************************************************************* * Nestml-Language *********************************************************************************************************************/ @@ -235,10 +232,10 @@ grammar NESTML extends org.nest.Literals { BLOCK_CLOSE; /** ASTInput represents the input block: - input: - spikeBuffer <- inhibitory excitatory spike - currentBuffer <- current - end + input: + spikeBuffer <- inhibitory excitatory spike + currentBuffer <- current + end @attribute inputLine set of input lines. */ diff --git a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java index dc7e5be6a..be30b56bb 100644 --- a/src/main/java/org/nest/codegeneration/NestCodeGenerator.java +++ b/src/main/java/org/nest/codegeneration/NestCodeGenerator.java @@ -8,18 +8,18 @@ import de.monticore.generating.GeneratorEngine; import de.monticore.generating.GeneratorSetup; import de.monticore.generating.templateengine.GlobalExtensionManagement; -import org.nest.codegeneration.converters.*; +import org.nest.codegeneration.converters.GslReferenceConverter; +import org.nest.codegeneration.converters.NESTReferenceConverter; import org.nest.codegeneration.helpers.*; import org.nest.codegeneration.sympy.EquationsBlockProcessor; import org.nest.codegeneration.sympy.OdeTransformer; -import org.nest.nestml._ast.ASTNeuron; -import org.nest.nestml._ast.ASTNESTMLCompilationUnit; import org.nest.nestml._ast.ASTEquationsBlock; +import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._ast.ASTNeuron; import org.nest.nestml._ast.ASTShape; import org.nest.nestml._symboltable.NESTMLLanguage; import org.nest.nestml._symboltable.NestmlSymbols; import org.nest.nestml.prettyprinter.ExpressionsPrettyPrinter; -import org.nest.nestml.prettyprinter.IReferenceConverter; import org.nest.nestml.prettyprinter.LegacyExpressionPrinter; import org.nest.reporting.Reporter; import org.nest.utils.AstUtils; diff --git a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java index eaaefb0df..ebb495aea 100644 --- a/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java +++ b/src/main/java/org/nest/codegeneration/sympy/EquationsBlockProcessor.java @@ -91,12 +91,13 @@ else if (workingVersion.findEquationsBlock().get().getShapes().size() > 0 && workingVersion = shapesToOdesTransformer.transformShapesToOdeForm(astNeuron, solverOutput); } + else { + applyIncomingSpikes(workingVersion); + } } - reporter.reportProgress("Apply spikes to buffers..."); - applyIncomingSpikes(workingVersion); - return astNeuron; + return workingVersion; } private boolean odeShapeExists(final List shapes) { diff --git a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java index 793b5e994..33141bb0e 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java @@ -19,7 +19,7 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; import static org.nest.codegeneration.sympy.AstCreator.createDeclaration; -import static org.nest.codegeneration.sympy.TransformerBase.computeShapeStateVariablesWithInitialValues; +import static org.nest.codegeneration.sympy.TransformerBase.*; /** * Takes SymPy result with the linear solution of the ODE and the source AST. @@ -35,35 +35,39 @@ ASTNeuron addExactSolution( ASTNeuron workingVersion = astNeuron; workingVersion.addToInternalBlock(createDeclaration("__h ms = resolution()")); - workingVersion = TransformerBase.addVariableToInternals(workingVersion, solverOutput.ode_var_factor); - workingVersion = TransformerBase.addVariableToInternals(workingVersion, solverOutput.const_input); - workingVersion = TransformerBase.addVariablesToInternals(workingVersion, solverOutput.propagator_elements); + workingVersion = addVariableToInternals(workingVersion, solverOutput.ode_var_factor); + workingVersion = addVariableToInternals(workingVersion, solverOutput.const_input); + workingVersion = addVariablesToInternals(workingVersion, solverOutput.propagator_elements); - final List> stateShapeVariablesWithInitialValues - = computeShapeStateVariablesWithInitialValues(solverOutput); - workingVersion = TransformerBase.addVariablesToInitialValues(workingVersion, stateShapeVariablesWithInitialValues); + final List> stateShapeVariablesWithInitialValues = + computeShapeStateVariablesWithInitialValues(solverOutput); - workingVersion = addShapeStateUpdatesToUpdateBlock(workingVersion, solverOutput); + // copy initial block variables to the state block, since they are not backed through an ODE. + astNeuron.getInitialValuesDeclarations() + .forEach(astNeuron::addToStateBlock); + + workingVersion = addVariablesToInitialValues(workingVersion, stateShapeVariablesWithInitialValues); addStateUpdates(solverOutput, workingVersion); - workingVersion.removeEquationsBlock(); workingVersion = TransformerBase.replaceIntegrateCallThroughPropagation( workingVersion, solverOutput.ode_var_update_instructions); - return workingVersion; - } + applyIncomingSpikes(workingVersion); - private ASTNeuron addShapeStateUpdatesToUpdateBlock(final ASTNeuron astNeuron, final SolverOutput solverOutput) { + // get rid of the ODE stuff since the model is solved exactly and all ODEs are removed. + workingVersion.removeEquationsBlock(); + stateShapeVariablesWithInitialValues + .stream() + .map(Map.Entry::getKey) + .map(shapeStateVariable -> createDeclaration(shapeStateVariable + " real")) + .forEach(astNeuron::addToStateBlock); - /*addShapeVariableUpdatesWithIncomingSpikes( - solverOutput, - astNeuron, - TransformerBase.variableNameExtracter, - TransformerBase.shapeNameExtracter);*/ + workingVersion.getInitialValuesBlock().ifPresent(block -> block.getDeclarations().clear()); - return astNeuron; + // since there is no + return workingVersion; } private void addStateUpdates(final SolverOutput solverOutput, final ASTNeuron astNeuron) { diff --git a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java index 9f76e7bf0..87780405b 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ShapesToOdesTransformer.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.util.stream.Collectors.toList; +import static org.nest.codegeneration.sympy.TransformerBase.applyIncomingSpikes; import static org.nest.codegeneration.sympy.TransformerBase.computeShapeStateVariablesWithInitialValues; /** @@ -36,7 +37,10 @@ ASTNeuron transformShapesToOdeForm(final ASTNeuron astNeuron, final SolverOutput // TODO actually, only shapes that are solved must be reseted astNeuron.removeShapes(); + addStateShapeEquationsToEquationsBlock(solverOutput.shape_state_odes, workingVersion.findEquationsBlock().get()); + applyIncomingSpikes(workingVersion); + return workingVersion; } diff --git a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java index 3efbec6c2..2dc0d0a0f 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java +++ b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java @@ -154,15 +154,19 @@ public List getStateSymbols() { } public List getInitialValuesDeclarations() { - Optional initialValuesBlock = getBlockWithVariabless() - .stream() - .filter(ASTBlockWithVariables::isInitial_values) - .findFirst(); + Optional initialValuesBlock = getInitialValuesBlock(); final List initialValuesDeclarations = Lists.newArrayList(); initialValuesBlock.ifPresent(block -> initialValuesDeclarations.addAll(block.getDeclarations())); return initialValuesDeclarations; } + public Optional getInitialValuesBlock() { + return getBlockWithVariabless() + .stream() + .filter(ASTBlockWithVariables::isInitial_values) + .findFirst(); + } + public List getInitialValuesSymbols() { return this.getSpannedScope().get().resolveLocally(VariableSymbol.KIND) .stream() @@ -297,10 +301,6 @@ public void addToStateBlock(final ASTDeclaration astDeclaration) { } - private Optional findDynamics() { - return this.getUpdateBlocks().stream().findFirst(); - } - public List getInputLines() { List result = Lists.newArrayList(); diff --git a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java index 880613bc5..2563a1782 100644 --- a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java +++ b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java @@ -242,7 +242,7 @@ public String printComment(final String prefix) { final StringBuffer output = new StringBuffer(); if(getAstNode().isPresent() && getAstNode().get() instanceof ASTDeclaration) { final ASTDeclaration astDeclaration = (ASTDeclaration) getAstNode().get(); - astDeclaration.getDocStrings().forEach(comment -> output.append(prefix).append(" ").append(comment)); + astDeclaration.getDocStrings().forEach(comment -> output.append(prefix).append(" ").append(comment).append("\n")); } return output.toString(); diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl index 7ec18f67e..6ce7d09a8 100644 --- a/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl +++ b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl @@ -241,6 +241,10 @@ private: <#list body.getStateNonAliasSymbols() as variable> ${tc.includeArgs("org.nest.nestml.neuron.function.MemberDeclaration", [variable])} + <#list body.getInitialValuesSymbols() as variable> + ${tc.includeArgs("org.nest.nestml.neuron.function.MemberDeclaration", [variable])} + + <#else> //! Symbolic indices to the elements of the state vector y enum StateVecElems diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index e578bdd42..413399d68 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -127,7 +127,7 @@ public void testTutorialModels() { @Test public void manually() { final String[] args = new String[] { - "models/iaf_psc_alpha.nestml", + "models/aeif_cond_exp.nestml", "--json_log", "model_issues", "--target", outputPath.toString()}; diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index afaebf8e1..8b21c929a 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -8,7 +8,7 @@ - + \ No newline at end of file diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index c3be75df6..3f9765b66 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -13,7 +13,7 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): if not (gsl_error_tol is None): nest.SetStatus(neuron2, {"gsl_error_tol": gsl_error_tol}) - spikegenerator=nest.Create('spike_generator',params={'spike_times':[100.0, 200.0], 'spike_weights':[1.0, -1.0]}) + spikegenerator=nest.Create('spike_generator',params={'spike_times':[100.0, 200.0], 'spike_weights':[1.0, -2.0]}) nest.Connect(spikegenerator, neuron1) nest.Connect(spikegenerator, neuron2) @@ -55,75 +55,14 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): None #print("Greater than 0 difference" + str(abs(Vms1[index]-Vms2[index])) + " at iteration: " + str(index) + " of overall iterations: " + str(len(Vms1))) print(testant + " PASSED") - - -def test_multysinapse(): - neuron1=nest.Create ("iaf_psc_alpha_multisynapse_neuron") - neuron2=nest.Create ("iaf_psc_alpha_multisynapse_neuron") - - nest.SetDefaults("iaf_psc_alpha_multisynapse", {"tau_syn": [1.0,2.0]}) - - - spikegenerator=nest.Create('spike_generator',params={'spike_times':[100.0, 200.0] }) - - syn_dict ={"model": "static_synapse", "weight":2.5, 'receptor_type': 1} - - nest.Connect(spikegenerator, neuron2, syn_spec= syn_dict) - nest.Connect(spikegenerator, neuron1, syn_spec= syn_dict) - - #nest.SetStatus(neuron1, {"I_e": 376.0}) - #nest.SetStatus(neuron2, {"I_e": 376.0}) - - multimeter1=nest.Create('multimeter') - multimeter2=nest.Create('multimeter') - - V_m_specifier = 'V_m'# 'delta_V_m' - nest.SetStatus (multimeter1, {"withtime":True, "record_from":[V_m_specifier]}) - nest.SetStatus (multimeter2, {"withtime":True, "record_from":[V_m_specifier]}) - - nest.Connect (multimeter1, neuron1) - nest.Connect (multimeter2, neuron2) - - nest.Simulate (400.0) - dmm1=nest.GetStatus(multimeter1)[0] - Vms1=dmm1["events"][V_m_specifier] - ts1=dmm1["events"]["times"] - - events1=dmm1["events"] - pylab.figure(1) - - dmm2=nest.GetStatus(multimeter2)[0] - Vms2=dmm2["events"][V_m_specifier] - ts2=dmm2["events"]["times"] - - pylab.plot(ts1,Vms1) - pylab.plot(ts2,Vms2) - - pylab.show() - - for index in range(0, len(Vms1)): - if abs(Vms1[index]-Vms2[index]) > 0.000001: - print('!!!!!!!!!!!!!!!!!!!!') - print(str(Vms1[index]) + " divers from " + str(Vms2[index]) + " at iteration: " + str(index) + " of overall iterations: " + str(len(Vms1))) - print('!!!!!!!!!!!!!!!!!!!!') - raise Exception("TEST FAILED") - elif abs(Vms1[index]-Vms2[index]) > 0: - print("Greater than 0 difference" + str(abs(Vms1[index]-Vms2[index])) + " at iteration: " + str(index) + " of overall iterations: " + str(len(Vms1))) - print("Test: PASSED") - - - - if __name__ == "__main__": # execute only if run as a script # test_multysinapse() models = list() - - - models.append( ("iaf_cond_alpha_implicit", "iaf_cond_alpha_neuron", None, 0.001)) + models.append( ("aeif_cond_exp", "aeif_cond_exp_implicit", None, 0.001)) + models.append( ("aeif_cond_exp", "aeif_cond_exp_neuron", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: test(reference, testant, gsl_error_tol, tollerance) - \ No newline at end of file From d6bbb18bf44cbad503dd036e48dbb8ae046d27b8 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Thu, 21 Sep 2017 08:21:42 +0200 Subject: [PATCH 09/17] Only non function variables must be stored in the state array. Adopts the new syntax int he hh_cond_exp_traub neuron model. --- models/hh_cond_exp_traub.nestml | 45 ++++++++----------- .../nest/codegeneration/helpers/GslNames.java | 2 +- .../java/org/nest/nestml/_ast/ASTNeuron.java | 18 ++++++++ .../org/nest/nestml/neuron/NeuronClass.ftl | 6 +-- .../org/nest/nestml/neuron/NeuronHeader.ftl | 5 ++- .../function/GSLDifferentiationFunction.ftl | 2 +- .../org/nest/frontend/NestmlFrontendTest.java | 3 +- src/test/resources/neuron_tester.py | 4 +- 8 files changed, 50 insertions(+), 35 deletions(-) diff --git a/models/hh_cond_exp_traub.nestml b/models/hh_cond_exp_traub.nestml index 8897dc255..5fa9a57d8 100644 --- a/models/hh_cond_exp_traub.nestml +++ b/models/hh_cond_exp_traub.nestml @@ -34,10 +34,11 @@ SeeAlso: hh_psc_alpha neuron hh_cond_exp_traub_neuron: state: - V_m mV = E_L # Membrane potential + r integer # counts number of tick during the refractory period + end - g_in nS = 0nS # Inhibitory synaptic conductance - g_ex nS = 0nS # Excitatory synaptic conductance + initial_values: + V_m mV = E_L # Membrane potential function alpha_n_init 1/ms = 0.032/(ms* mV ) * ( 15. mV - V_m) / ( exp( ( 15. mV - V_m) / 5. mV ) - 1. ) function beta_n_init 1/ms = 0.5 /ms * exp( ( 10. mV - V_m ) / 40. mV ) @@ -49,15 +50,18 @@ neuron hh_cond_exp_traub_neuron: Act_m real = alpha_m_init / ( alpha_m_init + beta_m_init ) Act_h real = alpha_h_init / ( alpha_h_init + beta_h_init ) Inact_n real = alpha_n_init / ( alpha_n_init + beta_n_init ) - - r integer # counts number of tick during the refractory period end equations: + # synapses: exponential conductance + shape g_in = exp(-1/tau_syn_in*t) + shape g_ex = exp(-1/tau_syn_ex*t) + # Add aliases to simplify the equation definition of V_m function I_Na pA = g_Na * Act_m * Act_m * Act_m * Act_h * ( V_m - E_Na ) function I_K pA = g_K * Inact_n * Inact_n * Inact_n * Inact_n * ( V_m - E_K ) function I_L pA = g_L * ( V_m - E_L ) + function I_syn_exc pA = cond_sum(g_ex, spikeExc) * ( V_m - E_ex ) function I_syn_inh pA = cond_sum(g_in, spikeInh) * ( V_m - E_in ) @@ -76,9 +80,6 @@ neuron hh_cond_exp_traub_neuron: Act_h' = ( alpha_h - ( alpha_h + beta_h ) * Act_h ) Inact_n' = ( alpha_n - ( alpha_n + beta_n ) * Inact_n ) - # synapses: exponential conductance - g_ex' = -g_ex / tau_syn_ex - g_in' = -g_in / tau_syn_in end parameters: @@ -122,10 +123,6 @@ neuron hh_cond_exp_traub_neuron: emit_spike() end - - - g_ex += spikeExc * nS - g_in += spikeInh * nS end end @@ -166,10 +163,14 @@ SeeAlso: hh_psc_alpha neuron hh_cond_exp_traub_implicit: state: + r integer # counts number of tick during the refractory period + end + + initial_values: V_m mV = E_L # Membrane potential - g_in nS = 0nS # Inhibitory synaptic conductance - g_ex nS = 0nS # Excitatory synaptic conductance + g_in nS = 1nS # Inhibitory synaptic conductance + g_ex nS = 1nS # Excitatory synaptic conductance function alpha_n_init 1/ms = 0.032/(ms* mV ) * ( 15. mV - V_m) / ( exp( ( 15. mV - V_m) / 5. mV ) - 1. ) function beta_n_init 1/ms = 0.5 /ms * exp( ( 10. mV - V_m ) / 40. mV ) @@ -181,12 +182,13 @@ neuron hh_cond_exp_traub_implicit: Act_m real = alpha_m_init / ( alpha_m_init + beta_m_init ) Act_h real = alpha_h_init / ( alpha_h_init + beta_h_init ) Inact_n real = alpha_n_init / ( alpha_n_init + beta_n_init ) - - r integer # counts number of tick during the refractory period - end equations: + # synapses: exponential conductance + shape g_ex' = -g_ex / tau_syn_ex + shape g_in' = -g_in / tau_syn_in + # Add aliases to simplify the equation definition of V_m function I_Na pA = g_Na * Act_m * Act_m * Act_m * Act_h * ( V_m - E_Na ) function I_K pA = g_K * Inact_n * Inact_n * Inact_n * Inact_n * ( V_m - E_K ) @@ -208,10 +210,6 @@ neuron hh_cond_exp_traub_implicit: Act_m' = ( alpha_m - ( alpha_m + beta_m ) * Act_m ) Act_h' = ( alpha_h - ( alpha_h + beta_h ) * Act_h ) Inact_n' = ( alpha_n - ( alpha_n + beta_n ) * Inact_n ) - - # synapses: exponential conductance - g_ex' = -g_ex / tau_syn_ex - g_in' = -g_in / tau_syn_in end parameters: @@ -254,11 +252,6 @@ neuron hh_cond_exp_traub_implicit: r = RefractoryCounts emit_spike() end - - - - g_ex += spikeExc * nS - g_in += spikeInh * nS end end \ No newline at end of file diff --git a/src/main/java/org/nest/codegeneration/helpers/GslNames.java b/src/main/java/org/nest/codegeneration/helpers/GslNames.java index 590501c69..a9af93a0e 100644 --- a/src/main/java/org/nest/codegeneration/helpers/GslNames.java +++ b/src/main/java/org/nest/codegeneration/helpers/GslNames.java @@ -14,7 +14,7 @@ public static String arrayIndex(final VariableSymbol variableSymbol) { } public static String name(final VariableSymbol variableSymbol) { - if (variableSymbol.isInInitialValues()) { + if (variableSymbol.isInInitialValues() && !variableSymbol.isFunction()) { return "ode_state[State_::" + Names.convertToCPPName(variableSymbol.getName()) + "]"; } else { diff --git a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java index 2dc0d0a0f..967aae912 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java +++ b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java @@ -175,6 +175,24 @@ public List getInitialValuesSymbols() { .collect(toList()); } + public List getNonFunctionInitialValuesSymbols() { + return this.getSpannedScope().get().resolveLocally(VariableSymbol.KIND) + .stream() + .map(variable -> (VariableSymbol) variable) + .filter(VariableSymbol::isInInitialValues) + .filter(variableSymbol -> !variableSymbol.isFunction()) + .collect(toList()); + } + + public List getFunctionInitialValuesSymbols() { + return this.getSpannedScope().get().resolveLocally(VariableSymbol.KIND) + .stream() + .map(variable -> (VariableSymbol) variable) + .filter(VariableSymbol::isInInitialValues) + .filter(VariableSymbol::isFunction) + .collect(toList()); + } + public List getStateAliasSymbols() { return getVariableSymbols(getDeclarationsFromBlock(ASTBlockWithVariables::isState), getSpannedScope().get()) diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl index 7333f6473..abbd4856d 100644 --- a/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl +++ b/src/main/resources/org/nest/nestml/neuron/NeuronClass.ftl @@ -40,7 +40,7 @@ #include "${neuronName}.h" -<#assign stateSize = body.getInitialValuesSymbols()?size> +<#assign stateSize = body.getNonFunctionInitialValuesSymbols()?size> /* ---------------------------------------------------------------- * Recordables map * ---------------------------------------------------------------- */ @@ -63,8 +63,8 @@ namespace nest <#list body.getParameterSymbols() as parameter> ${tc.includeArgs("org.nest.nestml.neuron.function.RecordCallback", [parameter])} - <#list body.getInitialValuesSymbols() as parameter> - ${tc.includeArgs("org.nest.nestml.neuron.function.RecordCallback", [parameter])} + <#list body.getInitialValuesSymbols() as initial_value> + ${tc.includeArgs("org.nest.nestml.neuron.function.RecordCallback", [initial_value])} <#list body.getODEAliases() as odeAlias> ${tc.includeArgs("org.nest.nestml.neuron.function.RecordCallback", [odeAlias])} diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl index 6ce7d09a8..9c89d9348 100644 --- a/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl +++ b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl @@ -249,7 +249,7 @@ private: //! Symbolic indices to the elements of the state vector y enum StateVecElems { - <#list body.getInitialValuesSymbols() as variable> + <#list body.getNonFunctionInitialValuesSymbols() as variable> ${names.convertToCPPName(variable.getName())}, ${variable.printComment("// ")} STATE_VEC_SIZE @@ -259,6 +259,9 @@ private: <#list body.getStateSymbols() as variable> ${tc.includeArgs("org.nest.nestml.neuron.function.MemberDeclaration", [variable])} + <#list body.getFunctionInitialValuesSymbols() as variable> + ${tc.includeArgs("org.nest.nestml.neuron.function.MemberDeclaration", [variable])} + <#list body.getODEAliases() as odeAlias> diff --git a/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl b/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl index 20d0b90fa..d7ea74c2c 100644 --- a/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl +++ b/src/main/resources/org/nest/nestml/neuron/function/GSLDifferentiationFunction.ftl @@ -30,7 +30,7 @@ ${neuronName}_dynamics( double, const double ode_state[], double f[], void* pnod double ${names.name(function)} = ${expressionsPrinterForGSL.print(declaringExpression)}; - <#list ast.getInitialValuesSymbols() as odeVariable> + <#list ast.getNonFunctionInitialValuesSymbols() as odeVariable> <#assign simpleOde = odeTransformer.replaceSumCalls(odeVariable.getOdeDeclaration().get())> f[ ${names.arrayIndex(odeVariable)} ] = ${expressionsPrinterForGSL.print(simpleOde)}; diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index 413399d68..db6a58daa 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -127,8 +127,9 @@ public void testTutorialModels() { @Test public void manually() { final String[] args = new String[] { - "models/aeif_cond_exp.nestml", + "models/hh_cond_exp_traub.nestml", "--json_log", "model_issues", + "--enable_tracing", "--target", outputPath.toString()}; new NestmlFrontend().start(args); diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index 3f9765b66..7e21821fb 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -60,8 +60,8 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): # test_multysinapse() models = list() - models.append( ("aeif_cond_exp", "aeif_cond_exp_implicit", None, 0.001)) - models.append( ("aeif_cond_exp", "aeif_cond_exp_neuron", None, 0.001)) + models.append( ("hh_cond_exp_traub", "hh_cond_exp_traub_implicit", None, 0.001)) + models.append( ("hh_cond_exp_traub", "hh_cond_exp_traub_neuron", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: test(reference, testant, gsl_error_tol, tollerance) From fc3672acfef0013c250e1ac5d62ee252db4ef39f Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Thu, 21 Sep 2017 11:23:14 +0200 Subject: [PATCH 10/17] Fixes the next model. --- models/hh_psc_alpha.nestml | 38 ++++++++----------- .../org/nest/frontend/NestmlFrontendTest.java | 2 +- src/test/resources/neuron_tester.py | 4 +- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/models/hh_psc_alpha.nestml b/models/hh_psc_alpha.nestml index f636e5dae..38d1512ca 100644 --- a/models/hh_psc_alpha.nestml +++ b/models/hh_psc_alpha.nestml @@ -45,8 +45,11 @@ Authors: Schrader SeeAlso: hh_cond_exp_traub */ neuron hh_psc_alpha_neuron: - state: + r integer # number of steps in the current refractory phase + end + + initial_values: V_m mV = -65. mV # Membrane potential function alpha_n_init real = ( 0.01 * ( V_m / mV + 55. ) ) / ( 1. - exp( -( V_m / mV + 55. ) / 10. ) ) @@ -59,7 +62,6 @@ neuron hh_psc_alpha_neuron: Act_m real = alpha_m_init / ( alpha_m_init + beta_m_init ) # Activation variable m Act_h real = alpha_h_init / ( alpha_h_init + beta_h_init ) # Activation variable h Inact_n real = alpha_n_init / ( alpha_n_init + beta_n_init ) # Inactivation variable n - r integer # number of steps in the current refractory phase end equations: @@ -181,11 +183,15 @@ SeeAlso: hh_cond_exp_traub neuron hh_psc_alpha_implicit: state: + r integer # number of steps in the current refractory phase + end + + initial_values: V_m mV = -65. mV # Membrane potential - I_syn_ex pA # inputs from the exc spikes - I_syn_ex' pA/ms # inputs from the exc spikes - I_syn_in pA # inputs from the inh spikes - I_syn_in' pA/ms # inputs from the inh spikes + I_syn_ex pA = 0pA # inputs from the exc spikes + I_syn_ex' pA/ms = pA * e / tau_syn_ex # inputs from the exc spikes + I_syn_in pA = 0pA # inputs from the inh spikes + I_syn_in' pA/ms = pA * e / tau_syn_in # inputs from the inh spikes function alpha_n_init real = ( 0.01 * ( V_m / mV + 55. ) ) / ( 1. - exp( -( V_m / mV + 55. ) / 10. ) ) function beta_n_init real = 0.125 * exp( -( V_m / mV + 65. ) / 80. ) @@ -197,17 +203,16 @@ neuron hh_psc_alpha_implicit: Act_m real = alpha_m_init / ( alpha_m_init + beta_m_init ) # Activation variable m Act_h real = alpha_h_init / ( alpha_h_init + beta_h_init ) # Activation variable h Inact_n real = alpha_n_init / ( alpha_n_init + beta_n_init ) # Inactivation variable n - r integer # number of steps in the current refractory phase end equations: # synapses: alpha functions - I_syn_in' = I_syn_in' - I_syn_in'' = (-2/tau_syn_in) * I_syn_in'-(1/tau_syn_in**2) * I_syn_in + shape I_syn_in' = I_syn_in' + shape I_syn_in'' = (-2/tau_syn_in) * I_syn_in'-(1/tau_syn_in**2) * I_syn_in ## alpha function for the g_ex - I_syn_ex' = I_syn_ex' - I_syn_ex'' = (-2/tau_syn_ex) * I_syn_ex'-(1/tau_syn_ex**2) * I_syn_ex + shape I_syn_ex' = I_syn_ex' + shape I_syn_ex'' = (-2/tau_syn_ex) * I_syn_ex'-(1/tau_syn_ex**2) * I_syn_ex function I_syn_exc pA = curr_sum(I_syn_ex, spikeExc) function I_syn_inh pA = curr_sum(I_syn_in, spikeInh) @@ -247,15 +252,6 @@ neuron hh_psc_alpha_implicit: end internals: - # Impulse to add to DG_EXC on spike arrival to evoke unit-amplitude - # conductance excursion. - PSConInit_E pA/ms = pA * e / tau_syn_ex - - # Impulse to add to DG_INH on spike arrival to evoke unit-amplitude - # conductance excursion. - PSConInit_I pA/ms = pA * e / tau_syn_in - - RefractoryCounts integer = steps(t_ref) # refractory time in steps end @@ -278,8 +274,6 @@ neuron hh_psc_alpha_implicit: emit_spike() end - I_syn_ex' += spikeExc * PSConInit_E - I_syn_in' += spikeInh * PSConInit_I end end diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index db6a58daa..0647420c3 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -127,7 +127,7 @@ public void testTutorialModels() { @Test public void manually() { final String[] args = new String[] { - "models/hh_cond_exp_traub.nestml", + "models/hh_psc_alpha.nestml", "--json_log", "model_issues", "--enable_tracing", "--target", outputPath.toString()}; diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index 7e21821fb..efc30ebac 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -60,8 +60,8 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): # test_multysinapse() models = list() - models.append( ("hh_cond_exp_traub", "hh_cond_exp_traub_implicit", None, 0.001)) - models.append( ("hh_cond_exp_traub", "hh_cond_exp_traub_neuron", None, 0.001)) + models.append( ("hh_psc_alpha", "hh_psc_alpha_neuron", None, 0.001)) + models.append( ("hh_psc_alpha", "hh_psc_alpha_neuron", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: test(reference, testant, gsl_error_tol, tollerance) From fbc4b4af945f6df6f23a88a4ed9ee80d6d17b8c2 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Tue, 26 Sep 2017 14:56:43 +0200 Subject: [PATCH 11/17] Adopt new syntax in the next batch of nestml models. --- models/ht_neuron.nestml | 8 +- models/iaf_chxk_2008.nestml | 27 +++-- models/iaf_cond_beta.nestml | 5 +- models/iaf_cond_exp.nestml | 71 ++++++------ models/iaf_cond_exp_sfa_rr.nestml | 109 +++++++++--------- models/iaf_neuron.nestml | 7 +- models/iaf_psc_alpha_multisynapse.nestml | 7 +- models/iaf_psc_delta.nestml | 7 +- models/iaf_psc_exp.nestml | 7 +- models/iaf_psc_exp_multisynapse.nestml | 6 +- .../codegeneration/sympy/SymPySolver.java | 3 +- .../codegeneration/sympy/TransformerBase.java | 3 + .../NESTMLSymbolTableCreator.java | 18 +-- .../org/nest/nestml/neuron/NeuronHeader.ftl | 2 +- .../org/nest/frontend/NestmlFrontendTest.java | 2 +- src/test/resources/neuron_tester.py | 4 +- 16 files changed, 157 insertions(+), 129 deletions(-) diff --git a/models/ht_neuron.nestml b/models/ht_neuron.nestml index 3dfc1339d..637e8eda5 100644 --- a/models/ht_neuron.nestml +++ b/models/ht_neuron.nestml @@ -44,14 +44,16 @@ SeeAlso: ht_synapse */ neuron ht_neuron_nestml: - state: + r_potassium integer + g_spike boolean = false + end + + initial_values: V_m mV = ( g_NaL * E_Na + g_KL * E_K ) / ( g_NaL + g_KL ) # membrane potential Theta mV = Theta_eq # Threshold g_AMPA, g_NMDA, g_GABAA, g_GABAB, IKNa_D, IT_m, IT_h, Ih_m nS g_AMPA', g_NMDA', g_GABAA', g_GABAB' nS/ms - r_potassium integer - g_spike boolean = false end equations: diff --git a/models/iaf_chxk_2008.nestml b/models/iaf_chxk_2008.nestml index cd12597cb..d0a2b1e3c 100644 --- a/models/iaf_chxk_2008.nestml +++ b/models/iaf_chxk_2008.nestml @@ -24,10 +24,10 @@ SeeAlso: iaf_cond_alpha */ neuron iaf_chxk_2008_neuron: - state: - V_m mV = E_L ## membrane potential - G_ahp nS ## AHP conductance - G_ahp' nS/ms ## AHP conductance + initial_values: + V_m mV = E_L # membrane potential + G_ahp nS # AHP conductance + G_ahp' nS/ms # AHP conductance end equations: @@ -139,22 +139,21 @@ SeeAlso: iaf_cond_alpha */ neuron iaf_chxk_2008_implicit: - state: - - V_m mV = E_L ## membrane potential - g_in nS ## inputs from the inh conductance - g_in' nS/ms ## inputs from the inh conductance - g_ex nS ## inputs from the exc conductance - g_ex' nS/ms ## inputs from the exc conductance - G_ahp nS ## AHP conductance - G_ahp' nS/ms ## AHP conductance + initial_values: + V_m mV = E_L # membrane potential + g_in nS # inputs from the inh conductance + g_in' nS/ms # inputs from the inh conductance + g_ex nS # inputs from the exc conductance + g_ex' nS/ms # inputs from the exc conductance + G_ahp nS # AHP conductance + G_ahp' nS/ms # AHP conductance end equations: g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in g_in' = g_in' - ## alpha function for the g_ex + # alpha function for the g_ex g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex g_ex' = g_ex' diff --git a/models/iaf_cond_beta.nestml b/models/iaf_cond_beta.nestml index 61c498544..0c30de0ec 100644 --- a/models/iaf_cond_beta.nestml +++ b/models/iaf_cond_beta.nestml @@ -22,12 +22,15 @@ SeeAlso: iaf_cond_exp, iaf_cond_beta_mc, iaf_cond_alpha */ neuron iaf_cond_beta_neuron: state: + r integer ## counts number of tick during the refractory period + end + + initial_values: V_m mV = E_L ## membrane potential g_in nS = 0 nS ## inputs from the inh conductance g_in' nS/ms = 0 nS/ms ## inputs from the inh conductance g_ex nS = 0 nS ## inputs from the exc conductance g_ex' nS/ms = 0 nS/ms ## inputs from the exc conductance - r integer ## counts number of tick during the refractory period end equations: diff --git a/models/iaf_cond_exp.nestml b/models/iaf_cond_exp.nestml index e94176b1d..3a7f0d2f6 100644 --- a/models/iaf_cond_exp.nestml +++ b/models/iaf_cond_exp.nestml @@ -26,13 +26,16 @@ SeeAlso: iaf_psc_delta, iaf_psc_exp, iaf_cond_exp neuron iaf_cond_exp_neuron: state: - V_m mV = E_L ## membrane potential - r integer ## counts number of tick during the refractory period + r integer # counts number of tick during the refractory period + end + + initial_values: + V_m mV = E_L # membrane potential end equations: - shape g_in = exp(-t/tau_syn_in) ## inputs from the inh conductance - shape g_ex = exp(-t/tau_syn_ex) ## inputs from the exc conductance + shape g_in = exp(-t/tau_syn_in) # inputs from the inh conductance + shape g_ex = exp(-t/tau_syn_ex) # inputs from the exc conductance function I_syn_exc pA = cond_sum(g_ex, spikeExc) * ( V_m - E_ex ) function I_syn_inh pA = cond_sum(g_in, spikeInh) * ( V_m - E_in ) @@ -41,17 +44,17 @@ neuron iaf_cond_exp_neuron: end parameters: - V_th mV = -55.0mV ## Threshold Potential in mV - V_reset mV = -60.0mV ## Reset Potential in mV - t_ref ms = 2.0 ms ## Refractory period in ms - g_L nS = 16.6667nS ## Leak Conductance in nS - C_m pF = 250.0 pF ## Membrane Capacitance in pF - E_ex mV = 0mV ## Excitatory reversal Potential in mV - E_in mV = -85.0mV ## Inhibitory reversal Potential in mV - E_L mV = -70.0mV ## Leak reversal Potential (aka resting potential) in mV - tau_syn_ex ms = 0.2ms ## Synaptic Time Constant Excitatory Synapse in ms - tau_syn_in ms = 2.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - I_e pA = 0pA ## Constant Current in pA + V_th mV = -55.0mV # Threshold Potential in mV + V_reset mV = -60.0mV # Reset Potential in mV + t_ref ms = 2.0 ms # Refractory period in ms + g_L nS = 16.6667nS # Leak Conductance in nS + C_m pF = 250.0 pF # Membrane Capacitance in pF + E_ex mV = 0mV # Excitatory reversal Potential in mV + E_in mV = -85.0mV # Inhibitory reversal Potential in mV + E_L mV = -70.0mV # Leak reversal Potential (aka resting potential) in mV + tau_syn_ex ms = 0.2ms # Synaptic Time Constant Excitatory Synapse in ms + tau_syn_in ms = 2.0ms # Synaptic Time Constant for Inhibitory Synapse in ms + I_e pA = 0pA # Constant Current in pA end internals: @@ -109,10 +112,13 @@ SeeAlso: iaf_psc_delta, iaf_psc_exp, iaf_cond_exp neuron iaf_cond_exp_implicit: state: - g_in nS = 0nS ## inputs from the inh conductance - g_ex nS = 0nS ## inputs from the exc conductance - V_m nS = E_L ## membrane potential - r integer ## counts number of tick during the refractory period + r integer # counts number of tick during the refractory period + end + + initial_values: + g_in nS = 1nS # inputs from the inh conductance + g_ex nS = 1nS # inputs from the exc conductance + V_m nS = E_L # membrane potential end equations: @@ -125,21 +131,21 @@ neuron iaf_cond_exp_implicit: end parameters: - V_th mV = -55.0mV ## Threshold Potential in mV - V_reset mV = -60.0mV ## Reset Potential in mV - t_ref ms = 2.0 ms ## Refractory period in ms - g_L nS = 16.6667nS ## Leak Conductance in nS - C_m pF = 250.0 pF ## Membrane Capacitance in pF - E_ex mV = 0mV ## Excitatory reversal Potential in mV - E_in mV = -85.0mV ## Inhibitory reversal Potential in mV - E_L mV = -70.0mV ## Leak reversal Potential (aka resting potential) in mV - tau_synE ms = 0.2ms ## Synaptic Time Constant Excitatory Synapse in ms - tau_synI ms = 2.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - I_e pA = 0pA ## Constant Current in pA + V_th mV = -55.0mV # Threshold Potential in mV + V_reset mV = -60.0mV # Reset Potential in mV + t_ref ms = 2.0 ms # Refractory period in ms + g_L nS = 16.6667nS # Leak Conductance in nS + C_m pF = 250.0 pF # Membrane Capacitance in pF + E_ex mV = 0mV # Excitatory reversal Potential in mV + E_in mV = -85.0mV # Inhibitory reversal Potential in mV + E_L mV = -70.0mV # Leak reversal Potential (aka resting potential) in mV + tau_synE ms = 0.2ms # Synaptic Time Constant Excitatory Synapse in ms + tau_synI ms = 2.0ms # Synaptic Time Constant for Inhibitory Synapse in ms + I_e pA = 0pA # Constant Current in pA end internals: - RefractoryCounts integer = steps(t_ref) ## refractory time in steps + RefractoryCounts integer = steps(t_ref) # refractory time in steps end input: @@ -161,9 +167,6 @@ neuron iaf_cond_exp_implicit: emit_spike() end - # add incoming spikes - g_ex += spikeExc * nS - g_in += spikeInh * nS end end diff --git a/models/iaf_cond_exp_sfa_rr.nestml b/models/iaf_cond_exp_sfa_rr.nestml index 87e2e772b..1ec33c8a9 100644 --- a/models/iaf_cond_exp_sfa_rr.nestml +++ b/models/iaf_cond_exp_sfa_rr.nestml @@ -39,18 +39,21 @@ iaf_cond_alpha neuron iaf_cond_exp_sfa_rr_neuron: state: - V_m mV = E_L ## membrane potential - g_sfa nS ## inputs from the sfa conductance - g_rr nS ## inputs from the rr conductance - r integer ## counts number of tick during the refractory period + r integer # counts number of tick during the refractory period + end + + initial_values: + V_m mV = E_L # membrane potential + g_sfa nS # inputs from the sfa conductance + g_rr nS # inputs from the rr conductance end equations: - shape g_in = exp(-t/tau_syn_in) ## inputs from the inh conductance - shape g_ex = exp(-t/tau_syn_ex) ## inputs from the exc conductance + shape g_in = exp(-t/tau_syn_in) # inputs from the inh conductance + shape g_ex = exp(-t/tau_syn_ex) # inputs from the exc conductance g_sfa' = -g_sfa / tau_sfa - g_rr' = g_rr / tau_rr + g_rr' = -g_rr / tau_rr function I_syn_exc pA = cond_sum(g_ex, spikesExc) * ( V_m - E_ex ) function I_syn_inh pA = cond_sum(g_in, spikesInh) * ( V_m - E_in ) @@ -62,23 +65,23 @@ neuron iaf_cond_exp_sfa_rr_neuron: end parameters: - V_th mV = -57.0mV ## Threshold Potential in mV - V_reset mV = -70.0mV ## Reset Potential in mV - t_ref ms = 0.5ms ## Refractory period in ms - g_L nS = 28.95nS ## Leak Conductance in nS - C_m pF = 289.5pF ## Membrane Capacitance in pF - E_ex mV = 0 mV ## Excitatory reversal Potential in mV - E_in mV = -75.0mV ## Inhibitory reversal Potential in mV - E_L mV = -70.0mV ## Leak reversal Potential (aka resting potential) in mV - tau_syn_ex ms = 1.5ms ## Synaptic Time Constant Excitatory Synapse in ms - tau_syn_in ms = 10.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - q_sfa nS = 14.48nS ## Outgoing spike activated quantal spike-frequency adaptation conductance increase - q_rr nS = 3214.0nS ## Outgoing spike activated quantal relative refractory conductance increase. - tau_sfa ms = 110.0ms ## Time constant of spike-frequency adaptation in ms. - tau_rr ms = 1.97ms ## Time constant of the relative refractory mechanism. - E_sfa mV = -70.0mV ## spike-frequency adaptation conductance reversal potential - E_rr mV = -70.0mV ## relative refractory mechanism conductance reversal potential - I_e pA = 0pA ## Constant Current + V_th mV = -57.0mV # Threshold Potential in mV + V_reset mV = -70.0mV # Reset Potential in mV + t_ref ms = 0.5ms # Refractory period in ms + g_L nS = 28.95nS # Leak Conductance in nS + C_m pF = 289.5pF # Membrane Capacitance in pF + E_ex mV = 0 mV # Excitatory reversal Potential in mV + E_in mV = -75.0mV # Inhibitory reversal Potential in mV + E_L mV = -70.0mV # Leak reversal Potential (aka resting potential) in mV + tau_syn_ex ms = 1.5ms # Synaptic Time Constant Excitatory Synapse in ms + tau_syn_in ms = 10.0ms # Synaptic Time Constant for Inhibitory Synapse in ms + q_sfa nS = 14.48nS # Outgoing spike activated quantal spike-frequency adaptation conductance increase + q_rr nS = 3214.0nS # Outgoing spike activated quantal relative refractory conductance increase. + tau_sfa ms = 110.0ms # Time constant of spike-frequency adaptation in ms. + tau_rr ms = 1.97ms # Time constant of the relative refractory mechanism. + E_sfa mV = -70.0mV # spike-frequency adaptation conductance reversal potential + E_rr mV = -70.0mV # relative refractory mechanism conductance reversal potential + I_e pA = 0pA # Constant Current end internals: @@ -110,7 +113,6 @@ neuron iaf_cond_exp_sfa_rr_neuron: end - /* BeginDocumentation Name: iaf_cond_exp_sfa_rr_implicit - Simple conductance based leaky integrate-and-fire neuron model. @@ -151,21 +153,24 @@ iaf_cond_alpha */ neuron iaf_cond_exp_sfa_rr_implicit: + initial_values: + V_m mV = E_L # membrane potential + g_in nS = 1nS # inputs from the inh conductance + g_ex nS = 1nS # inputs from the exc conductance + g_sfa nS = 0nS # inputs from the sfa conductance + g_rr nS = 0nS # inputs from the rr conductance + end + state: - V_m mV = E_L ## membrane potential - g_in nS ## inputs from the inh conductance - g_ex nS ## inputs from the exc conductance - g_sfa nS ## inputs from the sfa conductance - g_rr nS ## inputs from the rr conductance - r integer ## counts number of tick during the refractory period + r integer # counts number of tick during the refractory period end equations: - g_in' = -g_in/tau_syn_in - g_ex' = -g_ex/tau_syn_ex + shape g_in' = -g_in/tau_syn_in + shape g_ex' = -g_ex/tau_syn_ex g_sfa' = -g_sfa / tau_sfa - g_rr' = g_rr / tau_rr + g_rr' = -g_rr / tau_rr function I_syn_exc pA = cond_sum(g_ex, spikesExc) * ( V_m - E_ex ) function I_syn_inh pA = cond_sum(g_in, spikesInh) * ( V_m - E_in ) @@ -177,23 +182,23 @@ neuron iaf_cond_exp_sfa_rr_implicit: end parameters: - V_th mV = -57.0mV ## Threshold Potential in mV - V_reset mV = -70.0mV ## Reset Potential in mV - t_ref ms = 0.5ms ## Refractory period in ms - g_L nS = 28.95nS ## Leak Conductance in nS - C_m pF = 289.5pF ## Membrane Capacitance in pF - E_ex mV = 0 mV ## Excitatory reversal Potential in mV - E_in mV = -75.0mV ## Inhibitory reversal Potential in mV - E_L mV = -70.0mV ## Leak reversal Potential (aka resting potential) in mV - tau_syn_ex ms = 1.5ms ## Synaptic Time Constant Excitatory Synapse in ms - tau_syn_in ms = 10.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - q_sfa nS = 14.48nS ## Outgoing spike activated quantal spike-frequency adaptation conductance increase - q_rr nS = 3214.0nS ## Outgoing spike activated quantal relative refractory conductance increase. - tau_sfa ms = 110.0ms ## Time constant of spike-frequency adaptation in ms. - tau_rr ms = 1.97ms ## Time constant of the relative refractory mechanism. - E_sfa mV = -70.0mV ## spike-frequency adaptation conductance reversal potential - E_rr mV = -70.0mV ## relative refractory mechanism conductance reversal potential - I_e pA = 0pA ## Constant Current + V_th mV = -57.0mV # Threshold Potential in mV + V_reset mV = -70.0mV # Reset Potential in mV + t_ref ms = 0.5ms # Refractory period in ms + g_L nS = 28.95nS # Leak Conductance in nS + C_m pF = 289.5pF # Membrane Capacitance in pF + E_ex mV = 0 mV # Excitatory reversal Potential in mV + E_in mV = -75.0mV # Inhibitory reversal Potential in mV + E_L mV = -70.0mV # Leak reversal Potential (aka resting potential) in mV + tau_syn_ex ms = 1.5ms # Synaptic Time Constant Excitatory Synapse in ms + tau_syn_in ms = 10.0ms # Synaptic Time Constant for Inhibitory Synapse in ms + q_sfa nS = 14.48nS # Outgoing spike activated quantal spike-frequency adaptation conductance increase + q_rr nS = 3214.0nS # Outgoing spike activated quantal relative refractory conductance increase. + tau_sfa ms = 110.0ms # Time constant of spike-frequency adaptation in ms. + tau_rr ms = 1.97ms # Time constant of the relative refractory mechanism. + E_sfa mV = -70.0mV # spike-frequency adaptation conductance reversal potential + E_rr mV = -70.0mV # relative refractory mechanism conductance reversal potential + I_e pA = 0pA # Constant Current end internals: @@ -221,8 +226,6 @@ neuron iaf_cond_exp_sfa_rr_implicit: emit_spike() end - g_ex += spikesExc * nS - g_in += spikesInh * nS end end diff --git a/models/iaf_neuron.nestml b/models/iaf_neuron.nestml index 70066d6e5..f12662084 100644 --- a/models/iaf_neuron.nestml +++ b/models/iaf_neuron.nestml @@ -74,11 +74,14 @@ neuron iaf_neuron_nestml: # Captures the dynamic state of the neuron state: - V_abs mV - function V_m mV = V_abs + E_L # Membrane potential. r integer # counts number of tick during the refractory period end + initial_values: + V_abs mV = 0mV + function V_m mV = V_abs + E_L # Membrane potential. + end + # Declarative description of the updates rules equations: shape G = (e/tau_syn) * t * exp(-1/tau_syn*t) diff --git a/models/iaf_psc_alpha_multisynapse.nestml b/models/iaf_psc_alpha_multisynapse.nestml index 0e250d93b..2808cb30c 100644 --- a/models/iaf_psc_alpha_multisynapse.nestml +++ b/models/iaf_psc_alpha_multisynapse.nestml @@ -31,11 +31,14 @@ iaf_psc_exp_multisynapse neuron iaf_psc_alpha_multisynapse_neuron: state: - V_abs mV - function V_m mV = V_abs + E_L # Membrane potential. r integer # counts number of tick during the refractory period end + initial_values: + V_abs mV = 0mV + function V_m mV = V_abs + E_L # Membrane potential. + end + equations: shape I_shape = pA * (e/tau_syn) * t * exp(-1/tau_syn*t) V_abs' = -1/tau_m * V_abs + 1/C_m * (curr_sum(I_shape, spikes) + I_e + currents) diff --git a/models/iaf_psc_delta.nestml b/models/iaf_psc_delta.nestml index a2e8a52d2..c0a79b24d 100644 --- a/models/iaf_psc_delta.nestml +++ b/models/iaf_psc_delta.nestml @@ -69,10 +69,13 @@ SeeAlso: iaf_psc_alpha, iaf_psc_exp, iaf_neuron, iaf_psc_delta_canon neuron iaf_psc_delta_neuron: state: - V_abs mV = 0 mV refr_spikes_buffer mV = 0 mV + r integer # counts number of tick during the refractory period + end + + initial_values: + V_abs mV = 0 mV function V_m mV = V_abs + E_L # Membrane potential. - r integer # counts number of tick during the refractory period end equations: diff --git a/models/iaf_psc_exp.nestml b/models/iaf_psc_exp.nestml index ecaafc2bd..ef819e015 100644 --- a/models/iaf_psc_exp.nestml +++ b/models/iaf_psc_exp.nestml @@ -77,11 +77,14 @@ Author: Moritz Helias neuron iaf_psc_exp_neuron: state: - V_abs mV - function V_m mV = V_abs + E_L # Membrane potential. r integer # counts number of tick during the refractory period end + initial_values: + V_abs mV = 0mV + function V_m mV = V_abs + E_L # Membrane potential. + end + equations: shape I_shape_in = exp(-1/tau_syn_in*t) shape I_shape_ex = exp(-1/tau_syn_ex*t) diff --git a/models/iaf_psc_exp_multisynapse.nestml b/models/iaf_psc_exp_multisynapse.nestml index dafbe81c1..51944cba8 100644 --- a/models/iaf_psc_exp_multisynapse.nestml +++ b/models/iaf_psc_exp_multisynapse.nestml @@ -21,12 +21,14 @@ SeeAlso: iaf_psc_alpha, iaf_psc_delta, iaf_psc_exp, iaf_cond_exp, iaf_psc_alpha_multisynapse */ neuron iaf_psc_exp_multisynapse_neuron: - state: + r integer # counts number of tick during the refractory period + end + + initial_values: V_abs mV # membrane potential function V_m mV = V_abs + E_L # Relative membrane potential. # I.e. the real threshold is (V_m-E_L). - r integer # counts number of tick during the refractory period end equations: diff --git a/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java b/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java index cf835ba57..e04d3b9d6 100644 --- a/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java +++ b/src/main/java/org/nest/codegeneration/sympy/SymPySolver.java @@ -71,10 +71,11 @@ private SolverOutput executeSolver(final SolverInput solverInput, final Path out ODE_ANALYZER_SCRIPT, solverInput.toJSON()).directory(output.toFile()).command(commands); + final Process res = processBuilder.start(); res.waitFor(); long end = System.nanoTime(); - + // reports standard output getStreamAsListOfStrings(res.getInputStream()).forEach(reporter::reportProgress); // reports errors diff --git a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java index 067eb0a1c..90b45a0bf 100644 --- a/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java +++ b/src/main/java/org/nest/codegeneration/sympy/TransformerBase.java @@ -218,6 +218,9 @@ static void applyIncomingSpikes(final ASTNeuron astNeuron) { for (ASTVariable variable:astDeclaration.getVars()) { if (variable.toString().matches(shape + "(')*") || // handwritten models variable.toString().matches(shape + "__\\d+$")) { // generated models + if (!astDeclaration.getExpr().isPresent()) { + System.out.println(); + } spikesUpdates.add(AstCreator.createAssignment( variable.toString() + " += " + buffer + " * " + printer.print(astDeclaration.getExpr().get()))); } diff --git a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java index e9fcbb6d3..8fc313c1c 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java +++ b/src/main/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreator.java @@ -187,16 +187,16 @@ private void connectOdesToInitialValues(final ASTEquationsBlock astOdeDeclaratio private void connectOdeToVariable(final ASTDerivative derivedVariable, final ASTExpr astExpr) { checkState(this.currentScope().isPresent()); final Scope scope = currentScope().get(); - final String variableName = derivedVariable.getNameOfDerivedVariable(); - final Optional variable = scope.resolve(variableName, VariableSymbol.KIND); + final String variableName = derivedVariable.getNameOfDerivedVariable(); + final Optional variable = scope.resolve(variableName, VariableSymbol.KIND); - if (variable.isPresent()) { - variable.get().setOdeDeclaration(astExpr); - } - else { - Log.warn("NESTMLSymbolTableCreator: The left side of the ode is undefined. Cannot assign its definition: " + - variableName, derivedVariable.get_SourcePositionStart()); - } + if (variable.isPresent()) { + variable.get().setOdeDeclaration(astExpr); + } + else { + Log.warn("NESTMLSymbolTableCreator: The left side of the ode is undefined. Cannot assign its definition: " + + variableName, derivedVariable.get_SourcePositionStart()); + } } diff --git a/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl index 9c89d9348..667b580b2 100644 --- a/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl +++ b/src/main/resources/org/nest/nestml/neuron/NeuronHeader.ftl @@ -532,7 +532,7 @@ void ${neuronName}::set_status(const DictionaryDatum &__d) ${tc.includeArgs("org.nest.nestml.neuron.function.AssignTmpDictionaryValue", [state])} <#list body.getParameterInvariants() as invariant> - if ( !(${printerWithGetters.print(invariant)}) ) { + if ( !(${expressionsPrinter.print(invariant)}) ) { throw nest::BadProperty("The constraint '${idemPrinter.print(invariant)}' is violated!"); } diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index 0647420c3..c3ccc667e 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -127,7 +127,7 @@ public void testTutorialModels() { @Test public void manually() { final String[] args = new String[] { - "models/hh_psc_alpha.nestml", + "models/iaf_psc_exp_multisynapse.nestml", "--json_log", "model_issues", "--enable_tracing", "--target", outputPath.toString()}; diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index efc30ebac..edd1c32c7 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -60,8 +60,8 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): # test_multysinapse() models = list() - models.append( ("hh_psc_alpha", "hh_psc_alpha_neuron", None, 0.001)) - models.append( ("hh_psc_alpha", "hh_psc_alpha_neuron", None, 0.001)) + models.append( ("iaf_psc_exp", "iaf_psc_exp_neuron", None, 0.001)) + # models.append( ("iaf_cond_exp_sfa_rr", "iaf_cond_exp_sfa_rr_implicit", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: test(reference, testant, gsl_error_tol, tollerance) From f31efbf9f45373ed41a2bd2f52efde1b343ead58 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Wed, 27 Sep 2017 17:12:08 +0200 Subject: [PATCH 12/17] Map more NESTML models to the new syntax. --- models/iaf_tum_2000.nestml | 16 ++++++++-------- models/izhikevich.nestml | 6 ++---- models/izhikevich_psc_alpha.nestml | 10 ++++++++-- models/mat2_psc_exp.nestml | 10 +++++++--- .../org/nest/frontend/NestmlFrontendTest.java | 2 +- src/test/resources/neuron_tester.py | 4 ++-- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/models/iaf_tum_2000.nestml b/models/iaf_tum_2000.nestml index 8ba02fc32..0ff719192 100644 --- a/models/iaf_tum_2000.nestml +++ b/models/iaf_tum_2000.nestml @@ -92,11 +92,14 @@ neuron iaf_tum_2000_neuron: state: - V_m mV # Membrane potential r_tot integer r_abs integer end + initial_values: + V_m mV = 0 # Membrane potential + end + equations: shape I_shape_in = exp(-1/tau_syn_in*t) shape I_shape_ex = exp(-1/tau_syn_ex*t) @@ -142,7 +145,6 @@ neuron iaf_tum_2000_neuron: RefractoryCountsTot integer = steps(t_ref_tot) [[RefractoryCountsTot > 0]] end - input: ex_spikes <- excitatory spike in_spikes <- inhibitory spike @@ -160,17 +162,15 @@ neuron iaf_tum_2000_neuron: if r_tot == 0: if V_m >= V_th: # threshold crossing - r_abs = RefractoryCountsAbs - r_tot = RefractoryCountsTot - V_m = V_reset - emit_spike() + r_abs = RefractoryCountsAbs + r_tot = RefractoryCountsTot + V_m = V_reset + emit_spike() end else: r_tot -= 1 # neuron is totally refractory (cannot generate spikes) end - - end end diff --git a/models/izhikevich.nestml b/models/izhikevich.nestml index c7ebab0fd..7607a1ece 100644 --- a/models/izhikevich.nestml +++ b/models/izhikevich.nestml @@ -41,14 +41,13 @@ SeeAlso: iaf_psc_delta, mat2_psc_exp */ neuron izhikevich_neuron: - state: + initial_values: V_m mV = -65mV # Membrane potential in mV U_m real = 0 # Membrane potential recovery variable - I pA = 0. pA # input current end equations: - V_m' = ( 0.04 * V_m * V_m / mV + 5.0 * V_m + ( 140 - U_m ) * mV + ( (I + I_e) * GOhm ) ) / ms + V_m' = ( 0.04 * V_m * V_m / mV + 5.0 * V_m + ( 140 - U_m ) * mV + ( (currents + I_e) * GOhm ) ) / ms U_m' = a*(b*V_m-U_m * mV) / (mV*ms) end @@ -83,7 +82,6 @@ neuron izhikevich_neuron: emit_spike() end - I = currents end end diff --git a/models/izhikevich_psc_alpha.nestml b/models/izhikevich_psc_alpha.nestml index 2e352e4fa..e815266de 100644 --- a/models/izhikevich_psc_alpha.nestml +++ b/models/izhikevich_psc_alpha.nestml @@ -31,9 +31,12 @@ SeeAlso: izhikevitch, iaf_psc_alpha, mat2_psc_alpha neuron izhikevich_psc_alpha: state: + r integer # number of steps in the current refractory phase + end + + initial_values: V_m mV = -65 mV # Membrane potential in mV U_m pA = 0 pA # Membrane potential recovery variable - r integer # number of steps in the current refractory phase end equations: @@ -135,13 +138,16 @@ SeeAlso: izhikevitch, iaf_psc_alpha, mat2_psc_alpha neuron izhikevich_psc_alpha_implicit: state: + r integer # number of steps in the current refractory phase + end + + initial_values: V_m mV = -65 mV # Membrane potential in mV U_m pA = 0 pA # Membrane potential recovery variable I_syn_ex pA = 0. pA # inputs from the exc conductance I_syn_ex' pA/ms = 0. pA/ms # inputs from the exc conductance I_syn_in pA = 0. pA # inputs from the inh conductance I_syn_in' pA/ms = 0. pA/ms # inputs from the inh conductance - r integer # number of steps in the current refractory phase end equations: diff --git a/models/mat2_psc_exp.nestml b/models/mat2_psc_exp.nestml index 4ac84dc24..6259db6e1 100644 --- a/models/mat2_psc_exp.nestml +++ b/models/mat2_psc_exp.nestml @@ -61,14 +61,18 @@ neuron mat2_psc_exp_neuron: state: - V_abs mV # Membrane potential V_th_alpha_1 mV # Two-timescale adaptive threshold V_th_alpha_2 mV # Two-timescale adaptive threshold - function V_m mV = V_abs + E_L # Relative membrane potential. - # I.e. the real threshold is (V_m-E_L). + r integer # counts number of tick during the refractory period end + initial_values: + V_abs mV = 0mV# Membrane potential + function V_m mV = V_abs + E_L # Relative membrane potential. + # I.e. the real threshold is (V_m-E_L). + end + equations: shape I_shape_in = exp(-1/tau_syn_in*t) shape I_shape_ex = exp(-1/tau_syn_ex*t) diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index c3ccc667e..6ba9238c7 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -127,7 +127,7 @@ public void testTutorialModels() { @Test public void manually() { final String[] args = new String[] { - "models/iaf_psc_exp_multisynapse.nestml", + "models/mat2_psc_exp.nestml", "--json_log", "model_issues", "--enable_tracing", "--target", outputPath.toString()}; diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index edd1c32c7..b26ce3738 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -13,7 +13,7 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): if not (gsl_error_tol is None): nest.SetStatus(neuron2, {"gsl_error_tol": gsl_error_tol}) - spikegenerator=nest.Create('spike_generator',params={'spike_times':[100.0, 200.0], 'spike_weights':[1.0, -2.0]}) + spikegenerator=nest.Create('spike_generator',params={'spike_times':[100.0, 200.0], 'spike_weights':[20.0, -20.0]}) nest.Connect(spikegenerator, neuron1) nest.Connect(spikegenerator, neuron2) @@ -60,7 +60,7 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): # test_multysinapse() models = list() - models.append( ("iaf_psc_exp", "iaf_psc_exp_neuron", None, 0.001)) + models.append( ("mat2_psc_exp", "mat2_psc_exp_neuron", None, 0.001)) # models.append( ("iaf_cond_exp_sfa_rr", "iaf_cond_exp_sfa_rr_implicit", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: From 1605818aab21baa1c2479b83750be29dde6209b8 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Thu, 28 Sep 2017 18:26:34 +0200 Subject: [PATCH 13/17] Fixes cocos, tests, improves cocos. --- models/terub_neuron_gpe.nestml | 30 +++-- models/terub_neuron_stn.nestml | 30 +++-- .../sympy/ExactSolutionTransformer.java | 3 +- .../java/org/nest/nestml/_ast/ASTNeuron.java | 2 +- ...ava => EquationsOnlyForInitialValues.java} | 28 ++++- .../nestml/_cocos/NestmlErrorStrings.java | 6 +- .../nestml/_cocos/RestrictUseOfShapes.java | 115 +++++++++++------- .../_symboltable/NestmlCoCosManager.java | 5 +- .../_symboltable/symbols/VariableSymbol.java | 4 + .../sympy/EquationsBlockProcessorTest.java | 13 +- .../sympy/ExactSolutionTransformerTest.java | 5 - .../sympy/ShapesToOdesTransformerTest.java | 12 +- .../org/nest/frontend/NestmlFrontendTest.java | 2 +- .../nest/nestml/_cocos/NestmlCoCosTest.java | 34 +++--- .../nest/nestml/_parser/NESTMLParserTest.java | 2 +- .../NESTMLSymbolTableCreatorTest.java | 4 +- src/test/java/org/nest/units/UnitsTest.java | 9 +- .../iaf_psc_alpha_three_buffers.nestml | 4 +- src/test/resources/comments/iaf_neuron.nestml | 28 ++--- src/test/resources/logback-test.xml | 2 +- src/test/resources/neuron_tester.py | 2 +- ...l => equationsOnlyForInitialValues.nestml} | 4 +- .../restrictUseOfShapes.nestml} | 7 +- .../nestml/_cocos/invalid/unitsInODEs.nestml | 6 +- .../_cocos/restrictUseOfShapes/valid.nestml | 27 ---- ...l => equationsOnlyForInitialValues.nestml} | 6 +- .../_cocos/valid/restrictUseOfShapes.nestml | 28 +++++ .../nestml/_cocos/valid/unitsInODEs.nestml | 6 +- .../nestml/_symboltable/iaf_neuron.nestml | 9 +- 29 files changed, 239 insertions(+), 194 deletions(-) rename src/main/java/org/nest/nestml/_cocos/{EquationsOnlyForStateVariables.java => EquationsOnlyForInitialValues.java} (64%) rename src/test/resources/org/nest/nestml/_cocos/invalid/{equationsOnlyForStateVariables.nestml => equationsOnlyForInitialValues.nestml} (85%) rename src/test/resources/org/nest/nestml/_cocos/{restrictUseOfShapes/invalid.nestml => invalid/restrictUseOfShapes.nestml} (85%) delete mode 100644 src/test/resources/org/nest/nestml/_cocos/restrictUseOfShapes/valid.nestml rename src/test/resources/org/nest/nestml/_cocos/valid/{equationsOnlyForStateVariables.nestml => equationsOnlyForInitialValues.nestml} (66%) create mode 100644 src/test/resources/org/nest/nestml/_cocos/valid/restrictUseOfShapes.nestml diff --git a/models/terub_neuron_gpe.nestml b/models/terub_neuron_gpe.nestml index 3737a03b9..544eb5e98 100644 --- a/models/terub_neuron_gpe.nestml +++ b/models/terub_neuron_gpe.nestml @@ -39,15 +39,17 @@ Receives: SpikeEvent, CurrentEvent, DataLoggingRequest Author: Martin Ebert */ neuron terub_neuron_gpe: - state: + r integer # counts number of tick during the refractory period + end + + initial_values: V_m mV = E_L # Membrane potential - gate_h real # gating variable h - gate_n real # gating variable n - gate_r real # gating variable r - Ca_con real # gating variable r - r integer # counts number of tick during the refractory period + gate_h real = 0 # gating variable h + gate_n real = 0 # gating variable n + gate_r real = 0 # gating variable r + Ca_con real = 0 # gating variable r end equations: @@ -146,8 +148,6 @@ neuron terub_neuron_gpe: end internals: - PSCurrInit_E pA/ms = pA * e / tau_syn_ex - PSCurrInit_I pA/ms = pA * e / tau_syn_in refractory_counts integer = steps(t_ref) end @@ -216,20 +216,22 @@ Receives: SpikeEvent, CurrentEvent, DataLoggingRequest Author: Martin Ebert */ neuron terub_neuron_gpe_implicit: - state: + r integer # counts number of tick during the refractory period + end + + initial_values: V_m mV = E_L # Membrane potential g_in pA = 0pA # Inhibitory synaptic conductance - g_in' pA/ms = 0pA/ms # Inhibitory synaptic conductance + g_in' pA/ms = pA * e / tau_syn_in # Inhibitory synaptic conductance g_ex pA = 0pA # Excitatory synaptic conductance - g_ex' pA/ms = 0pA/ms # Excitatory synaptic conductance + g_ex' pA/ms = pA * e / tau_syn_ex # Excitatory synaptic conductance gate_h real # gating variable h gate_n real # gating variable n gate_r real # gating variable r Ca_con real # gating variable r - r integer # counts number of tick during the refractory period end equations: @@ -331,8 +333,6 @@ neuron terub_neuron_gpe_implicit: end internals: - PSCurrInit_E pA/ms = pA * e / tau_syn_ex - PSCurrInit_I pA/ms = pA * e / tau_syn_in refractory_counts integer = steps(t_ref) end @@ -356,8 +356,6 @@ neuron terub_neuron_gpe_implicit: emit_spike() end - g_ex' += spikeExc * PSCurrInit_E - g_in' += spikeInh * PSCurrInit_I end end \ No newline at end of file diff --git a/models/terub_neuron_stn.nestml b/models/terub_neuron_stn.nestml index 5c5ceb469..c5b114152 100644 --- a/models/terub_neuron_stn.nestml +++ b/models/terub_neuron_stn.nestml @@ -39,16 +39,18 @@ Receives: SpikeEvent, CurrentEvent, DataLoggingRequest Author: Martin Ebert */ neuron terub_neuron_stn: - state: - V_m mV = E_L # Membrane potential - gate_h real # gating variable h - gate_n real # gating variable n - gate_r real # gating variable r - Ca_con real # gating variable r r integer # counts number of tick during the refractory period end + initial_values: + V_m mV = E_L # Membrane potential + gate_h real = 0 # gating variable h + gate_n real = 0 # gating variable n + gate_r real = 0 # gating variable r + Ca_con real = 0 # gating variable r + end + equations: #Parameters for Terman Rubin STN Neuron @@ -155,8 +157,6 @@ neuron terub_neuron_stn: end internals: - PSCurrInit_E real = ms * e / tau_syn_ex - PSCurrInit_I real = ms * e / tau_syn_in refractory_counts integer = steps(t_ref) end @@ -225,20 +225,22 @@ Receives: SpikeEvent, CurrentEvent, DataLoggingRequest Author: Martin Ebert */ neuron terub_neuron_stn_implicit: - state: + r integer # counts number of tick during the refractory period + end + + initial_values: V_m mV = E_L # Membrane potential g_in pA = 0pA # Inhibitory synaptic conductance - g_in' pA/ms = 0pA/ms # Inhibitory synaptic conductance + g_in' pA/ms = pA * e / tau_syn_in # Inhibitory synaptic conductance g_ex pA = 0pA # Excitatory synaptic conductance - g_ex' pA/ms = 0pA/ms # Excitatory synaptic conductance + g_ex' pA/ms = pA * e / tau_syn_ex # Excitatory synaptic conductance gate_h real # gating variable h gate_n real # gating variable n gate_r real # gating variable r Ca_con real # gating variable r - r integer # counts number of tick during the refractory period end equations: @@ -350,8 +352,6 @@ neuron terub_neuron_stn_implicit: end internals: - PSCurrInit_E real = ms * e / tau_syn_ex - PSCurrInit_I real = ms * e / tau_syn_in refractory_counts integer = steps(t_ref) end @@ -375,8 +375,6 @@ neuron terub_neuron_stn_implicit: emit_spike() end - g_ex' += spikeExc * PSCurrInit_E * pA/ms - g_in' += spikeInh * PSCurrInit_I * pA/ms end end diff --git a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java index 33141bb0e..ec36833a1 100644 --- a/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java +++ b/src/main/java/org/nest/codegeneration/sympy/ExactSolutionTransformer.java @@ -43,8 +43,7 @@ ASTNeuron addExactSolution( computeShapeStateVariablesWithInitialValues(solverOutput); // copy initial block variables to the state block, since they are not backed through an ODE. - astNeuron.getInitialValuesDeclarations() - .forEach(astNeuron::addToStateBlock); + astNeuron.getInitialValuesDeclarations().forEach(astNeuron::addToStateBlock); workingVersion = addVariablesToInitialValues(workingVersion, stateShapeVariablesWithInitialValues); addStateUpdates(solverOutput, workingVersion); diff --git a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java index 967aae912..26fff7b79 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTNeuron.java +++ b/src/main/java/org/nest/nestml/_ast/ASTNeuron.java @@ -305,7 +305,7 @@ public void addToInitialValuesBlock(ASTDeclaration astDeclaration) { } public void addToStateBlock(final ASTDeclaration astDeclaration) { - if (!this.getInternalBlock().isPresent()) { + if (!this.getStateBlock().isPresent()) { final ASTBlockWithVariables stateBlock = AstCreator.createStateBlock(); getBlockWithVariabless().add(stateBlock); } diff --git a/src/main/java/org/nest/nestml/_cocos/EquationsOnlyForStateVariables.java b/src/main/java/org/nest/nestml/_cocos/EquationsOnlyForInitialValues.java similarity index 64% rename from src/main/java/org/nest/nestml/_cocos/EquationsOnlyForStateVariables.java rename to src/main/java/org/nest/nestml/_cocos/EquationsOnlyForInitialValues.java index c37716842..491b92ad1 100644 --- a/src/main/java/org/nest/nestml/_cocos/EquationsOnlyForStateVariables.java +++ b/src/main/java/org/nest/nestml/_cocos/EquationsOnlyForInitialValues.java @@ -23,6 +23,7 @@ import de.monticore.symboltable.Scope; import de.se_rwth.commons.logging.Log; import org.nest.nestml._ast.ASTEquation; +import org.nest.nestml._ast.ASTShape; import org.nest.nestml._symboltable.symbols.VariableSymbol; import java.util.Optional; @@ -34,7 +35,7 @@ * * @author plotnikov */ -public class EquationsOnlyForStateVariables implements NESTMLASTEquationCoCo { +public class EquationsOnlyForInitialValues implements NESTMLASTEquationCoCo, NESTMLASTShapeCoCo { @Override public void check(final ASTEquation astEq) { @@ -62,4 +63,29 @@ public void check(final ASTEquation astEq) { } + @Override + public void check(final ASTShape astShape) { + checkArgument(astShape.getEnclosingScope().isPresent(), "No scope was assigned. Please, run symboltable creator."); + final Scope scope = astShape.getEnclosingScope().get(); + + if (astShape.getLhs().getDifferentialOrder().size() > 0) { + final Optional variableSymbol = scope.resolve(astShape.getLhs().getSimpleName(), VariableSymbol.KIND); + if (variableSymbol.isPresent()) { + if (!variableSymbol.get().isInInitialValues()) { + final String msg = NestmlErrorStrings.message(this,variableSymbol.get().getName()); + + Log.error(msg, astShape.get_SourcePositionStart()); + } + } + else { + final String msg = NestmlErrorStrings.getErrorMsgVariableNotDefined(this, astShape.getLhs().getSimpleName()); + Log.error(msg, astShape.get_SourcePositionStart()); + } + + } + else { + Log.trace("The lefthandside of an equation must be a derivative, e.g. " + astShape.getLhs().toString() + "'", this.getClass().getSimpleName()); + } + + } } diff --git a/src/main/java/org/nest/nestml/_cocos/NestmlErrorStrings.java b/src/main/java/org/nest/nestml/_cocos/NestmlErrorStrings.java index 62975cfe2..1122f1c5a 100644 --- a/src/main/java/org/nest/nestml/_cocos/NestmlErrorStrings.java +++ b/src/main/java/org/nest/nestml/_cocos/NestmlErrorStrings.java @@ -144,21 +144,21 @@ static String code(final CurrentPortIsInhOrExc coco) { } static public String message( - final EquationsOnlyForStateVariables coco, + final EquationsOnlyForInitialValues coco, final String variableName) { final String ERROR_MSG_FORMAT = "The variable " + variableName + " must defined in the 'initial_values' block" + " for being used on the left side of an ODE."; return code(coco) + SEPARATOR + ERROR_MSG_FORMAT; } - static public String getErrorMsgVariableNotDefined(EquationsOnlyForStateVariables coco, final String variableName) { + static public String getErrorMsgVariableNotDefined(EquationsOnlyForInitialValues coco, final String variableName) { final String ERROR_MSG_FORMAT = "The variable " + variableName + " used as left-hand side " + "of the ode is not defined."; return code(coco) + SEPARATOR + ERROR_MSG_FORMAT; } @SuppressWarnings({"unused"}) // used for the routing - static String code(final EquationsOnlyForStateVariables coco) { + static String code(final EquationsOnlyForInitialValues coco) { return "NESTML_EQUATIONS_ONLY_FOR_STATE_VARIABLES"; } diff --git a/src/main/java/org/nest/nestml/_cocos/RestrictUseOfShapes.java b/src/main/java/org/nest/nestml/_cocos/RestrictUseOfShapes.java index 5233a0d8f..1f19982d2 100644 --- a/src/main/java/org/nest/nestml/_cocos/RestrictUseOfShapes.java +++ b/src/main/java/org/nest/nestml/_cocos/RestrictUseOfShapes.java @@ -1,13 +1,12 @@ package org.nest.nestml._cocos; import de.monticore.ast.ASTNode; -import org.nest.nestml._ast.ASTFunctionCall; -import org.nest.nestml._ast.ASTVariable; -import org.nest.nestml._ast.ASTNeuron; -import org.nest.nestml._visitor.NESTMLVisitor; -import org.nest.nestml._ast.ASTDerivative; -import org.nest.nestml._ast.ASTShape; +import de.monticore.symboltable.Scope; +import de.monticore.symboltable.Symbol; +import org.nest.nestml._ast.*; import org.nest.nestml._symboltable.predefined.PredefinedFunctions; +import org.nest.nestml._symboltable.symbols.VariableSymbol; +import org.nest.nestml._visitor.NESTMLVisitor; import org.nest.utils.AstUtils; import java.util.ArrayList; @@ -17,15 +16,27 @@ import static de.se_rwth.commons.logging.Log.error; /** - * @author traeder + * Forbids the usage of the functional shapes everywhere but in the convolve-call. + * @author traeder, plotnikov */ public class RestrictUseOfShapes implements NESTMLASTNeuronCoCo { + @Override + public void check(final ASTNeuron node) { + + ShapeCollectingVisitor shapeCollectingVisitor = new ShapeCollectingVisitor(); + List shapeNames = shapeCollectingVisitor.collectShapes(node); + + ShapeUsageVisitor shapeUsageVisitor = new ShapeUsageVisitor(shapeNames); + shapeUsageVisitor.workOn(node); + + } + public class ShapeCollectingVisitor implements NESTMLVisitor { private List shapeNames = new ArrayList<>(); - List collectShapes(ASTNeuron node){ + List collectShapes(ASTNeuron node) { node.accept(this); return shapeNames; } @@ -33,69 +44,81 @@ List collectShapes(ASTNeuron node){ @Override public void visit(ASTShape node) { ASTDerivative shapeVar = node.getLhs(); - shapeNames.add(shapeVar.getName().toString()); + shapeNames.add(shapeVar.getName()); } + } - class ShapeUsageVisitor implements NESTMLVisitor{ + class ShapeUsageVisitor implements NESTMLVisitor { private List shapes; private ASTNeuron neuronNode; - ShapeUsageVisitor(List shapes){ + ShapeUsageVisitor(List shapes) { this.shapes = shapes; } - void workOn(ASTNeuron node){ + void workOn(ASTNeuron node) { neuronNode = node; node.accept(this); } - public void visit(ASTVariable node){ - for(String shapeName: shapes){ - if(node.getName().toString().equals(shapeName)){ - Optional parent = AstUtils.getParent(node,neuronNode); - if(parent.isPresent()){ - //Dont mind its own declaration - if(parent.get() instanceof ASTShape){ - continue; - } - //We have to dig deeper for funcitonCalls: - Optional grandparent = AstUtils.getParent(parent.get(),neuronNode); - if(grandparent.isPresent() && - grandparent.get() instanceof ASTFunctionCall){ - ASTFunctionCall grandparentCall = (ASTFunctionCall) grandparent.get(); - if(grandparentCall.getCalleeName().equals(PredefinedFunctions.CURR_SUM) || - grandparentCall.getCalleeName().equals(PredefinedFunctions.COND_SUM)){ + @Override + public void visit(final ASTVariable astVariable) { + final Scope scope = astVariable.getEnclosingScope().get(); + + for (String shapeName : shapes) { + final Optional shapeVariable = scope.resolve(shapeName, VariableSymbol.KIND); + + // shapes as ODEs can be still used as normal variables. only functions must be checked. + if (shapeVariable.isPresent() && shapeVariable.get().isFunctionalShape()) { + if (astVariable.getName().equals(shapeName)) { + final Optional parent = AstUtils.getParent(astVariable, neuronNode); + if (parent.isPresent()) { + // Don't mind its own declaration + if (parent.get() instanceof ASTShape) { continue; } + // We have to dig deeper for funcitonCalls: + final Optional grandparent = AstUtils.getParent(parent.get(), neuronNode); + if (grandparent.isPresent() && + grandparent.get() instanceof ASTFunctionCall) { + ASTFunctionCall grandparentCall = (ASTFunctionCall) grandparent.get(); + if (grandparentCall.getCalleeName().equals(PredefinedFunctions.CURR_SUM) || + grandparentCall.getCalleeName().equals(PredefinedFunctions.COND_SUM)) { + continue; + } + + } + } + final String errorMsg = NestmlErrorStrings.message(RestrictUseOfShapes.this); + + error(errorMsg, astVariable.get_SourcePositionStart()); } - final String errorMsg = NestmlErrorStrings.message(RestrictUseOfShapes.this); - error(errorMsg,node.get_SourcePositionStart()); } - } - } - public void visit(ASTDerivative node){ - for(String shapeName: shapes){ - if(node.getName().toString().equals(shapeName)){ - final String errorMsg = NestmlErrorStrings.message(RestrictUseOfShapes.this); - error(errorMsg,node.get_SourcePositionStart()); - } } - } - } - @Override - public void check(ASTNeuron node) { + } - ShapeCollectingVisitor shapeCollectingVisitor = new ShapeCollectingVisitor(); - List shapeNames = shapeCollectingVisitor.collectShapes(node); + @Override + public void visit(final ASTEquation astEquation) { + final Scope scope = astEquation.getEnclosingScope().get(); + + final Optional shapeVariable = scope.resolve( + astEquation.getLhs().getNameOfDerivedVariable(), + VariableSymbol.KIND); + if (shapeVariable.isPresent() && + shapeVariable.get().isFunctionalShape() && + shapes.contains(shapeVariable.get().getName())) { + final String errorMsg = NestmlErrorStrings.message(RestrictUseOfShapes.this); + error(errorMsg, astEquation.get_SourcePositionStart()); + } - ShapeUsageVisitor shapeUsageVisitor = new ShapeUsageVisitor(shapeNames); - shapeUsageVisitor.workOn(node); + } } + } diff --git a/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java b/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java index 8ebdb06cf..5f933ced4 100644 --- a/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java +++ b/src/main/java/org/nest/nestml/_symboltable/NestmlCoCosManager.java @@ -160,8 +160,9 @@ private void registerCocos() { final SumHasCorrectParameter _sumHasCorrectParameter = new SumHasCorrectParameter(); nestmlCoCoChecker.addCoCo(_sumHasCorrectParameter); - final EquationsOnlyForStateVariables equationsOnlyForStateVariables = new EquationsOnlyForStateVariables(); - nestmlCoCoChecker.addCoCo(equationsOnlyForStateVariables); + final EquationsOnlyForInitialValues equationsOnlyForInitialValues = new EquationsOnlyForInitialValues(); + nestmlCoCoChecker.addCoCo((NESTMLASTEquationCoCo) equationsOnlyForInitialValues); + nestmlCoCoChecker.addCoCo((NESTMLASTShapeCoCo) equationsOnlyForInitialValues); final DerivativeOrderAtLeastOne derivativeOrderAtLeastOne = new DerivativeOrderAtLeastOne(); nestmlCoCoChecker.addCoCo(derivativeOrderAtLeastOne); diff --git a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java index 2563a1782..b4683853c 100644 --- a/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java +++ b/src/main/java/org/nest/nestml/_symboltable/symbols/VariableSymbol.java @@ -176,6 +176,10 @@ public void setVectorParameter(final String arraySizeParameter) { this.arraySizeParameter = arraySizeParameter; } + public boolean isFunctionalShape() { + return variableType == VariableType.SHAPE && !getName().contains("'"); + } + public boolean isState() { return blockType == BlockType.STATE; } diff --git a/src/test/java/org/nest/codegeneration/sympy/EquationsBlockProcessorTest.java b/src/test/java/org/nest/codegeneration/sympy/EquationsBlockProcessorTest.java index 9a0606218..09696a206 100644 --- a/src/test/java/org/nest/codegeneration/sympy/EquationsBlockProcessorTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/EquationsBlockProcessorTest.java @@ -27,9 +27,11 @@ import org.nest.base.ModelbasedTest; import org.nest.codegeneration.sympy.EquationsBlockProcessor; import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml._ast.ASTNeuron; import org.nest.nestml._symboltable.symbols.NeuronSymbol; import org.nest.nestml._symboltable.symbols.VariableSymbol; import org.nest.nestml.prettyprinter.NESTMLPrettyPrinter; +import org.nest.utils.AstUtils; import org.nest.utils.FilesHelper; import java.nio.file.Path; @@ -72,10 +74,10 @@ public void test_cond_model() throws Exception { final Optional y1 = neuronSymbol.get().getVariableByName("g_in"); final Optional y2 = neuronSymbol.get().getVariableByName("g_ex"); assertTrue(y1.isPresent()); - assertTrue(y1.get().getBlockType().equals(VariableSymbol.BlockType.STATE)); + assertTrue(y1.get().getBlockType().equals(VariableSymbol.BlockType.INITIAL_VALUES)); assertTrue(y2.isPresent()); - assertTrue(y2.get().getBlockType().equals(VariableSymbol.BlockType.STATE)); + assertTrue(y2.get().getBlockType().equals(VariableSymbol.BlockType.INITIAL_VALUES)); } @Test @@ -97,9 +99,10 @@ private Scope solveOdesAndShapes(final String pathToModel) { final Path outputBase = Paths.get(OUTPUT_FOLDER.toString(), Names.getPathFromQualifiedName(pathToModel)); FilesHelper.deleteFilesInFolder(outputBase); - testant.solveOdeWithShapes(modelRoot.getNeurons().get(0), outputBase); - System.out.println(NESTMLPrettyPrinter.print(modelRoot.getNeurons().get(0))); - return scopeCreator.runSymbolTableCreator(modelRoot); + final ASTNeuron solvedNeuron = testant.solveOdeWithShapes(modelRoot.getNeurons().get(0), outputBase); + + return AstUtils.deepCloneNeuronAndBuildSymbolTable(solvedNeuron, OUTPUT_FOLDER).getSpannedScope().get(); + } } \ No newline at end of file diff --git a/src/test/java/org/nest/codegeneration/sympy/ExactSolutionTransformerTest.java b/src/test/java/org/nest/codegeneration/sympy/ExactSolutionTransformerTest.java index 3d361afce..7e38f5f21 100644 --- a/src/test/java/org/nest/codegeneration/sympy/ExactSolutionTransformerTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/ExactSolutionTransformerTest.java @@ -55,11 +55,6 @@ public void testExactSolutionTransformation() { assertTrue(pscInitialValue.isPresent()); assertTrue(pscInitialValue.get().getBlockType().equals(VariableSymbol.BlockType.STATE)); - - final Optional y2 = neuronSymbol.get().getVariableByName("iv__I_shape_in__0"); - assertTrue(y2.isPresent()); - assertTrue(y2.get().getBlockType().equals(VariableSymbol.BlockType.INTERNALS)); - } @Test diff --git a/src/test/java/org/nest/codegeneration/sympy/ShapesToOdesTransformerTest.java b/src/test/java/org/nest/codegeneration/sympy/ShapesToOdesTransformerTest.java index 148dfdceb..2c1f8da49 100644 --- a/src/test/java/org/nest/codegeneration/sympy/ShapesToOdesTransformerTest.java +++ b/src/test/java/org/nest/codegeneration/sympy/ShapesToOdesTransformerTest.java @@ -46,21 +46,21 @@ public void testExactSolutionTransformation() { Optional neuronSymbol = scope.resolve(NEURON_NAME, NeuronSymbol.KIND); assertTrue(neuronSymbol.isPresent()); - final Optional pscInitialValue1 = neuronSymbol.get().getVariableByName("iv__g_in"); + final Optional pscInitialValue1 = neuronSymbol.get().getVariableByName("g_in"); assertTrue(pscInitialValue1.isPresent()); - assertTrue(pscInitialValue1.get().getBlockType().equals(VariableSymbol.BlockType.INTERNALS)); + assertTrue(pscInitialValue1.get().getBlockType().equals(VariableSymbol.BlockType.INITIAL_VALUES)); - final Optional pscInitialValue2 = neuronSymbol.get().getVariableByName("iv__g_in__1"); + final Optional pscInitialValue2 = neuronSymbol.get().getVariableByName("g_in__1"); assertTrue(pscInitialValue2.isPresent()); - assertTrue(pscInitialValue2.get().getBlockType().equals(VariableSymbol.BlockType.INTERNALS)); + assertTrue(pscInitialValue2.get().getBlockType().equals(VariableSymbol.BlockType.INITIAL_VALUES)); final Optional shapeAsState = neuronSymbol.get().getVariableByName("g_in"); assertTrue(shapeAsState.isPresent()); - assertTrue(shapeAsState.get().getBlockType().equals(VariableSymbol.BlockType.STATE)); + assertTrue(shapeAsState.get().getBlockType().equals(VariableSymbol.BlockType.INITIAL_VALUES)); final Optional derivedStateVariable = neuronSymbol.get().getVariableByName("g_ex__1"); assertTrue(derivedStateVariable.isPresent()); - assertTrue(derivedStateVariable.get().getBlockType().equals(VariableSymbol.BlockType.STATE)); + assertTrue(derivedStateVariable.get().getBlockType().equals(VariableSymbol.BlockType.INITIAL_VALUES)); } diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index 6ba9238c7..2b01b76f9 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -127,7 +127,7 @@ public void testTutorialModels() { @Test public void manually() { final String[] args = new String[] { - "models/mat2_psc_exp.nestml", + "models/terub_neuron_stn.nestml", "--json_log", "model_issues", "--enable_tracing", "--target", outputPath.toString()}; diff --git a/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java b/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java index 1391593da..3db9e9fe8 100644 --- a/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java +++ b/src/test/java/org/nest/nestml/_cocos/NestmlCoCosTest.java @@ -6,13 +6,11 @@ package org.nest.nestml._cocos; import de.se_rwth.commons.Names; -import de.se_rwth.commons.logging.Log; import org.junit.Before; import org.junit.Test; import org.nest.base.ModelbasedTest; import org.nest.nestml._ast.ASTNESTMLCompilationUnit; import org.nest.nestml._symboltable.NESTMLScopeCreator; -import org.nest.nestml.prettyprinter.NESTMLPrettyPrinter; import org.nest.nestml._symboltable.predefined.PredefinedTypes; import org.nest.nestml._symboltable.symbols.TypeSymbol; @@ -177,25 +175,25 @@ public void testResolvingOfPredefinedTypes() { @Test public void testRestrictUseOfShapes(){ + final RestrictUseOfShapes restrictUseOfShapes = new RestrictUseOfShapes(); + nestmlCoCoChecker.addCoCo(restrictUseOfShapes); + + /* final Optional validRoot = getAstRoot( - TEST_MODELS_FOLDER + "restrictUseOfShapes/valid.nestml"); + TEST_VALID_MODELS_FOLDER + "/restrictUseOfShapes.nestml"); assertTrue(validRoot.isPresent()); scopeCreator.runSymbolTableCreator(validRoot.get()); - final RestrictUseOfShapes restrictUseOfShapes = new RestrictUseOfShapes(); - nestmlCoCoChecker.addCoCo(restrictUseOfShapes); nestmlCoCoChecker.checkAll(validRoot.get()); Integer errorsFound = countErrorsByPrefix(NestmlErrorStrings.code(restrictUseOfShapes), getFindings()); - assertEquals(Integer.valueOf(0), errorsFound); - - Log.getFindings().clear(); + assertEquals(Integer.valueOf(0), errorsFound);*/ + Integer errorsFound; final Optional invalidRoot = getAstRoot( - TEST_MODELS_FOLDER + "restrictUseOfShapes/invalid.nestml"); + TEST_INVALID_MODELS_FOLDER + "/restrictUseOfShapes.nestml"); assertTrue(invalidRoot.isPresent()); scopeCreator.runSymbolTableCreator(invalidRoot.get()); - nestmlCoCoChecker.checkAll(invalidRoot.get()); errorsFound = countErrorsByPrefix(NestmlErrorStrings.code(restrictUseOfShapes), getFindings()); assertEquals(Integer.valueOf(5), errorsFound); @@ -658,18 +656,18 @@ public void testAliasHasDefiningExpression() { } @Test - public void testOnlyStateVariablesInOde() { - final EquationsOnlyForStateVariables equationsOnlyForStateVariables - = new EquationsOnlyForStateVariables(); - nestmlCoCoChecker.addCoCo(equationsOnlyForStateVariables); + public void testEquationsOnlyForInitialValues() { + final EquationsOnlyForInitialValues equationsOnlyForInitialValues = new EquationsOnlyForInitialValues(); + nestmlCoCoChecker.addCoCo((NESTMLASTEquationCoCo) equationsOnlyForInitialValues); + nestmlCoCoChecker.addCoCo((NESTMLASTShapeCoCo) equationsOnlyForInitialValues); - final Path pathToValidModel = Paths.get(TEST_MODELS_FOLDER, "valid/equationsOnlyForStateVariables.nestml"); + final Path pathToValidModel = Paths.get(TEST_MODELS_FOLDER, "valid/equationsOnlyForInitialValues.nestml"); checkModelAndAssertNoErrors( pathToValidModel, nestmlCoCoChecker, - NestmlErrorStrings.code(equationsOnlyForStateVariables)); + NestmlErrorStrings.code(equationsOnlyForInitialValues)); - final Path pathToInvalidModel = Paths.get(TEST_MODELS_FOLDER, "invalid/equationsOnlyForStateVariables.nestml"); + final Path pathToInvalidModel = Paths.get(TEST_MODELS_FOLDER, "invalid/equationsOnlyForInitialValues.nestml"); final Optional ast = getAstRoot(pathToInvalidModel.toString()); scopeCreator.runSymbolTableCreator(ast.get()); @@ -677,7 +675,7 @@ public void testOnlyStateVariablesInOde() { checkModelAndAssertWithErrors( pathToInvalidModel, nestmlCoCoChecker, - NestmlErrorStrings.code(equationsOnlyForStateVariables), + NestmlErrorStrings.code(equationsOnlyForInitialValues), 2); } diff --git a/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java b/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java index 328add652..bf1d2d3e3 100644 --- a/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java +++ b/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java @@ -68,8 +68,8 @@ public void testCommentsExtraction() throws IOException { assertTrue(ast.isPresent()); final List declarations = AstUtils.getAll(ast.get(), ASTDeclaration.class); for (final ASTDeclaration declaration:declarations) { - assertEquals(3, declaration.getDocStrings().size()); declaration.getDocStrings().forEach(System.out::println); + assertEquals(4, declaration.getDocStrings().size()); } } diff --git a/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java b/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java index 28c8f9f3b..4ead9c63a 100644 --- a/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java +++ b/src/test/java/org/nest/nestml/_symboltable/NESTMLSymbolTableCreatorTest.java @@ -60,8 +60,8 @@ public void testCreationOfSymtabAndResolvingOfSymbols() throws IOException { assertTrue(y0TVariable.get().isRecordable()); assertTrue(y1Varialbe.isPresent()); - assertTrue(y1Varialbe.get().isInInitialValues()); - assertTrue(y1Varialbe.get().getOdeDeclaration().isPresent()); + assertFalse(y1Varialbe.get().isInInitialValues()); + assertFalse(y1Varialbe.get().getOdeDeclaration().isPresent()); // Checks that the derived variable is also resolvable final Optional Dy0Varialbe = neuronTypeOptional.get().getSpannedScope().resolve("y0'", VariableSymbol.KIND); diff --git a/src/test/java/org/nest/units/UnitsTest.java b/src/test/java/org/nest/units/UnitsTest.java index ff1f0cdcc..363adf1d7 100644 --- a/src/test/java/org/nest/units/UnitsTest.java +++ b/src/test/java/org/nest/units/UnitsTest.java @@ -141,13 +141,6 @@ public void test_unit_ODEs(){ assertEquals(0, errorsFound); - //long warningsFound = Log.getFindings() - // .stream() - // .filter(finding -> finding.getType().equals(Finding.Type.WARNING)) - // .count(); - - // TODO fails assertEquals(0, warningsFound); - final Optional invalidRoot = getAstRoot( "src/test/resources/org/nest/nestml/_cocos/invalid/unitsInODEs.nestml"); @@ -167,7 +160,7 @@ public void test_unit_ODEs(){ .filter(finding -> finding.getType().equals(Finding.Type.WARNING)) .count(); - // TODO fails assertEquals(0, warningsFound); + // TODO: check me } @Test diff --git a/src/test/resources/codegeneration/iaf_psc_alpha_three_buffers.nestml b/src/test/resources/codegeneration/iaf_psc_alpha_three_buffers.nestml index 4f1cabf66..1570f2dee 100644 --- a/src/test/resources/codegeneration/iaf_psc_alpha_three_buffers.nestml +++ b/src/test/resources/codegeneration/iaf_psc_alpha_three_buffers.nestml @@ -1,7 +1,7 @@ neuron iaf_psc_alpha_neuron: - state: - V_abs mV + initial_values: + V_abs mV = 0mV function V_m mV = V_abs + E_L # Membrane potential. end diff --git a/src/test/resources/comments/iaf_neuron.nestml b/src/test/resources/comments/iaf_neuron.nestml index 292d43c97..6d56151e1 100644 --- a/src/test/resources/comments/iaf_neuron.nestml +++ b/src/test/resources/comments/iaf_neuron.nestml @@ -5,28 +5,28 @@ neuron iaf_neuron_nestml: # comment on block state: + # me 1 + # comment before variable V_abs + V_abs mV # comment in the same line as V_abs + # comment in the next line as V_abs + # ignore me - ## comment before variable V_abs - V_abs mV ## comment in the same line as V_abs - ## comment in the next line as V_abs - ## ignore me + # me2 + # comment before variable V_m + V_m mV # comment in the same line as V_m + # comment in the next line as V_m # ignore me - ## comment before variable V_m - V_m mV ## comment in the same line as V_m - ## comment in the next line as V_m - - ## ignore me end update: - # ignore me - ## comment before local1 - local1 real ## comment in the same line local1 - ## comment in the next line as local1 + # me 3 + # comment before local1 + local1 real # comment in the same line local1 + # comment in the next line as local1 - ## ignore me + # ignore me end end diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 8b21c929a..957437c3e 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -8,7 +8,7 @@ - + \ No newline at end of file diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index b26ce3738..a28ef8bf2 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -60,7 +60,7 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): # test_multysinapse() models = list() - models.append( ("mat2_psc_exp", "mat2_psc_exp_neuron", None, 0.001)) + models.append( ("terub_neuron_stn", "terub_neuron_stn_implicit", None, 0.001)) # models.append( ("iaf_cond_exp_sfa_rr", "iaf_cond_exp_sfa_rr_implicit", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: diff --git a/src/test/resources/org/nest/nestml/_cocos/invalid/equationsOnlyForStateVariables.nestml b/src/test/resources/org/nest/nestml/_cocos/invalid/equationsOnlyForInitialValues.nestml similarity index 85% rename from src/test/resources/org/nest/nestml/_cocos/invalid/equationsOnlyForStateVariables.nestml rename to src/test/resources/org/nest/nestml/_cocos/invalid/equationsOnlyForInitialValues.nestml index 109f987b9..2c2bc0908 100644 --- a/src/test/resources/org/nest/nestml/_cocos/invalid/equationsOnlyForStateVariables.nestml +++ b/src/test/resources/org/nest/nestml/_cocos/invalid/equationsOnlyForInitialValues.nestml @@ -2,16 +2,16 @@ neuron iaf_neuron_ode: state: V_m mV + G real end equations: - G' = e * t + shape G' = e * t Tau' = -1/Tau * V_m + 1/C_m end parameters: C_m pF = 250pF # Capacity of the membrane Tau ms = 10 # Membrane time constant. - G ms end end \ No newline at end of file diff --git a/src/test/resources/org/nest/nestml/_cocos/restrictUseOfShapes/invalid.nestml b/src/test/resources/org/nest/nestml/_cocos/invalid/restrictUseOfShapes.nestml similarity index 85% rename from src/test/resources/org/nest/nestml/_cocos/restrictUseOfShapes/invalid.nestml rename to src/test/resources/org/nest/nestml/_cocos/invalid/restrictUseOfShapes.nestml index e4fd71c6e..be5ee752a 100644 --- a/src/test/resources/org/nest/nestml/_cocos/restrictUseOfShapes/invalid.nestml +++ b/src/test/resources/org/nest/nestml/_cocos/invalid/restrictUseOfShapes.nestml @@ -1,6 +1,6 @@ neuron invalidShapes: state: - StateVar real + StateVar real end input: @@ -15,7 +15,7 @@ neuron invalidShapes: output: spike equations: - shape testShape = 1.5 + shape testShape = 1.5 *t testShape' = 10 /s #Error end @@ -28,4 +28,7 @@ neuron invalidShapes: foo(testShape) #Error testShape += 3 #Error end + + function foo(tt real): + end end diff --git a/src/test/resources/org/nest/nestml/_cocos/invalid/unitsInODEs.nestml b/src/test/resources/org/nest/nestml/_cocos/invalid/unitsInODEs.nestml index be8657bdf..b37e25267 100644 --- a/src/test/resources/org/nest/nestml/_cocos/invalid/unitsInODEs.nestml +++ b/src/test/resources/org/nest/nestml/_cocos/invalid/unitsInODEs.nestml @@ -1,7 +1,6 @@ neuron validODETest: - state: + initial_values: Distance km - DeltaTime s end input: @@ -10,7 +9,8 @@ neuron validODETest: currents <- current end - parameters: + parameters: + DeltaTime s end output: spike diff --git a/src/test/resources/org/nest/nestml/_cocos/restrictUseOfShapes/valid.nestml b/src/test/resources/org/nest/nestml/_cocos/restrictUseOfShapes/valid.nestml deleted file mode 100644 index d639b4031..000000000 --- a/src/test/resources/org/nest/nestml/_cocos/restrictUseOfShapes/valid.nestml +++ /dev/null @@ -1,27 +0,0 @@ -neuron validShapes: - state: - end - - input: - spikeInh <- inhibitory spike - spikeExc <- excitatory spike - currents <- current - end - - parameters: - end - - output: spike - - equations: - shape testShape = 1.5 - end - - internals: - end - - update: - curr_sum(testShape) - cond_sum(testShape) - end -end diff --git a/src/test/resources/org/nest/nestml/_cocos/valid/equationsOnlyForStateVariables.nestml b/src/test/resources/org/nest/nestml/_cocos/valid/equationsOnlyForInitialValues.nestml similarity index 66% rename from src/test/resources/org/nest/nestml/_cocos/valid/equationsOnlyForStateVariables.nestml rename to src/test/resources/org/nest/nestml/_cocos/valid/equationsOnlyForInitialValues.nestml index 1f16fa04c..2eecfceef 100644 --- a/src/test/resources/org/nest/nestml/_cocos/valid/equationsOnlyForStateVariables.nestml +++ b/src/test/resources/org/nest/nestml/_cocos/valid/equationsOnlyForInitialValues.nestml @@ -1,17 +1,17 @@ neuron iaf_neuron_ode: - state: + initial_values: V_m mV G ms end equations: - G' = e * t + shape G' = e * t V_m' = -1/Tau * V_m + 1/C_m end parameters: C_m pF = 250pF # Capacity of the membrane - Tau ms = 10 # Membrane time constant. + Tau ms = 10ms # Membrane time constant. end end diff --git a/src/test/resources/org/nest/nestml/_cocos/valid/restrictUseOfShapes.nestml b/src/test/resources/org/nest/nestml/_cocos/valid/restrictUseOfShapes.nestml new file mode 100644 index 000000000..e79c003a3 --- /dev/null +++ b/src/test/resources/org/nest/nestml/_cocos/valid/restrictUseOfShapes.nestml @@ -0,0 +1,28 @@ +neuron validShapes: + state: + end + + input: + spikeInh <- inhibitory spike + spikeExc <- excitatory spike + currents <- current + end + + parameters: + end + + output: spike + + equations: + shape testShape = 1.5 * t + function AA pA = curr_sum(spikeInh, testShape) + function BB nS = cond_sum(spikeExc, testShape) + end + + internals: + end + + update: + + end +end diff --git a/src/test/resources/org/nest/nestml/_cocos/valid/unitsInODEs.nestml b/src/test/resources/org/nest/nestml/_cocos/valid/unitsInODEs.nestml index df78ef33c..0de2b0fb8 100644 --- a/src/test/resources/org/nest/nestml/_cocos/valid/unitsInODEs.nestml +++ b/src/test/resources/org/nest/nestml/_cocos/valid/unitsInODEs.nestml @@ -1,7 +1,6 @@ neuron validODETest: - state: + initial_values: Distance km - DeltaTime s end input: @@ -10,7 +9,7 @@ neuron validODETest: currents <- current end - parameters: + parameters: end output: spike @@ -20,6 +19,7 @@ neuron validODETest: end internals: + DeltaTime s end update: diff --git a/src/test/resources/org/nest/nestml/_symboltable/iaf_neuron.nestml b/src/test/resources/org/nest/nestml/_symboltable/iaf_neuron.nestml index 40dfac42c..7adf2b4fd 100644 --- a/src/test/resources/org/nest/nestml/_symboltable/iaf_neuron.nestml +++ b/src/test/resources/org/nest/nestml/_symboltable/iaf_neuron.nestml @@ -1,12 +1,15 @@ neuron iaf_neuron: state: - y0 mV - y0' mV y1 mV y2 mV - y3 mV # Membrane potential. + end + + initial_values: + y0 mV = 0mV + y0' mV = 0mV/ms + y3 mV function V_m mV = y3 + E_L end From 0364e9b3ac8d932cc3caf572cbdbdd074c257d63 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Fri, 29 Sep 2017 09:45:24 +0200 Subject: [PATCH 14/17] Fixes further model set --- models/iaf_cond_exp.nestml | 90 +------------------ models/terub_neuron_gpe.nestml | 30 +++---- models/terub_neuron_stn.nestml | 8 +- .../org/nest/frontend/NestmlFrontendTest.java | 12 +-- src/test/resources/logback-test.xml | 2 +- src/test/resources/neuron_tester.py | 2 +- .../resources/tutorial/11.rc_neuron.nestml | 2 +- .../tutorial/12.rc_neuron_rel.nestml | 7 +- src/test/resources/tutorial/21_rc_fire.nestml | 2 +- .../tutorial/22_rc_refractory.nestml | 5 +- .../resources/tutorial/31_rc_input.nestml | 5 +- .../resources/tutorial/32_rc_alpha.nestml | 17 ++-- .../resources/tutorial/33_rc_shape.nestml | 5 +- src/test/resources/tutorial/41_iaf.nestml | 2 +- .../resources/tutorial/42_quadratic.nestml | 2 +- src/test/resources/tutorial/izhikevich.nestml | 4 +- 16 files changed, 52 insertions(+), 143 deletions(-) diff --git a/models/iaf_cond_exp.nestml b/models/iaf_cond_exp.nestml index 3a7f0d2f6..4025830dc 100644 --- a/models/iaf_cond_exp.nestml +++ b/models/iaf_cond_exp.nestml @@ -1,89 +1,3 @@ -/* -Name: iaf_cond_exp_neuron - Simple conductance based leaky integrate-and-fire neuron - model. - -Description: -iaf_cond_exp is an implementation of a spiking neuron using IAF dynamics with -conductance-based synapses. Incoming spike events induce a post-synaptic change -of conductance modelled by an exponential function. The exponential function -is normalised such that an event of weight 1.0 results in a peak conductance of -1 nS. - -Sends: SpikeEvent - -Receives: SpikeEvent, CurrentEvent, DataLoggingRequest - -References: - -Meffin, H., Burkitt, A. N., & Grayden, D. B. (2004). An analytical -model for the large, fluctuating synaptic conductance state typical of -neocortical neurons in vivo. J. Comput. Neurosci., 16, 159-175. - -Author: Sven Schrader - -SeeAlso: iaf_psc_delta, iaf_psc_exp, iaf_cond_exp -*/ -neuron iaf_cond_exp_neuron: - - state: - r integer # counts number of tick during the refractory period - end - - initial_values: - V_m mV = E_L # membrane potential - end - - equations: - shape g_in = exp(-t/tau_syn_in) # inputs from the inh conductance - shape g_ex = exp(-t/tau_syn_ex) # inputs from the exc conductance - - function I_syn_exc pA = cond_sum(g_ex, spikeExc) * ( V_m - E_ex ) - function I_syn_inh pA = cond_sum(g_in, spikeInh) * ( V_m - E_in ) - function I_leak pA = g_L * ( V_m - E_L ) - V_m' = ( -I_leak - I_syn_exc - I_syn_inh + currents + I_e ) / C_m - end - - parameters: - V_th mV = -55.0mV # Threshold Potential in mV - V_reset mV = -60.0mV # Reset Potential in mV - t_ref ms = 2.0 ms # Refractory period in ms - g_L nS = 16.6667nS # Leak Conductance in nS - C_m pF = 250.0 pF # Membrane Capacitance in pF - E_ex mV = 0mV # Excitatory reversal Potential in mV - E_in mV = -85.0mV # Inhibitory reversal Potential in mV - E_L mV = -70.0mV # Leak reversal Potential (aka resting potential) in mV - tau_syn_ex ms = 0.2ms # Synaptic Time Constant Excitatory Synapse in ms - tau_syn_in ms = 2.0ms # Synaptic Time Constant for Inhibitory Synapse in ms - I_e pA = 0pA # Constant Current in pA - end - - internals: - RefractoryCounts integer = steps(t_ref) # refractory time in steps - end - - input: - spikeInh <- inhibitory spike - spikeExc <- excitatory spike - currents <- current - end - - output: spike - - update: - integrate_odes() - if r != 0: # neuron is absolute refractory - r = r - 1 - V_m = V_reset # clamp potential - elif V_m >= V_th: # neuron is not absolute refractory - r = RefractoryCounts - V_m = V_reset # clamp potential - emit_spike() - end - - end - -end - /* Name: iaf_cond_exp_implicit - Simple conductance based leaky integrate-and-fire neuron model. @@ -122,8 +36,8 @@ neuron iaf_cond_exp_implicit: end equations: - g_in' = -g_in/tau_synI - g_ex' = -g_ex/tau_synE + shape g_in' = -g_in/tau_synI + shape g_ex' = -g_ex/tau_synE function I_syn_exc pA = cond_sum(g_ex, spikeExc) * ( V_m - E_ex ) function I_syn_inh pA = cond_sum(g_in, spikeInh) * ( V_m - E_in ) function I_leak pA = g_L * ( V_m - E_L ) diff --git a/models/terub_neuron_gpe.nestml b/models/terub_neuron_gpe.nestml index 544eb5e98..4b3a468e0 100644 --- a/models/terub_neuron_gpe.nestml +++ b/models/terub_neuron_gpe.nestml @@ -223,15 +223,15 @@ neuron terub_neuron_gpe_implicit: initial_values: V_m mV = E_L # Membrane potential - g_in pA = 0pA # Inhibitory synaptic conductance - g_in' pA/ms = pA * e / tau_syn_in # Inhibitory synaptic conductance - g_ex pA = 0pA # Excitatory synaptic conductance - g_ex' pA/ms = pA * e / tau_syn_ex # Excitatory synaptic conductance - - gate_h real # gating variable h - gate_n real # gating variable n - gate_r real # gating variable r - Ca_con real # gating variable r + gate_h real = 0 # gating variable h + gate_n real = 0 # gating variable n + gate_r real = 0 # gating variable r + Ca_con real = 0 # gating variable r + + g_in pA = 0 nS # Excitatory synaptic conductance + g_in' pA/mS = nS * e / tau_syn_in # Excitatory synaptic conductance + g_ex pA = 0 nS # Inhibitory synaptic conductance in nS + g_ex' pA/mS = nS * e / tau_syn_ex # Inhibitory synaptic conductance in nS end equations: @@ -293,13 +293,13 @@ neuron terub_neuron_gpe_implicit: function I_ahp real = g_ahp * (Ca_con / (Ca_con + g_k1)) * (V_m - E_K ) # synapses: alpha functions - ## alpha function for the g_in - g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in - g_in' = g_in' + # alpha function for the g_in + shape g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in + shape g_in' = g_in' - ## alpha function for the g_ex - g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex - g_ex' = g_ex' + # alpha function for the g_ex + shape g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex + shape g_ex' = g_ex' # V dot -- synaptic input are currents, inhib current is negative V_m' = ( -(I_Na + I_K + I_L + I_T + I_Ca + I_ahp)* pA + currents + I_e + I_ex_mod * pA + I_in_mod * pA) / C_m diff --git a/models/terub_neuron_stn.nestml b/models/terub_neuron_stn.nestml index c5b114152..bd73147f9 100644 --- a/models/terub_neuron_stn.nestml +++ b/models/terub_neuron_stn.nestml @@ -324,12 +324,12 @@ neuron terub_neuron_stn_implicit: # synapses: alpha functions ## alpha function for the g_in - g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in - g_in' = g_in' + shape g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in + shape g_in' = g_in' ## alpha function for the g_ex - g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex - g_ex' = g_ex' + shape g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex + shape g_ex' = g_ex' end parameters: diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index 2b01b76f9..2d74460e6 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -107,7 +107,7 @@ public void testJsonOutput() { @Test public void testModelsFolder() { final String[] args = new String[] { - "models/", + "models", "--json_log", "model_issues", "--target", outputPath.toString()}; @@ -124,14 +124,4 @@ public void testTutorialModels() { new NestmlFrontend().start(args); } - @Test - public void manually() { - final String[] args = new String[] { - "models/terub_neuron_stn.nestml", - "--json_log", "model_issues", - "--enable_tracing", - "--target", outputPath.toString()}; - - new NestmlFrontend().start(args); - } } diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 957437c3e..8b21c929a 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -8,7 +8,7 @@ - + \ No newline at end of file diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index a28ef8bf2..61b292d36 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -60,7 +60,7 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): # test_multysinapse() models = list() - models.append( ("terub_neuron_stn", "terub_neuron_stn_implicit", None, 0.001)) + models.append( ("terub_neuron_stn", "terub_neuron_stn_implicit", 1.e-3, 0.001)) # models.append( ("iaf_cond_exp_sfa_rr", "iaf_cond_exp_sfa_rr_implicit", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: diff --git a/src/test/resources/tutorial/11.rc_neuron.nestml b/src/test/resources/tutorial/11.rc_neuron.nestml index a4a26c824..8fc348a3b 100644 --- a/src/test/resources/tutorial/11.rc_neuron.nestml +++ b/src/test/resources/tutorial/11.rc_neuron.nestml @@ -3,7 +3,7 @@ */ neuron rc_neuron: - state: + initial_values: V_m mV = 0mV end diff --git a/src/test/resources/tutorial/12.rc_neuron_rel.nestml b/src/test/resources/tutorial/12.rc_neuron_rel.nestml index 7ad512787..957d4fb27 100644 --- a/src/test/resources/tutorial/12.rc_neuron_rel.nestml +++ b/src/test/resources/tutorial/12.rc_neuron_rel.nestml @@ -3,7 +3,9 @@ */ neuron rc_neuron_rel: - + initial_values: + V_m mV = E_L + end equations: V_m' = -(V_m - E_L)/tau_m + I_syn/C_m @@ -16,9 +18,6 @@ neuron rc_neuron_rel: I_syn pA = 10pA end - state: - V_m mV = E_L - end input: spikes <- spike diff --git a/src/test/resources/tutorial/21_rc_fire.nestml b/src/test/resources/tutorial/21_rc_fire.nestml index e9f657ecf..4251117f7 100644 --- a/src/test/resources/tutorial/21_rc_fire.nestml +++ b/src/test/resources/tutorial/21_rc_fire.nestml @@ -4,7 +4,7 @@ */ neuron rc_fire: - state: + initial_values: V_m mV = E_L end diff --git a/src/test/resources/tutorial/22_rc_refractory.nestml b/src/test/resources/tutorial/22_rc_refractory.nestml index 5522763f6..97807cd2c 100644 --- a/src/test/resources/tutorial/22_rc_refractory.nestml +++ b/src/test/resources/tutorial/22_rc_refractory.nestml @@ -5,10 +5,13 @@ neuron rc_refractory: state: - V_m mV = E_L refractory_counts integer = 0 end + initial_values: + V_m mV = E_L + end + equations: V_m' = -(V_m - E_L)/tau_m + I_syn/C_m end diff --git a/src/test/resources/tutorial/31_rc_input.nestml b/src/test/resources/tutorial/31_rc_input.nestml index c4090db65..4f6a64160 100644 --- a/src/test/resources/tutorial/31_rc_input.nestml +++ b/src/test/resources/tutorial/31_rc_input.nestml @@ -5,10 +5,13 @@ neuron rc_input: state: - V_m mV = E_L refractory_counts integer = 0 end + initial_values: + V_m mV = E_L + end + equations: V_m' = -(V_m - E_L)/tau_m + I_syn/C_m end diff --git a/src/test/resources/tutorial/32_rc_alpha.nestml b/src/test/resources/tutorial/32_rc_alpha.nestml index 2ea455a4e..ea49a0688 100644 --- a/src/test/resources/tutorial/32_rc_alpha.nestml +++ b/src/test/resources/tutorial/32_rc_alpha.nestml @@ -3,17 +3,19 @@ Adds alpha shapes for synaptic currents. */ neuron rc_alpha: - state: + refractory_counts integer = 0 + end + + initial_values: V_m mV = E_L g_ex pA = 0pA - g_ex' pA/ms = 0pA/ms - refractory_counts integer = 0 + g_ex' pA/ms = pA * e / tau_syn end equations: - g_ex'' = -g_ex' / tau_syn - g_ex' = g_ex' - ( g_ex / tau_syn ) + shape g_ex'' = -g_ex' / tau_syn + shape g_ex' = g_ex' - ( g_ex / tau_syn ) function I_syn pA = g_ex + currents + I_e V_m' = -(V_m - E_L)/tau_m + I_syn/C_m end @@ -30,10 +32,6 @@ neuron rc_alpha: I_e pA = 0pA end - internals: - PSConInit_E pA/ms = 1.0 pA * e / tau_syn - end - input: spikes <- spike currents <- current @@ -53,7 +51,6 @@ neuron rc_alpha: refractory_counts -= 1 end - g_ex' += PSConInit_E * spikes end end diff --git a/src/test/resources/tutorial/33_rc_shape.nestml b/src/test/resources/tutorial/33_rc_shape.nestml index 865444e73..ba36e8547 100644 --- a/src/test/resources/tutorial/33_rc_shape.nestml +++ b/src/test/resources/tutorial/33_rc_shape.nestml @@ -5,10 +5,13 @@ neuron rc_shape: state: - V_m mV = E_L refractory_counts integer = 0 end + initial_values: + V_m mV = E_L + end + equations: shape g_ex = (e/tau_syn) * t * exp(-1/tau_syn*t) function I_syn pA = curr_sum(g_ex, spikes) + currents + I_e diff --git a/src/test/resources/tutorial/41_iaf.nestml b/src/test/resources/tutorial/41_iaf.nestml index 1268a4506..d364dd568 100644 --- a/src/test/resources/tutorial/41_iaf.nestml +++ b/src/test/resources/tutorial/41_iaf.nestml @@ -3,7 +3,7 @@ */ neuron IaF: - state: + initial_values: V_m mV = 0mV end diff --git a/src/test/resources/tutorial/42_quadratic.nestml b/src/test/resources/tutorial/42_quadratic.nestml index ca2412dc3..d2d4cbd5d 100644 --- a/src/test/resources/tutorial/42_quadratic.nestml +++ b/src/test/resources/tutorial/42_quadratic.nestml @@ -3,7 +3,7 @@ */ neuron quadratic_IaF: - state: + initial_values: V_m mV = 0mV end diff --git a/src/test/resources/tutorial/izhikevich.nestml b/src/test/resources/tutorial/izhikevich.nestml index 60c963fca..b9ee8c09c 100644 --- a/src/test/resources/tutorial/izhikevich.nestml +++ b/src/test/resources/tutorial/izhikevich.nestml @@ -3,9 +3,9 @@ */ neuron izhikevich_neuron: - state: + initial_values: v mV = -65mV # Membrane potential in mV - u mV + u mV = 0mV # TODO add new variable U_m with the type real # NESTML syntax for variables: variable_name real = initial_value end From 27050e766ddb0ad79da202b6cae3fb3e4428c82b Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Fri, 29 Sep 2017 21:43:15 +0200 Subject: [PATCH 15/17] Now, the parser adds omitted differential equations for shapes and odes. --- models/iaf_cond_alpha.nestml | 3 - .../nest/codegeneration/sympy/AstCreator.java | 3 +- .../org/nest/nestml/_ast/ASTVariable.java | 3 +- .../org/nest/nestml/_parser/NESTMLParser.java | 73 ++++++++++++++++++- .../org/nest/frontend/NestmlFrontendTest.java | 11 +++ .../_parser/NESTMLParserModelCoverage.java | 2 +- .../nest/nestml/_parser/NESTMLParserTest.java | 22 ++++-- src/test/resources/neuron_tester.py | 2 +- src/test/resources/parser/adding_odes.nestml | 13 ++++ .../comments.nestml} | 0 .../multipleVariablesWithSameName.nestml | 0 .../{ => parser}/unparsable/wrongTypes.nestml | 0 12 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 src/test/resources/parser/adding_odes.nestml rename src/test/resources/{comments/iaf_neuron.nestml => parser/comments.nestml} (100%) rename src/test/resources/{ => parser}/unparsable/multipleVariablesWithSameName.nestml (100%) rename src/test/resources/{ => parser}/unparsable/wrongTypes.nestml (100%) diff --git a/models/iaf_cond_alpha.nestml b/models/iaf_cond_alpha.nestml index 5682db94b..480eb881c 100644 --- a/models/iaf_cond_alpha.nestml +++ b/models/iaf_cond_alpha.nestml @@ -141,10 +141,7 @@ neuron iaf_cond_alpha_implicit: equations: shape g_in'' = (-1)/(tau_syn_in)**(2)*g_in+(-2)/tau_syn_in*g_in' - shape g_in' = g_in' - shape g_ex'' = (-1)/(tau_syn_ex)**(2)*g_ex+(-2)/tau_syn_ex*g_ex' - shape g_ex' = g_ex' function I_syn_exc pA = cond_sum(g_ex, spikeExc) * ( V_m - E_ex ) function I_syn_inh pA = cond_sum(g_in, spikeInh) * ( V_m - E_in ) diff --git a/src/main/java/org/nest/codegeneration/sympy/AstCreator.java b/src/main/java/org/nest/codegeneration/sympy/AstCreator.java index ce5f9ffa0..4802a27f3 100644 --- a/src/main/java/org/nest/codegeneration/sympy/AstCreator.java +++ b/src/main/java/org/nest/codegeneration/sympy/AstCreator.java @@ -25,7 +25,7 @@ public class AstCreator { PARSER.setParserTarget(MCConcreteParser.ParserExecution.EOF); } - static ASTEquation createEquation(final String equation) { + public static ASTEquation createEquation(final String equation) { try { return PARSER.parseEquation(new StringReader(equation)).get(); @@ -105,4 +105,5 @@ public static ASTShape createShape(final String shapeAsString) { throw new RuntimeException(msg, e); } } + } diff --git a/src/main/java/org/nest/nestml/_ast/ASTVariable.java b/src/main/java/org/nest/nestml/_ast/ASTVariable.java index 19e1588e1..f538d94a1 100644 --- a/src/main/java/org/nest/nestml/_ast/ASTVariable.java +++ b/src/main/java/org/nest/nestml/_ast/ASTVariable.java @@ -21,6 +21,7 @@ package org.nest.nestml._ast; import com.google.common.base.Joiner; +import com.google.common.base.Strings; import de.monticore.types.types._ast.ASTQualifiedName; import java.util.List; @@ -43,7 +44,7 @@ public ASTVariable() { @Override public String toString() { - return name + Joiner.on("'").join(getDifferentialOrder()); + return name + Strings.repeat("'", differentialOrder.size()); } } diff --git a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java index c38fa05af..c55e5678c 100644 --- a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java +++ b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java @@ -5,22 +5,30 @@ */ package org.nest.nestml._parser; +import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.io.Files; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; +import javafx.util.Pair; import org.antlr.v4.runtime.RecognitionException; -import org.nest.nestml._ast.ASTDeclaration; -import org.nest.nestml._ast.ASTNESTMLCompilationUnit; -import org.nest.nestml._ast.ASTNeuron; +import org.nest.codegeneration.sympy.AstCreator; +import org.nest.nestml._ast.*; import org.nest.nestml._visitor.UnitsSIVisitor; import org.nest.utils.AstUtils; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; +import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.groupingBy; +import static org.nest.codegeneration.sympy.AstCreator.createEquation; +import static org.nest.codegeneration.sympy.AstCreator.createShape; /** * HW parser that also is able @@ -59,6 +67,65 @@ public Optional parseNESTMLCompilationUnit(final Strin variableComments.forEach(astDeclaration::addDocString); } + // here additional shape odes are added + for (final ASTNeuron astNeuron:res.get().getNeurons()) { + for (final ASTEquationsBlock astEquationsBlock:astNeuron.getEquationsBlocks()) { + // partition shapes by simple names name: + Map> equations = astEquationsBlock.getEquations() + .stream() + .collect(groupingBy(astEquation -> astEquation.getLhs().getSimpleName())); + + for (final Map.Entry> odeSystem:equations.entrySet()) { + odeSystem.getValue().sort(Comparator.comparingInt(a -> a.getLhs().getDifferentialOrder().size())); + // go from the 1st order to the last order + int highesOrderOde = odeSystem.getValue().get(odeSystem.getValue().size() - 1).getLhs().getDifferentialOrder().size(); + + + for (int i = highesOrderOde; i > 0; --i) { + final int currentOrder = i; + boolean isCorrespondingOdePresent = odeSystem.getValue() + .stream() + .anyMatch(astEquation -> astEquation.getLhs().getDifferentialOrder().size() == currentOrder); + if (!isCorrespondingOdePresent) { + String equationString = odeSystem.getKey() + Strings.repeat("'", currentOrder) + " = " + + odeSystem.getKey() + Strings.repeat("'", currentOrder); + astEquationsBlock.getEquations().add(createEquation(equationString)); + } + + } + + Map> shapes = astEquationsBlock.getShapes() + .stream() + .collect(groupingBy(astEquation -> astEquation.getLhs().getSimpleName())); + + for (final Map.Entry> shapeOdeSystem:shapes.entrySet()) { + shapeOdeSystem.getValue().sort(Comparator.comparingInt(a -> a.getLhs().getDifferentialOrder().size())); + // go from the 1st order to the last order + int highestOrderShape = shapeOdeSystem.getValue().get(shapeOdeSystem.getValue().size() - 1).getLhs().getDifferentialOrder().size(); + + + for (int i = highestOrderShape; i > 0; --i) { + final int currentOrder = i; + boolean isCorrespondingOdePresent = shapeOdeSystem.getValue() + .stream() + .anyMatch(astEquation -> astEquation.getLhs().getDifferentialOrder().size() == currentOrder); + if (!isCorrespondingOdePresent) { + String equationString = "shape " + + shapeOdeSystem.getKey() + Strings.repeat("'", currentOrder) + " = " + + shapeOdeSystem.getKey() + Strings.repeat("'", currentOrder); + astEquationsBlock.getShapes().add(createShape(equationString)); + } + + } + + } + + } + + } + + } + } return res; diff --git a/src/test/java/org/nest/frontend/NestmlFrontendTest.java b/src/test/java/org/nest/frontend/NestmlFrontendTest.java index 2d74460e6..2cba9bf7d 100644 --- a/src/test/java/org/nest/frontend/NestmlFrontendTest.java +++ b/src/test/java/org/nest/frontend/NestmlFrontendTest.java @@ -114,6 +114,17 @@ public void testModelsFolder() { new NestmlFrontend().start(args); } + @Test + public void test() { + final String[] args = new String[] { + "models/iaf_cond_alpha.nestml", + "--json_log", "model_issues", + "--enable_tracing", + "--target", outputPath.toString()}; + + new NestmlFrontend().start(args); + } + @Test public void testTutorialModels() { final String[] args = new String[] { diff --git a/src/test/java/org/nest/nestml/_parser/NESTMLParserModelCoverage.java b/src/test/java/org/nest/nestml/_parser/NESTMLParserModelCoverage.java index 3b3bfceec..f1703def5 100644 --- a/src/test/java/org/nest/nestml/_parser/NESTMLParserModelCoverage.java +++ b/src/test/java/org/nest/nestml/_parser/NESTMLParserModelCoverage.java @@ -35,7 +35,7 @@ public void testParsableModels() throws IOException { filenames.addAll(collectFiles( Paths.get("src/test/resources"), - model -> model.getFileName().toString().endsWith(NESTMLLanguage.FILE_ENDING) && !model.toString().contains("unparsable"))); + model -> model.getFileName().toString().endsWith(NESTMLLanguage.FILE_ENDING) && !model.toString().contains("parser/unparsable"))); filenames.forEach(this::parseAndCheck); } diff --git a/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java b/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java index bf1d2d3e3..e7472d6be 100644 --- a/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java +++ b/src/test/java/org/nest/nestml/_parser/NESTMLParserTest.java @@ -7,8 +7,10 @@ import org.junit.Test; import org.nest.base.ModelbasedTest; import org.nest.nestml._ast.ASTDeclaration; +import org.nest.nestml._ast.ASTEquation; import org.nest.nestml._ast.ASTExpr; import org.nest.nestml._ast.ASTNESTMLCompilationUnit; +import org.nest.nestml.prettyprinter.NESTMLPrettyPrinter; import org.nest.utils.AstUtils; import org.nest.utils.LogHelper; @@ -30,11 +32,11 @@ * @author plonikov */ public class NESTMLParserTest extends ModelbasedTest { - private static final String TEST_MODEL_COMMENTS = "src/test/resources/comments/iaf_neuron.nestml"; + private static final String PARSER_INPUT = "src/test/resources/parser/"; @Test public void testAllModels() { - // ignore all models, in an folder with an 'unparsable' infix + // ignore all models, in an folder with an 'parser.unparsable' infix final List testModels = collectNESTMLModelFilenames(Paths.get("src/test/resources/")) .stream() .filter( path -> !path.toString().contains("unparsable")) @@ -48,7 +50,7 @@ public void testAllModels() { @Test public void testNonExistentType() throws IOException { - final Optional ast = parser.parse("src/test/resources/unparsable/wrongTypes.nestml"); + final Optional ast = parser.parse("src/test/resources/parser/unparsable/wrongTypes.nestml"); assertFalse(ast.isPresent()); List findings = LogHelper.getModelErrors(Log.getFindings()); assertEquals(2, findings.size()); @@ -56,7 +58,7 @@ public void testNonExistentType() throws IOException { @Test public void testMultipleVariablesWithSameName() throws IOException { - final Optional ast = parser.parse("src/test/resources/unparsable/multipleVariablesWithSameName.nestml"); + final Optional ast = parser.parse("src/test/resources/parser/unparsable/multipleVariablesWithSameName.nestml"); assertTrue(ast.isPresent()); scopeCreator.runSymbolTableCreator(ast.get()); assertTrue(LogHelper.getModelErrors(Log.getFindings()).size() > 0); @@ -64,7 +66,7 @@ public void testMultipleVariablesWithSameName() throws IOException { @Test public void testCommentsExtraction() throws IOException { - final Optional ast = parser.parse(TEST_MODEL_COMMENTS); + final Optional ast = parser.parse(PARSER_INPUT + "comments.nestml"); assertTrue(ast.isPresent()); final List declarations = AstUtils.getAll(ast.get(), ASTDeclaration.class); for (final ASTDeclaration declaration:declarations) { @@ -74,6 +76,16 @@ public void testCommentsExtraction() throws IOException { } + @Test + public void testAddingTrivialEquations() throws IOException { + final Optional ast = parser.parse(PARSER_INPUT + "adding_odes.nestml"); + assertTrue(ast.isPresent()); + final List equations = AstUtils.getAll(ast.get(), ASTEquation.class); + System.out.println(NESTMLPrettyPrinter.print(ast.get())); + assertEquals(6, equations.size()); + + } + public Optional parse(String input) throws RecognitionException, IOException { final NESTMLParser parser = new NESTMLParser(); parser.setParserTarget(MCConcreteParser.ParserExecution.EOF); diff --git a/src/test/resources/neuron_tester.py b/src/test/resources/neuron_tester.py index 61b292d36..eb3203991 100644 --- a/src/test/resources/neuron_tester.py +++ b/src/test/resources/neuron_tester.py @@ -60,7 +60,7 @@ def test(referenceModel, testant, gsl_error_tol, tolerance = 0.000001): # test_multysinapse() models = list() - models.append( ("terub_neuron_stn", "terub_neuron_stn_implicit", 1.e-3, 0.001)) + models.append( ("iaf_cond_alpha", "iaf_cond_alpha_implicit", 1.e-3, 0.001)) # models.append( ("iaf_cond_exp_sfa_rr", "iaf_cond_exp_sfa_rr_implicit", None, 0.001)) for reference, testant, gsl_error_tol, tollerance in models: diff --git a/src/test/resources/parser/adding_odes.nestml b/src/test/resources/parser/adding_odes.nestml new file mode 100644 index 000000000..2eb02cf9d --- /dev/null +++ b/src/test/resources/parser/adding_odes.nestml @@ -0,0 +1,13 @@ +neuron alpha_implicit: + + equations: + shape g_in'' = (-1)/(tau_syn_in)**(2)*g_in+(-2)/tau_syn_in*g_in' + shape g_ex'''' = (-1)/(tau_syn_ex)**(2)*g_ex+(-2)/tau_syn_ex*g_ex' + shape g_ex'' = (-1)/(tau_syn_ex)**(2)*g_ex+(-2)/tau_syn_ex*g_ex' + + V_m'''''' = 6 + V_m'''' = 4 + V_m'' = 2 + end + +end \ No newline at end of file diff --git a/src/test/resources/comments/iaf_neuron.nestml b/src/test/resources/parser/comments.nestml similarity index 100% rename from src/test/resources/comments/iaf_neuron.nestml rename to src/test/resources/parser/comments.nestml diff --git a/src/test/resources/unparsable/multipleVariablesWithSameName.nestml b/src/test/resources/parser/unparsable/multipleVariablesWithSameName.nestml similarity index 100% rename from src/test/resources/unparsable/multipleVariablesWithSameName.nestml rename to src/test/resources/parser/unparsable/multipleVariablesWithSameName.nestml diff --git a/src/test/resources/unparsable/wrongTypes.nestml b/src/test/resources/parser/unparsable/wrongTypes.nestml similarity index 100% rename from src/test/resources/unparsable/wrongTypes.nestml rename to src/test/resources/parser/unparsable/wrongTypes.nestml From 9a37876cf4fccf90f6571d9f5585f1b86c3c9f48 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Wed, 4 Oct 2017 13:00:39 +0200 Subject: [PATCH 16/17] Fixes all models. odes are left out --- models/aeif_cond_alpha.nestml | 2 - models/hh_psc_alpha.nestml | 2 - models/iaf_chxk_2008.nestml | 3 -- models/iaf_cond_beta.nestml | 42 +++++++++---------- models/mat2_psc_exp.nestml | 2 +- models/terub_neuron_gpe.nestml | 2 - models/terub_neuron_stn.nestml | 2 - .../org/nest/nestml/_parser/NESTMLParser.java | 3 -- 8 files changed, 22 insertions(+), 36 deletions(-) diff --git a/models/aeif_cond_alpha.nestml b/models/aeif_cond_alpha.nestml index f4b296b9f..a06b6b366 100644 --- a/models/aeif_cond_alpha.nestml +++ b/models/aeif_cond_alpha.nestml @@ -173,11 +173,9 @@ neuron aeif_cond_alpha_implicit: function V_bounded mV = min(V_m, V_peak) # prevent exponential divergence # alpha function for the g_in shape g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in - shape g_in' = g_in' # alpha function for the g_ex shape g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex - shape g_ex' = g_ex' # Add aliases to simplify the equation definition of V_m function exp_arg real = (V_bounded-V_th)/Delta_T diff --git a/models/hh_psc_alpha.nestml b/models/hh_psc_alpha.nestml index 38d1512ca..1c419d4b7 100644 --- a/models/hh_psc_alpha.nestml +++ b/models/hh_psc_alpha.nestml @@ -207,11 +207,9 @@ neuron hh_psc_alpha_implicit: equations: # synapses: alpha functions - shape I_syn_in' = I_syn_in' shape I_syn_in'' = (-2/tau_syn_in) * I_syn_in'-(1/tau_syn_in**2) * I_syn_in ## alpha function for the g_ex - shape I_syn_ex' = I_syn_ex' shape I_syn_ex'' = (-2/tau_syn_ex) * I_syn_ex'-(1/tau_syn_ex**2) * I_syn_ex function I_syn_exc pA = curr_sum(I_syn_ex, spikeExc) diff --git a/models/iaf_chxk_2008.nestml b/models/iaf_chxk_2008.nestml index d0a2b1e3c..a6a996437 100644 --- a/models/iaf_chxk_2008.nestml +++ b/models/iaf_chxk_2008.nestml @@ -34,7 +34,6 @@ neuron iaf_chxk_2008_neuron: shape g_in = (e/tau_syn_in) * t * exp(-t/tau_syn_in) shape g_ex = (e/tau_syn_ex) * t * exp(-t/tau_syn_ex) G_ahp'' = (-2/tau_ahp) * G_ahp'-(1/tau_ahp**2) * G_ahp - G_ahp' = G_ahp' function I_syn_exc pA = cond_sum(g_ex, spikesExc) * ( V_m - E_ex ) function I_syn_inh pA = cond_sum(g_in, spikesInh) * ( V_m - E_in ) @@ -151,11 +150,9 @@ neuron iaf_chxk_2008_implicit: equations: g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in - g_in' = g_in' # alpha function for the g_ex g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex - g_ex' = g_ex' G_ahp'' = -G_ahp' / tau_ahp G_ahp' = G_ahp' - G_ahp / tau_ahp diff --git a/models/iaf_cond_beta.nestml b/models/iaf_cond_beta.nestml index 0c30de0ec..c752dfc65 100644 --- a/models/iaf_cond_beta.nestml +++ b/models/iaf_cond_beta.nestml @@ -22,15 +22,15 @@ SeeAlso: iaf_cond_exp, iaf_cond_beta_mc, iaf_cond_alpha */ neuron iaf_cond_beta_neuron: state: - r integer ## counts number of tick during the refractory period + r integer # counts number of tick during the refractory period end initial_values: - V_m mV = E_L ## membrane potential - g_in nS = 0 nS ## inputs from the inh conductance - g_in' nS/ms = 0 nS/ms ## inputs from the inh conductance - g_ex nS = 0 nS ## inputs from the exc conductance - g_ex' nS/ms = 0 nS/ms ## inputs from the exc conductance + V_m mV = E_L # membrane potential + g_in nS = 0 nS # inputs from the inh conductance + g_in' nS/ms = 0 nS/ms # inputs from the inh conductance + g_ex nS = 0 nS # inputs from the exc conductance + g_ex' nS/ms = 0 nS/ms # inputs from the exc conductance end equations: @@ -47,21 +47,21 @@ neuron iaf_cond_beta_neuron: end parameters: - E_L mV = -85.0mV ## Leak reversal Potential (aka resting potential) in mV - C_m pF = 250.0pF ## Capacity of the membrane - t_ref ms = 2.0ms ## Refractory period in ms - V_th mV = -55.0mV ## Threshold Potential in mV - V_reset mV = -60.0mV ## Reset Potential in mV - E_ex mV = 0mV ## Excitatory reversal Potential in mV - E_in mV = -85.0mV ## Inhibitory reversal Potential in mV - g_L nS = 16.6667nS ## Leak Conductance in nS - tau_syn_rise_I ms = 0.2ms ## Synaptic Time Constant Excitatory Synapse in ms - tau_syn_decay_I ms = 2.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - tau_syn_rise_E ms = 0.2ms ## Synaptic Time Constant Excitatory Synapse in ms - tau_syn_decay_E ms = 2.0ms ## Synaptic Time Constant for Inhibitory Synapse in ms - I_e pA = 0pA ## Constant Current in pA - F_E nS = 0nS ## Constant External input conductance in nS (excitatory). - F_I nS = 0nS ## Constant External input conductance in nS (inhibitory). + E_L mV = -85.0mV # Leak reversal Potential (aka resting potential) in mV + C_m pF = 250.0pF # Capacity of the membrane + t_ref ms = 2.0ms # Refractory period in ms + V_th mV = -55.0mV # Threshold Potential in mV + V_reset mV = -60.0mV # Reset Potential in mV + E_ex mV = 0mV # Excitatory reversal Potential in mV + E_in mV = -85.0mV # Inhibitory reversal Potential in mV + g_L nS = 16.6667nS # Leak Conductance in nS + tau_syn_rise_I ms = 0.2ms # Synaptic Time Constant Excitatory Synapse in ms + tau_syn_decay_I ms = 2.0ms # Synaptic Time Constant for Inhibitory Synapse in ms + tau_syn_rise_E ms = 0.2ms # Synaptic Time Constant Excitatory Synapse in ms + tau_syn_decay_E ms = 2.0ms # Synaptic Time Constant for Inhibitory Synapse in ms + I_e pA = 0pA # Constant Current in pA + F_E nS = 0nS # Constant External input conductance in nS (excitatory). + F_I nS = 0nS # Constant External input conductance in nS (inhibitory). end internals: diff --git a/models/mat2_psc_exp.nestml b/models/mat2_psc_exp.nestml index 6259db6e1..5cb7ff517 100644 --- a/models/mat2_psc_exp.nestml +++ b/models/mat2_psc_exp.nestml @@ -68,7 +68,7 @@ neuron mat2_psc_exp_neuron: end initial_values: - V_abs mV = 0mV# Membrane potential + V_abs mV = 0mV # Membrane potential function V_m mV = V_abs + E_L # Relative membrane potential. # I.e. the real threshold is (V_m-E_L). end diff --git a/models/terub_neuron_gpe.nestml b/models/terub_neuron_gpe.nestml index 4b3a468e0..982626e6d 100644 --- a/models/terub_neuron_gpe.nestml +++ b/models/terub_neuron_gpe.nestml @@ -295,11 +295,9 @@ neuron terub_neuron_gpe_implicit: # synapses: alpha functions # alpha function for the g_in shape g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in - shape g_in' = g_in' # alpha function for the g_ex shape g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex - shape g_ex' = g_ex' # V dot -- synaptic input are currents, inhib current is negative V_m' = ( -(I_Na + I_K + I_L + I_T + I_Ca + I_ahp)* pA + currents + I_e + I_ex_mod * pA + I_in_mod * pA) / C_m diff --git a/models/terub_neuron_stn.nestml b/models/terub_neuron_stn.nestml index bd73147f9..2d6a74daf 100644 --- a/models/terub_neuron_stn.nestml +++ b/models/terub_neuron_stn.nestml @@ -325,11 +325,9 @@ neuron terub_neuron_stn_implicit: # synapses: alpha functions ## alpha function for the g_in shape g_in'' = (-2/tau_syn_in) * g_in'-(1/tau_syn_in**2) * g_in - shape g_in' = g_in' ## alpha function for the g_ex shape g_ex'' = (-2/tau_syn_ex) * g_ex'-(1/tau_syn_ex**2) * g_ex - shape g_ex' = g_ex' end parameters: diff --git a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java index c55e5678c..5ad71f560 100644 --- a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java +++ b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java @@ -10,9 +10,7 @@ import com.google.common.io.Files; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; -import javafx.util.Pair; import org.antlr.v4.runtime.RecognitionException; -import org.nest.codegeneration.sympy.AstCreator; import org.nest.nestml._ast.*; import org.nest.nestml._visitor.UnitsSIVisitor; import org.nest.utils.AstUtils; @@ -24,7 +22,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; import static java.util.stream.Collectors.groupingBy; import static org.nest.codegeneration.sympy.AstCreator.createEquation; From 6dd0a9629d0b8e19f8a4196b643249264522b6b7 Mon Sep 17 00:00:00 2001 From: DimitriPlotnikov Date: Wed, 4 Oct 2017 13:10:24 +0200 Subject: [PATCH 17/17] Extract the logic to add trivial odes for the possible reuse --- .../org/nest/nestml/_parser/NESTMLParser.java | 57 ++--------------- src/main/java/org/nest/utils/AstUtils.java | 63 +++++++++++++++++-- 2 files changed, 64 insertions(+), 56 deletions(-) diff --git a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java index 5ad71f560..d561f8196 100644 --- a/src/main/java/org/nest/nestml/_parser/NESTMLParser.java +++ b/src/main/java/org/nest/nestml/_parser/NESTMLParser.java @@ -10,7 +10,9 @@ import com.google.common.io.Files; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; +import javafx.util.Pair; import org.antlr.v4.runtime.RecognitionException; +import org.nest.codegeneration.sympy.AstCreator; import org.nest.nestml._ast.*; import org.nest.nestml._visitor.UnitsSIVisitor; import org.nest.utils.AstUtils; @@ -22,10 +24,12 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import static java.util.stream.Collectors.groupingBy; import static org.nest.codegeneration.sympy.AstCreator.createEquation; import static org.nest.codegeneration.sympy.AstCreator.createShape; +import static org.nest.utils.AstUtils.addTrivialOdes; /** * HW parser that also is able @@ -67,58 +71,7 @@ public Optional parseNESTMLCompilationUnit(final Strin // here additional shape odes are added for (final ASTNeuron astNeuron:res.get().getNeurons()) { for (final ASTEquationsBlock astEquationsBlock:astNeuron.getEquationsBlocks()) { - // partition shapes by simple names name: - Map> equations = astEquationsBlock.getEquations() - .stream() - .collect(groupingBy(astEquation -> astEquation.getLhs().getSimpleName())); - - for (final Map.Entry> odeSystem:equations.entrySet()) { - odeSystem.getValue().sort(Comparator.comparingInt(a -> a.getLhs().getDifferentialOrder().size())); - // go from the 1st order to the last order - int highesOrderOde = odeSystem.getValue().get(odeSystem.getValue().size() - 1).getLhs().getDifferentialOrder().size(); - - - for (int i = highesOrderOde; i > 0; --i) { - final int currentOrder = i; - boolean isCorrespondingOdePresent = odeSystem.getValue() - .stream() - .anyMatch(astEquation -> astEquation.getLhs().getDifferentialOrder().size() == currentOrder); - if (!isCorrespondingOdePresent) { - String equationString = odeSystem.getKey() + Strings.repeat("'", currentOrder) + " = " + - odeSystem.getKey() + Strings.repeat("'", currentOrder); - astEquationsBlock.getEquations().add(createEquation(equationString)); - } - - } - - Map> shapes = astEquationsBlock.getShapes() - .stream() - .collect(groupingBy(astEquation -> astEquation.getLhs().getSimpleName())); - - for (final Map.Entry> shapeOdeSystem:shapes.entrySet()) { - shapeOdeSystem.getValue().sort(Comparator.comparingInt(a -> a.getLhs().getDifferentialOrder().size())); - // go from the 1st order to the last order - int highestOrderShape = shapeOdeSystem.getValue().get(shapeOdeSystem.getValue().size() - 1).getLhs().getDifferentialOrder().size(); - - - for (int i = highestOrderShape; i > 0; --i) { - final int currentOrder = i; - boolean isCorrespondingOdePresent = shapeOdeSystem.getValue() - .stream() - .anyMatch(astEquation -> astEquation.getLhs().getDifferentialOrder().size() == currentOrder); - if (!isCorrespondingOdePresent) { - String equationString = "shape " + - shapeOdeSystem.getKey() + Strings.repeat("'", currentOrder) + " = " + - shapeOdeSystem.getKey() + Strings.repeat("'", currentOrder); - astEquationsBlock.getShapes().add(createShape(equationString)); - } - - } - - } - - } - + addTrivialOdes(astEquationsBlock); } } diff --git a/src/main/java/org/nest/utils/AstUtils.java b/src/main/java/org/nest/utils/AstUtils.java index 574ac9a2c..690c0ba20 100644 --- a/src/main/java/org/nest/utils/AstUtils.java +++ b/src/main/java/org/nest/utils/AstUtils.java @@ -31,15 +31,15 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Deque; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.*; import static java.lang.Math.pow; +import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toList; +import static org.nest.codegeneration.sympy.AstCreator.createEquation; +import static org.nest.codegeneration.sympy.AstCreator.createShape; import static org.nest.nestml._symboltable.predefined.PredefinedTypes.getType; import static org.nest.nestml._symboltable.symbols.VariableSymbol.resolve; @@ -439,4 +439,59 @@ public static Optional convertSiName(String astVariable) { return Optional.empty(); } + public static void addTrivialOdes(ASTEquationsBlock astEquationsBlock) { + // partition shapes by simple names name: + Map> equations = astEquationsBlock.getEquations() + .stream() + .collect(groupingBy(astEquation -> astEquation.getLhs().getSimpleName())); + + for (final Map.Entry> odeSystem:equations.entrySet()) { + odeSystem.getValue().sort(Comparator.comparingInt(a -> a.getLhs().getDifferentialOrder().size())); + // go from the 1st order to the last order + int highesOrderOde = odeSystem.getValue().get(odeSystem.getValue().size() - 1).getLhs().getDifferentialOrder().size(); + + + for (int i = highesOrderOde; i > 0; --i) { + final int currentOrder = i; + boolean isCorrespondingOdePresent = odeSystem.getValue() + .stream() + .anyMatch(astEquation -> astEquation.getLhs().getDifferentialOrder().size() == currentOrder); + if (!isCorrespondingOdePresent) { + String equationString = odeSystem.getKey() + Strings.repeat("'", currentOrder) + " = " + + odeSystem.getKey() + Strings.repeat("'", currentOrder); + astEquationsBlock.getEquations().add(createEquation(equationString)); + } + + } + + Map> shapes = astEquationsBlock.getShapes() + .stream() + .collect(groupingBy(astEquation -> astEquation.getLhs().getSimpleName())); + + for (final Map.Entry> shapeOdeSystem:shapes.entrySet()) { + shapeOdeSystem.getValue().sort(Comparator.comparingInt(a -> a.getLhs().getDifferentialOrder().size())); + // go from the 1st order to the last order + int highestOrderShape = shapeOdeSystem.getValue().get(shapeOdeSystem.getValue().size() - 1).getLhs().getDifferentialOrder().size(); + + + for (int i = highestOrderShape; i > 0; --i) { + final int currentOrder = i; + boolean isCorrespondingOdePresent = shapeOdeSystem.getValue() + .stream() + .anyMatch(astEquation -> astEquation.getLhs().getDifferentialOrder().size() == currentOrder); + if (!isCorrespondingOdePresent) { + String equationString = "shape " + + shapeOdeSystem.getKey() + Strings.repeat("'", currentOrder) + " = " + + shapeOdeSystem.getKey() + Strings.repeat("'", currentOrder); + astEquationsBlock.getShapes().add(createShape(equationString)); + } + + } + + } + + } + + } + }