;; ;; TODO: finish gsl-fminimizer ;; ;; An extension for translating NEMO models to NEST code. ;; ;; Copyright 2011-2013 Ivan Raikov and the Okinawa Institute of Science and Technology ;; ;; This program 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 3 of the ;; License, or (at your option) any later version. ;; ;; This program 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. ;; ;; A full copy of the GPL license can be found at ;; . ;; (module nemo-nest (nemo:nest-translator) (import scheme chicken utils data-structures ports extras srfi-1 srfi-13 srfi-69) (require-extension lolevel posix matchable strictly-pretty varsubst datatype nemo-core nemo-utils nemo-gate-complex nemo-geometry nemo-synapse nemo-defaults) (define nest-builtin-consts `(params)) (define C++-ops `(+ - * / > < <= >= =)) (define builtin-fns `(+ - * / pow neg abs atan asin acos sin cos exp ln sqrt tan cosh sinh tanh hypot gamma lgamma log10 log2 log1p ldexp cube > < <= >= = and or round ceiling floor max min )) (define (nest-name s) (let ((cs (string->list (->string s)))) (let loop ((lst (list)) (cs cs)) (if (null? cs) (string->symbol (list->string (reverse lst))) (let* ((c (car cs)) (c1 (cond ((or (char-alphabetic? c) (char-numeric? c) (char=? c #\_)) c) (else #\_)))) (loop (cons c1 lst) (cdr cs))))))) (define (rhsexpr/C++ expr) (match expr (('if . es) `(if . ,(map (lambda (x) (rhsexpr/C++ x)) es))) (('pow x y) (if (and (integer? y) (positive? y)) (if (> y 1) (let ((tmp (gensym "x"))) `(let ((,tmp ,x)) (* . ,(list-tabulate (inexact->exact y) (lambda (i) tmp))))) x) (if (and (number? y) (zero? y)) 1.0 expr))) ((s . es) (if (symbol? s) (cons (if (member s builtin-fns) s (nest-name s)) (map (lambda (x) (rhsexpr/C++ x)) es)) expr)) (id (if (symbol? id) (nest-name id) id)))) (define (nest-state-name n s) (nest-name (s+ n s))) (define-syntax pp (syntax-rules () ((pp indent val ...) (ppf indent (quasiquote val) ...)))) (define group/C++ (doc:block 2 (doc:text "(") (doc:text ")"))) (define block/C++ (doc:block 2 (doc:text "{") (doc:text "}"))) (define (stmt/C++ x) (match x (($ doc 'DocCons _ ($ doc 'DocText ";")) x) (else (doc:cons x (doc:text ";"))))) (define (ifthen/C++ c e1 e2) (doc:nest 2 (doc:connect (doc:group (doc:connect (doc:text "if") c)) (doc:connect (doc:nest 2 e1) (doc:nest 2 (doc:connect (doc:text "else") e2)))) )) (define (letblk/C++ e1 e2) (cond ((equal? e1 (doc:empty)) (doc:group (doc:nest 2 e2))) ((equal? e2 (doc:empty)) (doc:group (doc:nest 2 e1))) (else (doc:connect (doc:group (doc:nest 2 (stmt/C++ e1))) (doc:group (doc:nest 2 e2)))))) (define (format-op/C++ indent op args) (let ((op1 (doc:text (->string op)))) (if (null? args) op1 (match args ((x) (doc:concat (list op1 x))) ((x y) (doc:concat (intersperse (list x op1 y) (doc:space)))) ((x y z) (doc:concat (intersperse (list x op1 y op1 z) (doc:space)))) (lst (let* ((n (length lst)) (n/2 (inexact->exact (round (/ n 2))))) (doc:concat (intersperse (list (format-op/C++ indent op (take lst n/2 )) op1 (format-op/C++ indent op (drop lst n/2 ))) (doc:space))))))))) (define (format-fncall/C++ indent op args) (let ((op1 (doc:text (->string op)))) (doc:cons op1 (group/C++ ((doc:list indent identity (lambda () (doc:text ", "))) args))))) (define (name-normalize expr) (match expr (('if c t e) `(if ,(name-normalize c) ,(name-normalize t) ,(name-normalize e))) (('let bs e) `(let ,(map (lambda (b) `(,(car b) ,(name-normalize (cadr b)))) bs) ,(name-normalize e))) ((f . es) (cons (if (member f builtin-fns) f (nest-name f)) (map name-normalize es))) ((? symbol? ) (nest-name expr)) ((? atom? ) expr))) (define (canonicalize-expr/C++ expr) (let ((subst-convert (subst-driver (lambda (x) (and (symbol? x) x)) nemo:binding? identity nemo:bind nemo:subst-term))) (let* ((expr1 (if-convert expr)) (expr2 (subst-convert expr1 subst-empty)) (expr3 (let-lift expr2)) (expr4 (name-normalize expr3))) expr4))) (define (format-expr/C++ indent expr . rest) (let-optionals rest ((rv #f)) (let ((indent+ (+ 2 indent))) (match expr (('let bindings body) (letblk/C++ (fold-right (lambda (x ax) (letblk/C++ (match (second x) (('if c t e) (ifthen/C++ (group/C++ (format-expr/C++ indent c)) (block/C++ (format-expr/C++ indent t (first x))) (block/C++ (format-expr/C++ indent e (first x))))) (else (stmt/C++ (format-op/C++ indent+ " = " (list (format-expr/C++ indent (first x) ) (format-expr/C++ indent (second x))))))) ax)) (doc:empty) bindings) (match body (('let _ _) (format-expr/C++ indent body rv)) (else (let ((body1 (doc:nest indent (format-expr/C++ indent body)))) (if rv (stmt/C++ (format-op/C++ indent " = " (list (format-expr/C++ indent+ rv ) body1))) body1)))))) (('if . rest) (error 'format-expr/C++ "invalid if statement " expr)) ((op . rest) (let ((op (case op ((ln) 'log) ((abs) 'fabs) (else op)))) (let ((fe (if (member op C++-ops) (let ((mdiv? (any (lambda (x) (match x (('* . _) #t) (('/ . _) #t) (else #f))) rest)) (mul? (any (lambda (x) (match x (('* . _) #t) (else #f))) rest)) (plmin? (any (lambda (x) (match x (('+ . _) #t) (('- . _) #t) (else #f))) rest))) (case op ((/) (format-op/C++ indent op (map (lambda (x) (let ((fx (format-expr/C++ indent+ x))) (if (or (symbol? x) (number? x)) fx (if (or mul? plmin?) (group/C++ fx) fx)))) rest))) ((*) (format-op/C++ indent op (map (lambda (x) (let ((fx (format-expr/C++ indent+ x))) (if (or (symbol? x) (number? x)) fx (if plmin? (group/C++ fx) fx)))) rest))) (else (format-op/C++ indent op (map (lambda (x) (let ((fx (format-expr/C++ indent+ x))) fx)) rest))))) (let ((op (case op ((neg) '-) (else op)))) (format-fncall/C++ indent op (map (lambda (x) (format-expr/C++ indent+ x)) rest)))))) (if rv (stmt/C++ (format-op/C++ indent " = " (list (format-expr/C++ indent+ rv ) fe))) fe)))) (else (let ((fe (doc:text (->string expr)))) (if rv (stmt/C++ (format-op/C++ indent " = " (list (format-expr/C++ indent+ rv ) fe))) fe))))))) (define (expr->string/C++ x . rest) (let-optionals rest ((rv #f) (width 72)) (sdoc->string (doc:format width (format-expr/C++ 2 x rv))))) (define (make-define-fn sysname ) (lambda (indent n proc) (let ((lst (procedure-data proc)) (indent+ (+ 2 indent))) (let ((rt (or (lookup-def 'rt lst) 'double)) (formals (lookup-def 'formals lst)) (vars (lookup-def 'vars lst)) (consts (filter (lambda (x) (not (procedure? (cdr x)))) (lookup-def 'consts lst))) (body (lookup-def 'body lst)) (rv (gensym 'rv))) (let ((argument-list (append (if (null? vars) '() (map (lambda (x) (s+ "double " (nest-name x))) vars)) '("const void* params")))) (pp indent ,nl (,rt ,(nest-name n) (,(slp ", " argument-list)) "{" )) (let* ((body0 (rhsexpr/C++ body)) (body1 (canonicalize-expr/C++ (add-params-to-fncall body0 builtin-fns))) (lbs (enum-bnds body1 (list)))) (pp indent+ (double ,rv ";")) (if (not (null? lbs)) (pp indent+ (double ,(slp ", " lbs) ";"))) (if (not (null? consts)) (begin (pp indent+ (double ,(slp ", " (map (compose nest-name car) consts)) ";") ("const " ,(s+ sysname "::Parameters_") "& p = " " *(reinterpret_cast< const " ,(s+ sysname "::Parameters_") "*>(params));")) (for-each (lambda (x) (let ((n (car x))) (pp indent+ (,(nest-name n) = ,(s+ "p." (nest-name n) ";"))))) consts) )) (pp indent+ ,(expr->string/C++ body1 (nest-name rv))) (pp indent+ ,(s+ "return " rv ";")) )) (pp indent "}")) ))) (define (make-define-fn-header sysname ) (lambda (indent n proc) (let ((lst (procedure-data proc)) (indent+ (+ 2 indent))) (let ((rt (or (lookup-def 'rt lst) 'double)) (formals (lookup-def 'formals lst)) (vars (lookup-def 'vars lst)) (consts (filter (lambda (x) (not (procedure? (cdr x)))) (lookup-def 'consts lst))) (body (lookup-def 'body lst)) (rv (gensym 'rv))) (let ((argument-list (append (if (null? vars) '() (map (lambda (x) (s+ "double " (nest-name x))) vars)) '("const void* params")))) (pp indent ,nl (,rt ,(nest-name n) (,(slp ", " argument-list)) ";" )) )) ))) (define (ith v i) (sprintf "Ith(~A,~A)" v i)) (define (output-dy sysname method imports const-defs state-index-map external-eq-defs rate-eq-defs reaction-eq-defs asgn-eq-defs pool-ions i-eqs v-eq indent indent+) (case method ((leapfrog) (pp indent ,nl ( ,(s+ "extern \"C\" int " sysname "_dynamics") (,(slp ", " `("double t" "const double y[]" "double f[]" "void* pnode" ))) #\{ ))) ((cvode) (pp indent ,nl (,(s+ "extern \"C\" int " sysname "_dynamics") (,(slp ", " `("double t" "N_Vector y" "N_Vector f" "void* pnode" ))) #\{ ))) ((gsl) (pp indent ,nl (,(s+ "extern \"C\" int " sysname "_dynamics") (,(slp ", " `("double t" "const double y[]" "double f[]" "void* pnode" ))) #\{ ))) ) (let* ( (i-eqs (map (lambda (def) (list (first def) (add-params-to-fncall (canonicalize-expr/C++ (second def)) builtin-fns))) i-eqs)) (v-eq (and v-eq (list (first v-eq) (add-params-to-fncall (canonicalize-expr/C++ (second v-eq)) builtin-fns)))) (eqs (append external-eq-defs asgn-eq-defs reaction-eq-defs (map (lambda (pool-ion) (let ((n (pool-ion-in pool-ion)) (b (pool-ion-inq pool-ion))) (list n b))) pool-ions) (map (lambda (pool-ion) (let ((n (pool-ion-out pool-ion)) (b (pool-ion-outq pool-ion))) (list n b))) pool-ions) i-eqs )) (eq-dag (map (lambda (def) (cons (first def) (enum-freevars (second def) '() '()))) eqs)) (eq-order (reverse (topological-sort eq-dag (lambda (x y) (string=? (->string x) (->string y)))))) (eq-locals (find-locals (map second (if v-eq (cons v-eq (append i-eqs rate-eq-defs eqs)) (append i-eqs rate-eq-defs eqs))))) ) (pp indent+ (double ,(slp ", " (delete-duplicates (map (compose ->string nest-name) (filter (lambda (x) (not (member x nest-builtin-consts))) (append eq-locals eq-order (map first i-eqs) (map first external-eq-defs) (map first state-index-map) (map first const-defs) ))) string=?)) ";")) (pp indent+ ,nl ("// S is shorthand for the type that describes the model state ") (typedef ,(s+ sysname "::State_") "S;") ,nl ("// cast the node ptr to an object of the proper type") ("assert(pnode);") ("const " ,sysname "& node = *(reinterpret_cast<" ,sysname "*>(pnode));") (,sysname "& vnode = *(reinterpret_cast<" ,sysname "*>(pnode));") ,nl ("// params is a reference to the model parameters ") (const struct ,(s+ sysname "::Parameters_") "*params;") ("params = &(node.P_);") ,nl ("// state is a reference to the model state ") (struct ,(s+ sysname "::State_") "*state;") ("state = &(vnode.S_);") ,nl ("// y[] must be the state vector supplied by the integrator, ") ("// not the state vector in the node, node.S_.y[]. ") ,nl ) (for-each (lambda (def) (let ((n (first def)) ) (pp indent+ ,(expr->string/C++ (s+ "params->" n) n)))) const-defs) (for-each (lambda (def) (pp indent+ ,(expr->string/C++ (second def) (first def)))) i-eqs) (let ((vi (lookup-def 'v state-index-map))) (if vi (pp indent+ ,(expr->string/C++ (ith 'y vi) 'v)))) (for-each (lambda (def) (let* ((n (first def)) (ni (lookup-def n state-index-map))) (pp indent+ ,(expr->string/C++ (ith 'y ni) (nest-name n))))) rate-eq-defs) (for-each (lambda (n) (let ((b (lookup-def n eqs))) (if b (pp indent+ ,(expr->string/C++ b (nest-name n)))))) eq-order) (for-each (lambda (def) (let* ((n (first def)) (b (second def)) (fv (ith 'f (lookup-def n state-index-map))) ) (pp indent+ ,(s+ "// rate equation " n) ,(expr->string/C++ b fv)))) rate-eq-defs) (if v-eq (let ((vi (lookup-def 'v state-index-map))) (if vi (pp indent+ ,(expr->string/C++ (second v-eq) (ith 'f vi))) ))) (case method ((leapfrog) (pp indent+ ,nl ("return 0;"))) ((cvode) (pp indent+ ,nl ("return 0;"))) ((gsl) (pp indent+ ,nl ("return GSL_SUCCESS;"))) ) (pp indent #\}) )) (define (output-jac sysname method state-index-map pool-ions i-eqs v-eq indent indent+) ;; Diagonal Jacobian approximation: (f(s+.01) - f(s))/.001 ;; CVODE: ;; typedef int (*CVDlsDenseJacFn)(long int N, realtype t, ;; N_Vector y, N_Vector fy, ;; DlsMat Jac, void *user_data, ;; N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); ;; GSL: ;; int (* jacobian) (double t, const double y[], double * dfdy, double dfdt[], void * params); (case method ((gsl) (pp indent ,nl (,(s+ "extern \"C\" int " sysname "_jacobian") (,(slp ", " `("double t" "const double y[]" "double *dfdy" "double dfdt[]" "void* pnode" )))) #\{ ("// cast the node ptr to an object of the proper type") ("assert(pnode);") ("const " ,sysname "& node = *(reinterpret_cast<" ,sysname "*>(pnode));") (,sysname "& vnode = *(reinterpret_cast<" ,sysname "*>(pnode));") ("// state is a reference to the model state ") (struct ,(s+ sysname "::Buffers_") "*b;") ("b = &(vnode.B_);") (,(sprintf #<N; i++) { b->u[i] = y[i] + 0.01; } ~A_dynamics(t, b->u, b->jac, pnode); for (int i = 0; i < b->N; i++) { dfdt[i*b->N + i] = (b->jac[i] - dfdy[i]) / .001; } return 0; EOF sysname)) #\} )) ) ) (define (output-parameters sysname imports const-defs external-eq-defs defaults indent indent+) (let* ((parameter-defs (map (lambda (def) (list (first def) (add-params-to-fncall (canonicalize-expr/C++ (second def)) builtin-fns))) const-defs)) (parameter-locals (find-locals (map second parameter-defs)))) (pp indent ,nl (,(s+ sysname "::Parameters_::Parameters_") () ":")) (let ((const-exprs (map (lambda (def) (let* ((n (first def)) (b (second def))) (s+ (nest-name n) " (" (expr->string/C++ b) ")"))) const-defs) ) (default-exprs (map (lambda (def) (let ((n (first def)) (b (second def))) (expr->string/C++ (nest-name b) (nest-name n)))) defaults)) ) (if (not (null? parameter-locals)) (pp indent+ (double ,(slp ", " parameter-locals) ";"))) (pp indent+ ,(slp ",\n" const-exprs)) (pp indent #\{ ,(slp "\n" default-exprs) #\}) )) ) (define (output-init sysname state-index-map steady-state-index-map imports external-eq-defs const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions defaults indent indent+) (let* ((N (length state-index-map)) (i-eqs (map (lambda (def) (list (first def) (add-params-to-fncall (canonicalize-expr/C++ (second def)) builtin-fns))) i-eqs)) (init-eqs (append (map (lambda (def) (let ((n (first def)) (b (second def))) (list (nest-name n) (nest-name b)))) external-eq-defs) asgn-eq-defs init-eq-defs (map (lambda (pool-ion) (let ((n (pool-ion-in pool-ion)) (b (pool-ion-inq pool-ion))) (list n b))) pool-ions) (map (lambda (pool-ion) (let ((n (pool-ion-out pool-ion)) (b (pool-ion-outq pool-ion))) (list n b))) pool-ions) )) (init-dag (map (lambda (def) (cons (first def) (enum-freevars (second def) '() '()))) init-eqs)) (init-order (reverse (topological-sort init-dag (lambda (x y) (string=? (->string x) (->string y)))))) (init-locals (find-locals (map second (append init-eqs i-eqs reaction-eq-defs)))) ) (pp indent ,nl (,(s+ sysname "::State_::State_") (const Parameters_& p) ": r_(0)")) (pp indent #\{) (pp indent+ (double ,(slp ", " (delete-duplicates (map ->string (filter (lambda (x) (not (member x nest-builtin-consts))) (append init-locals init-order (map first external-eq-defs) (map pool-ion-in pool-ions) (map pool-ion-out pool-ions) (map first i-eqs) (map first state-index-map) (map first const-defs) (map first reaction-eq-defs) ))) string=?)) ";") ("const Parameters_ *params = &p;") ) (pp indent+ ,(sprintf "memset(y_,0,~A*sizeof(double));" N)) (for-each (lambda (n) (pp indent+ ,(expr->string/C++ (s+ "p." n) n))) (map (compose nest-name first) const-defs) ) (let ((vi (lookup-def 'v state-index-map)) (vrest (or (and (lookup-def 'Vrest const-defs) 'Vrest) -65.0))) (if (and vi vrest) (pp indent+ ,(expr->string/C++ vrest 'v )))) (for-each (lambda (n) (let ((b (lookup-def n init-eqs))) (if b (pp indent+ ,(expr->string/C++ b (nest-name n)))))) init-order) (for-each (lambda (def) (let* ((n (first def)) (ni (lookup-def n state-index-map))) (if ni (pp indent+ ,(expr->string/C++ n (s+ "y_[" ni "]")))))) init-eq-defs) #| (if (not (null? steady-state-index-map)) (begin (gsl-fminimizer sysname N indent+) (for-each (lambda (def) (let* ((n (first def)) (si (lookup-def n steady-state-index-map)) (ni (lookup-def n state-index-map))) (if si (begin (pp indent+ ,(expr->string/C++ (s+ "gsl_vector_get(ys, " si ")") n)) (pp indent+ ,(expr->string/C++ (s+ "gsl_vector_get(ys," si ")") (s+ "y_[" ni "]"))))))) rate-eq-defs) (pp indent+ "gsl_vector_free (ys);") )) |# (for-each (lambda (def) (let ((n (first def)) (b (second def))) (if (not (lookup-def n init-eq-defs)) (pp indent+ ,(expr->string/C++ b n))))) reaction-eq-defs) (for-each (lambda (def) (pp indent+ ,(expr->string/C++ (second def) (first def)))) i-eqs) (let ((vi (lookup-def 'v state-index-map))) (if vi (pp indent+ ,(expr->string/C++ 'v (s+ "y_[" vi "]"))))) (pp indent #\}) (pp indent ,nl (,(s+ sysname "::State_::State_") (const State_& s) ": r_(0)" ) ) (pp indent #\{) (pp indent+ (,(sprintf "for ( int i = 0 ; i < ~A ; ++i ) y_[i] = s.y_[i];" N))) (pp indent #\}) (pp indent ,nl (,(s+ sysname "::State_& " sysname "::State_::operator=(const State_& s)"))) (pp indent #\{) (pp indent+ (,(sprintf #<gradient, 1e-3); } while (minimizer_status == GSL_CONTINUE && minimizer_iterc < 100); gsl_multimin_fdfminimizer_free (S); EOF sysname sysname sysname N N N N))) ) (define (output-accessors+modifiers sysname imports state-index-map const-defs asgn-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions indent indent+) (pp indent ,nl (,(sprintf "void ~A::Parameters_::get (DictionaryDatum &d) const" sysname) )) (pp indent #\{) (for-each (lambda (def) (let ((n (first def))) (pp indent+ (,(sprintf "def(d, ~S, ~A);" (->string n) n))))) const-defs) (pp indent #\}) (pp indent ,nl (,(sprintf "void ~A::Parameters_::set (const DictionaryDatum &d)" sysname) )) (pp indent #\{) (for-each (lambda (def) (let ((n (first def))) (pp indent+ (,(sprintf "updateValue(d, ~S, ~A);" (->string n) n))))) const-defs) (pp indent #\}) (pp indent ,nl (,(sprintf "void ~A::State_::get (DictionaryDatum &d) const" sysname) )) (pp indent #\{) (for-each (lambda (def) (let ((n (first def)) (i (second def))) (pp indent+ (,(sprintf "def(d, ~S, y_[~A]);" (->string n) i))))) state-index-map) (let ((vi (lookup-def 'v state-index-map))) (if vi (pp indent+ (,(sprintf "def(d, names::V_m, y_[~A]);" vi) )) )) (pp indent #\}) (pp indent ,nl (,(sprintf "void ~A::State_::set (const DictionaryDatum &d, const Parameters_&)" sysname) )) (pp indent #\{) (for-each (lambda (def) (let ((n (first def)) (i (second def))) (pp indent+ (,(sprintf "updateValue(d, ~S, y_[~A]);" (->string n) i))))) state-index-map) (let ((vi (lookup-def 'v state-index-map))) (if vi (pp indent+ (,(sprintf "updateValue(d, names::V_m, y_[~A]);" vi) )) )) (pp indent #\}) ) (define (output-handle sysname state-index-map steady-state-index-map const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions synapse-info indent indent+) (pp indent ,nl (,(sprintf #< 0); flag = 0; EOF sysname))) (let ((isyns (lookup-def 'i-synapses synapse-info)) (pscs (lookup-def 'post-synaptic-conductances synapse-info))) (for-each (lambda (isyn psc) (pp indent+ (,(sprintf #< P_.~A)) { B_.spike_~A.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), abs(e.get_weight()) * e.get_multiplicity()); flag = 1; } EOF (nest-name (second isyn)) (second psc))))) isyns pscs)) (pp indent ,nl #\} ,nl) (pp indent ,nl (,(sprintf #< 0); const double_t c=e.get_current(); const double_t w=e.get_weight(); B_.currents_.add_value(e.get_rel_delivery_steps(network()->get_slice_origin()), w *c); } void ~A::handle(DataLoggingRequest& e) { B_.logger_.handle(e); } EOF sysname sysname))) ) (define (output-recordables sysname state-index-map steady-state-index-map const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions indent indent+) (pp indent ,nl (,(sprintf "RecordablesMap<~A> ~A::recordablesMap_;" sysname sysname))) (pp indent (,(sprintf "template <> void RecordablesMap<~A>::create()" sysname))) (pp indent #\{) (for-each (lambda (def) (let ((n (first def)) (i (second def))) (pp indent+ (,(sprintf "insert_(~S, &~A::get_y_elem_<~A::State_::~A>);" (->string n) sysname sysname (string-upcase (->string n))))) )) state-index-map) (if (lookup-def 'v state-index-map) (pp indent+ (,(sprintf "insert_(names::V_m, &~A::get_y_elem_<~A::State_::~A>);" sysname sysname (string-upcase (->string 'v)))))) (pp indent #\}) ) (define (output-prelude sysname steady-state-index-map indent) (pp indent (,(sprintf "#include \"~A.h\" #include \"exceptions.h\" #include \"network.h\" #include \"dict.h\" #include \"integerdatum.h\" #include \"doubledatum.h\" #include \"dictutils.h\" #include \"numerics.h\" #include #include \"universal_data_logger_impl.h\" #include #include #include #include #include " sysname))) ) (define (output-header sysname method state-index-map steady-state-index-map defaults external-eq-defs const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions synapse-info indent indent+) (pp indent ("#include \"nest.h\" #include \"event.h\" #include \"archiving_node.h\" #include \"ring_buffer.h\" #include \"connection.h\" #include \"universal_data_logger.h\" #include \"recordables_map.h\" ")) (case method ((leapfrog) (pp indent ("#define Ith(v,i) (v[i]) /* Ith component in a vector */") )) ((cvode) (pp indent ("#include /* prototypes for CVODE fcts., consts. */") ("#include /* serial N_Vector types, fcts., macros */") ("#include /* prototype for CVDiag */") ("#include /* definition of type realtype */") ("#define Ith(v,i) NV_Ith_S(v,i) /* Ith component in a vector */") )) ((gsl) (pp indent ("#include ") ("#include ") ("#include ") ("#include ") ("#define Ith(v,i) (v[i])") )) ) (pp indent ("#define PI M_PI")) (pp indent ,nl) (pp indent "namespace nest {" ,nl) (case method ((cvode) (pp indent #<= 0 * opt == 2 means function allocates memory so check if returned * NULL pointer */ static int check_flag(void *flagvalue, const char *funcname, int opt) { int *errflag; /* Check if CVode function returned NULL pointer - no memory allocated */ if (opt == 0 && flagvalue == NULL) { fprintf(stderr, "\nCVode error: %s() failed - returned NULL pointer\n\n", funcname); return(1); } /* Check if flag < 0 */ else if (opt == 1) { errflag = (int *) flagvalue; if (*errflag < 0) { fprintf(stderr, "\nCVode error: %s() failed with flag = %d\n\n", funcname, *errflag); return(1); }} /* Check if function returned NULL pointer - no memory allocated */ else if (opt == 2 && flagvalue == NULL) { fprintf(stderr, "\nMemory error: %s() failed - returned NULL pointer\n\n", funcname); return(1); } return(0); } EOF ))) (case method ((leapfrog) (pp indent ("typedef int (*rhsfn_t)(double t, const double *y, double *ydot, void *user_data);") ,nl (extern "\"C\"" int ,(s+ sysname "_dynamics")\ "(double, const double *, double *, void*)" #\;) ,nl)) ((cvode) (pp indent (extern "\"C\"" int ,(s+ sysname "_dynamics") "(double, const N_Vector, N_Vector, void*)" #\;) ,nl)) (else (pp indent (extern "\"C\"" int ,(s+ sysname "_dynamics") "(double, const double*, double*, void*)" #\;) ,nl)) ) (pp indent (,(sprintf "class ~A:" sysname) "public Archiving_Node { ")) (pp indent+ ("public: ") (,(s+ "~" sysname "();")) (,(s+ sysname "(const " sysname "&);")) (,(s+ sysname "();"))) (pp indent (#<; friend class UniversalDataLogger<~A>; EOF sysname sysname))) (pp indent+ ,nl "struct Parameters_ { ") (for-each (lambda (x) (pp indent+ (,(sprintf "double ~A;" x)))) (append (map (compose nest-name first) const-defs) (map (compose nest-name first) defaults))) (pp indent+ ("Parameters_();") ("void get(DictionaryDatum&) const;") ("void set(const DictionaryDatum&);")) (pp indent+ "};") (pp indent+ ,nl "struct State_ { ") (pp indent+ ,nl "enum StateVecElems {" (,(slp ", " (map (lambda (x) (let ((n (string-upcase (->string (first x)))) (ni (second x))) (s+ n " = " ni))) state-index-map))) "};" "int_t r_;" (,(sprintf "double y_[~A];" (length state-index-map))) "State_(const Parameters_& p);" "State_(const State_& s);" "State_& operator=(const State_& s);" "void get(DictionaryDatum&) const;" "void set(const DictionaryDatum&, const Parameters_&);") (pp indent+ "};") (pp indent+ ,nl #< logger_;" sysname))) (let ((pscs (lookup-def 'post-synaptic-conductances synapse-info))) (for-each (lambda (psc) (pp indent+ (,(sprintf "RingBuffer spike_~A;" (second psc))))) pscs)) (pp indent+ ,nl (,(case method ((leapfrog) #<" "double_t get_y_elem_() const { return S_.y_[elem]; }" "Parameters_ P_;" "State_ S_;" "Variables_ V_;" "Buffers_ B_;" (,(sprintf "static RecordablesMap<~A> recordablesMap_;" sysname)) "}; ") (pp indent+ (,(sprintf #<connect_sender(e, receptor_type); } inline port ~A::connect_sender(SpikeEvent&, port receptor_type) { if (receptor_type != 0) throw UnknownReceptorType(receptor_type, get_name()); return 0; } inline port ~A::connect_sender(CurrentEvent&, port receptor_type) { if (receptor_type != 0) throw UnknownReceptorType(receptor_type, get_name()); return 0; } inline port ~A::connect_sender(DataLoggingRequest& dlr, port receptor_type) { if (receptor_type != 0) throw UnknownReceptorType(receptor_type, get_name()); return B_.logger_.connect_logging_device(dlr, recordablesMap_); } inline void ~A::get_status(DictionaryDatum &d) const { P_.get(d); S_.get(d); Archiving_Node::get_status(d); (*d)[names::recordables] = recordablesMap_.get_list(); def(d, names::t_spike, get_spiketime_ms()); } inline void ~A::set_status(const DictionaryDatum &d) { Parameters_ ptmp = P_; // temporary copy in case of errors ptmp.set(d); // throws if BadProperty State_ stmp = S_; // temporary copy in case of errors stmp.set(d, ptmp); // throws if BadProperty // We now know that (ptmp, stmp) are consistent. We do not // write them back to (P_, S_) before we are also sure that // the properties to be set in the parent class are internally // consistent. Archiving_Node::set_status(d); // if we get here, temporaries contain consistent set of properties P_ = ptmp; S_ = stmp; calibrate(); } EOF sysname sysname sysname sysname sysname sysname))) (pp indent "}" ,nl) ) (define (output-update sysname method state-index-map steady-state-index-map const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs defaults i-eqs pool-ions perm-ions synapse-info indent indent+) (let* ((vi (lookup-def 'v state-index-map)) (threshold (sprintf #<= P_.V_t && V_.U_old_ > S_.y_[~A]) { S_.r_ = V_.RefractoryCounts_; set_spiketime(Time::step(origin.get_steps()+lag+1)); SpikeEvent se; network()->send(*this, se, lag); } EOF vi vi))) (pp indent (,(sprintf #<= 0 && (delay) from < Scheduler::get_min_delay()); assert(from < to); double tout; long_t current_steps = origin.get_steps(); for ( long_t lag = from ; lag < to ; ++lag ) { double h = B_.step_; double tt = 0.0 ; V_.U_old_ = S_.y_[~A]; EOF vi))) (case method ((leapfrog) (pp indent+ (,(sprintf #<(this)); for (int i = 0; i < B_.N; i++) { B_.u[i] = S_.y_[i] + 0.5 * h * B_.dvdt[i]; } B_.sys_ (tt+0.5*h, B_.u, B_.dvdt, reinterpret_cast(this)); for (int i = 0; i < B_.N; i++) { B_.v[i] = S_.y_[i] + h * B_.dvdt[i]; } tt += h; } for (int i = 0; i < B_.N; i++) { S_.y_[i] = B_.v[i]; } EOF )) )) ((cvode) (pp indent+ (,(sprintf #<(proto); P_ = pr.P_; S_ = State_(P_); } EOF sysname sysname sysname))) (pp indent ,nl (,(sprintf #<(proto); S_ = State_(pr.P_); } EOF sysname sysname sysname))) (pp indent ,nl (,(sprintf #<(this)); if (check_flag(&status, "CVodeSetUserData", 1)) abort(); /* Initializes diagonal linear solver. */ status = CVDiag (B_.sys_); if (check_flag(&status, "CVDiag", 1)) abort(); EOF N sysname)))) ((gsl) (pp indent+ (,(sprintf #<(this); B_.u = (double *)malloc(sizeof(double) * B_.N); assert (B_.u); B_.jac = (double *)malloc(sizeof(double) * B_.N); assert (B_.jac); EOF N sysname sysname)))) ) (pp indent ,nl #\}) (let ((iv (lookup-def 'v state-index-map))) (if iv (pp indent ,nl (,(sprintf #<string sysname)) (deps* ((dis 'depgraph*) sys)) (consts ((dis 'consts) sys)) (asgns ((dis 'asgns) sys)) (states ((dis 'states) sys)) (reactions ((dis 'reactions) sys)) (defuns ((dis 'defuns) sys)) (components ((dis 'components) sys)) (g (match-let (((state-list asgn-list g) ((dis 'depgraph*) sys))) g)) (poset (vector->list ((dis 'depgraph->bfs-dist-poset) g))) (const-defs (filter-map (lambda (nv) (and (not (member (first nv) nest-builtin-consts)) (let ((v1 (canonicalize-expr/C++ (second nv)))) (list (nest-name (first nv)) v1)))) consts)) (gate-complex-info (nemo:gate-complex-query sys)) (synapse-info (nemo:post-synaptic-conductance-query sys)) (i-synapses (lookup-def 'i-synapses synapse-info)) (defaults (nemo:defaults-query sys)) (geometry (nemo:geometry-query sys)) (gate-complexes (lookup-def 'gate-complexes gate-complex-info)) (perm-ions (map (match-lambda ((comp i e erev val) `(,comp ,(nest-name i) ,(nest-name e) ,erev))) (lookup-def 'perm-ions gate-complex-info))) (acc-ions (map (match-lambda ((comp i in out) `(,comp ,@(map nest-name (list i in out))))) (lookup-def 'acc-ions gate-complex-info))) (epools (lookup-def 'pool-ions gate-complex-info)) (pool-ions (pool-ion-name-map nest-name epools)) (i-gates (lookup-def 'i-gates gate-complex-info)) (comprc (any (match-lambda ((name 'membrane-tau id) (list name id)) (else #f)) components)) (compcap (any (match-lambda ((name 'membrane-capacitance id) (list name id)) (else #f)) components)) (mrc (or (and comprc (car ((dis 'component-exports) sys (cid comprc)))) (and compcap (car ((dis 'component-exports) sys (cid compcap)))))) (soma-geometry (lookup-def 'soma geometry)) (marea (and soma-geometry (third soma-geometry))) (i-eqs (filter-map (lambda (gate-complex) (let* ((label (first gate-complex)) (n (second gate-complex)) (subcomps ((dis 'component-subcomps) sys n)) (acc (lookup-def 'accumulating-substance subcomps)) (perm (lookup-def 'permeating-ion subcomps)) (permqs (and perm ((dis 'component-exports) sys (cid perm)))) (pore (lookup-def 'pore subcomps)) (permeability (lookup-def 'permeability subcomps)) (gates (filter (lambda (x) (equal? (car x) 'gate)) subcomps)) (sts (map (lambda (gate) ((dis 'component-exports) sys (cid gate))) gates)) ) (if (and pore (null? permqs)) (nemo:error 'nemo:nest-translator ": ion channel definition " label "permeating-ion component lacks exported quantities")) (for-each (lambda (st) (if (null? st) (nemo:error 'nemo:nest-translator: "ion channel definition " label "gate component lacks exported quantities"))) sts) (if (not (or pore permeability)) (nemo:error 'nemo:nest-translator ": ion channel definition " label "lacks any pore or permeability components")) (cond ((and perm permeability (pair? gates)) (let* ((i (nest-name (s+ 'i (cn perm)))) (pmax (car ((dis 'component-exports) sys (cid permeability)))) (pwrs (map (lambda (st) (map (lambda (n) (rate/reaction-power sys n)) st)) sts)) (gpwrs (map (lambda (st pwr) (map (lambda (s p) (if p `(pow ,s ,p) s)) st pwr)) sts pwrs)) (gion `(* ,pmax ,(sum (map (lambda (gpwr) (match gpwr ((x) x) (else `(* ,@gpwr)))) gpwrs)))) ) (list i #f gion (nest-name (s+ 'i_ label) )))) ((and perm pore (pair? gates)) (case (cn perm) ((non-specific) (let* ((i (nest-name 'i)) (e (car permqs)) (gmax (car ((dis 'component-exports) sys (cid pore)))) (pwrs (map (lambda (st) (map (lambda (n) (rate/reaction-power sys n)) st)) sts)) (gpwrs (map (lambda (st pwr) (map (lambda (s p) (if p `(pow ,s ,p) s)) st pwr)) sts pwrs)) (gion `(* ,gmax ,(sum (map (lambda (gpwr) (match gpwr ((x) x) (else `(* ,@gpwr)))) gpwrs)))) ) (list i e gion (nest-name (s+ 'i_ label) )))) (else (let* ((i (nest-name (s+ 'i (cn perm)))) (e (car permqs)) (gmax (car ((dis 'component-exports) sys (cid pore)))) (pwrs (map (lambda (st) (map (lambda (n) (rate/reaction-power sys n)) st)) sts)) (gpwrs (map (lambda (st pwr) (map (lambda (s p) (if p `(pow ,s ,p) s)) st pwr)) sts pwrs)) (gion `(* ,gmax ,(sum (map (lambda (gpwr) (match gpwr ((x) x) (else `(* ,@gpwr)))) gpwrs)))) ) (list i e gion (nest-name (s+ 'i_ label) )))))) ((and perm pore) (case (cn perm) ((non-specific) (let* ((i (nest-name 'i)) (e (car permqs)) (gmax (car ((dis 'component-exports) sys (cid pore))))) (list i e gmax (nest-name (s+ 'i_ label) )))) (else (nemo:error 'nemo:nest-translator ": invalid ion channel definition " label)))) ((and acc pore (pair? gates)) (let* ((i (nest-name (s+ 'i (cn acc)))) (gmax (car ((dis 'component-exports) sys (cid pore)))) (pwrs (map (lambda (st) (map (lambda (n) (rate/reaction-power sys n)) st)) sts)) (gpwrs (map (lambda (st pwr) (map (lambda (s p) (if p `(pow ,s ,p) s)) st pwr)) sts pwrs)) (gion `(* ,gmax ,(sum (map (lambda (gpwr) (match gpwr ((x) x) (else `(* ,@gpwr)))) gpwrs)))) ) (list i #f gion (nest-name (s+ 'i_ label) )))) (else (nemo:error 'nemo:nest-translator ": invalid ion channel definition " label)) ))) gate-complexes)) (i-names (delete-duplicates (map first i-eqs))) (i-eqs (fold (lambda (i-gate ax) (let ((i-gate-var (first i-gate))) (cons (list (nest-name 'i) #f i-gate-var (s+ 'i_ (second i-gate))) ax))) i-eqs i-gates)) (i-eqs (fold (lambda (i-synapse ax) (cons (list (first i-synapse) (third i-synapse) (second i-synapse) (gensym 'i_syn )) ax)) i-eqs i-synapses)) (i-bkts (bucket-partition (lambda (x y) (eq? (car x) (car y))) i-eqs)) (i-eqs (fold (lambda (b ax) (match b ((and ps ((i e gion ii) . rst)) (let loop ((ps ps) (summands (list)) (eqs (list))) (if (null? ps) (let* ((sum0 (sum summands)) (sum1 (rhsexpr/C++ sum0)) (sum2 (add-params-to-fncall (canonicalize-expr/C++ sum1) builtin-fns))) (append eqs (list (list i sum2)) ax)) (match-let (((i e gion ii) (car ps))) (loop (cdr ps) (cons ii summands) (let* ((expr0 (rhsexpr/C++ (if e `(* ,gion (- v ,e)) gion))) (expr1 (canonicalize-expr/C++ expr0))) (cons (list ii expr1) eqs))))))) ((i e gion ii) (let* ((expr0 (rhsexpr/C++ (if e `(* ,gion (- v ,e)) gion))) (expr1 (canonicalize-expr/C++ expr0))) (cons (list i expr1) ax))) (else ax))) (list) i-bkts)) (external-eq-defs (external-eq-defs sys nest-name rhsexpr/C++ canonicalize-expr/C++)) (asgn-eq-defs (poset->asgn-eq-defs* poset sys nest-name rhsexpr/C++ canonicalize-expr/C++ builtin-fns)) (rate-eq-defs (reverse (poset->rate-eq-defs* poset sys method nest-name nest-state-name rhsexpr/C++ canonicalize-expr/C++ builtin-fns))) (reaction-eq-defs (poset->reaction-eq-defs* poset sys nest-name nest-state-name rhsexpr/C++ canonicalize-expr/C++)) (init-eq-defs (poset->init-defs* poset sys nest-name nest-state-name rhsexpr/C++ canonicalize-expr/C++ builtin-fns)) (conserve-eq-defs (map (lambda (eq) (list 0 `(- ,(second eq) ,(first eq)))) (poset->state-conserve-eq-defs poset sys nest-name nest-state-name))) (imports-sans-v (filter (lambda (x) (not (equal? 'v (first x)))) imports)) (v-eq (and (not (null? i-names)) (let ((istim "(node.B_.I_stim_)" )) (cond ((and mrc marea) (list 'v (rhsexpr/C++ `(* 1e3 (/ (+ (* ,istim (/ 100. ,marea)) (neg ,(sum i-names))) ,mrc))))) (marea (list 'v (rhsexpr/C++ `(* 1e3 (+ (* ,istim (/ 100. ,marea)) (neg ,(sum i-names))))))) (mrc (list 'v (rhsexpr/C++ `(* 1e3 (/ (+ ,istim (neg ,(sum i-names))) ,mrc))))) (else (list 'v (rhsexpr/C++ `(* 1e3 (+ ,istim (neg ,(sum i-names))))))) )) )) (state-index-map (let ((acc (fold (lambda (def ax) (let ((st-name (first def))) (list (+ 1 (first ax)) (cons `(,st-name ,(first ax)) (second ax))))) (list 0 (list)) (if (lookup-def 'v imports) (cons (list 'v) rate-eq-defs) rate-eq-defs) ))) (second acc))) (steady-state-index-map (let ((acc (fold (lambda (def ax) (let ((st-name (first def))) (if (not (alist-ref st-name init-eq-defs)) (list (+ 1 (first ax)) (cons `(,st-name ,(first ax)) (second ax))) ax))) (list 0 (list)) rate-eq-defs))) (second acc))) (dfenv (map (lambda (x) (let ((n (first x))) (list n (nest-name (s+ "d_" n ))))) defuns)) ) (for-each (lambda (a) (let ((acc-ion (car a))) (if (assoc acc-ion perm-ions) (nemo:error 'nemo:nest-translator ": ion species " acc-ion " cannot be declared as both accumulating and permeating")))) acc-ions) (let ((cpp-output (open-output-file (make-output-fname dirname prefix ".cpp"))) (hpp-output (open-output-file (make-output-fname dirname prefix ".h")))) ;; include files and other prelude definitions (with-output-to-port cpp-output (lambda () (pp indent ,nl ("/* " This file was generated by ,(nemo:version-string) on ,(seconds->string (current-seconds)) " */" ,nl)) (output-prelude sysname steady-state-index-map indent) )) (with-output-to-port cpp-output (lambda () (pp indent "namespace nest {" ,nl))) ;; user-defined functions (let ((define-fn (make-define-fn sysname)) (define-fn-header (make-define-fn-header sysname))) (for-each (lambda (fndef) (if (not (member (car fndef) builtin-fns)) (with-output-to-port cpp-output (lambda () (apply define-fn-header (cons indent fndef)) (pp indent ,nl))) )) defuns) (for-each (lambda (fndef) (if (not (member (car fndef) builtin-fns)) (with-output-to-port cpp-output (lambda () (apply define-fn (cons indent fndef)) (pp indent ,nl))) )) defuns) ) ;; derivative function (with-output-to-port cpp-output (lambda () (output-dy sysname method imports-sans-v const-defs state-index-map external-eq-defs rate-eq-defs reaction-eq-defs asgn-eq-defs pool-ions i-eqs v-eq indent indent+) )) ;; Jacobian function (with-output-to-port cpp-output (lambda () (output-jac sysname method state-index-map pool-ions i-eqs v-eq indent indent+) )) ;; system recordables (with-output-to-port cpp-output (lambda () (output-recordables sysname state-index-map steady-state-index-map const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions indent indent+) (pp indent ,nl) )) ;; system parameters (with-output-to-port cpp-output (lambda () (output-parameters sysname imports-sans-v const-defs external-eq-defs defaults indent indent+) )) ;; initial values function (with-output-to-port cpp-output (lambda () (output-init sysname state-index-map steady-state-index-map imports-sans-v external-eq-defs const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions defaults indent indent+) (pp indent ,nl) )) ;; accessors and modifiers for states and parameters (with-output-to-port cpp-output (lambda () (output-accessors+modifiers sysname imports-sans-v state-index-map const-defs asgn-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions indent indent+) (pp indent ,nl) )) ;; buffer and node initialization (with-output-to-port cpp-output (lambda () (output-buffers+nodes sysname method state-index-map steady-state-index-map const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions synapse-info indent indent+) (pp indent ,nl) )) ;; state update (with-output-to-port cpp-output (lambda () (output-update sysname method state-index-map steady-state-index-map const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs defaults i-eqs pool-ions perm-ions synapse-info indent indent+) (pp indent ,nl) )) ;; spike handler (with-output-to-port cpp-output (lambda () (output-handle sysname state-index-map steady-state-index-map const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions synapse-info indent indent+) (pp indent ,nl) )) (with-output-to-port cpp-output (lambda () (pp indent "}" ,nl))) (with-output-to-port hpp-output (lambda () (pp indent ,nl ("/* " This file was generated by ,(nemo:version-string) on ,(seconds->string (current-seconds)) " */" ,nl)) (output-header sysname method state-index-map steady-state-index-map defaults external-eq-defs const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs pool-ions perm-ions synapse-info indent indent+) (pp indent ,nl) )) (close-output-port cpp-output) (close-output-port hpp-output) )) )) )) ) )