;; ;; TODO: implement a new component type to be used for thresholds ;; TODO: finish gsl-fminimizer ;; ;; An extension for translating NEMO models to NEST code. ;; ;; Copyright 2011-2012 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 lolevel ports extras srfi-1 srfi-13 srfi-69) (require-extension lolevel matchable strictly-pretty varsubst datatype nemo-core nemo-utils nemo-gate-complex nemo-synapse) (define nest-builtin-consts `()) (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 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) (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 (state-init n init) (let* ((init (rhsexpr/C++ init)) (init1 (canonicalize-expr/C++ init))) (list (nest-name n) init1))) (define (asgn-eq n rhs) (let* ((fbody (rhsexpr/C++ rhs)) (fbody1 (canonicalize-expr/C++ fbody))) (list (nest-name n) fbody1))) (define (reaction-eq n open transitions conserve) (match-let (((g cnode node-subs) (transitions-graph n open transitions conserve nest-state-name))) (let ((nodes ((g 'nodes)))) (list (nest-name n) (nest-state-name n open))))) (define (reaction-transition-eqs n initial open transitions conserve power) (match-let (((g cnode node-subs) (transitions-graph n open transitions conserve nest-state-name))) (let* ((out-edges (g 'out-edges)) (in-edges (g 'in-edges)) (nodes ((g 'nodes)))) ;; generate differential equations for each state in the transitions system (let ((eqs (fold (lambda (s ax) (if (= (first cnode) (first s) ) ax (let* ((out (out-edges (first s))) (in (in-edges (first s))) (open? (eq? (second s) open)) (name (nest-name (lookup-def (second s) node-subs)))) (let* ((rhs1 (cond ((and (not (null? out)) (not (null? in))) `(+ (neg ,(sum (map third out))) ,(sum (map third in)))) ((and (not (null? out)) (null? in)) `(neg ,(sum (map third out)))) ((and (null? out) (not (null? in))) (sum (map third in))))) (fbody0 (rhsexpr/C++ rhs1))) (cons (list name (canonicalize-expr/C++ fbody0)) ax) )))) (list) nodes))) eqs)))) (define (poset->asgn-eq-defs poset sys) (fold-right (lambda (lst ax) (fold (lambda (x ax) (match-let (((i . n) x)) (let ((en (hash-table-ref sys n))) (if (nemo:quantity? en) (cases nemo:quantity en (ASGN (name value rhs) (cons (asgn-eq name rhs) ax)) (else ax)) ax)))) ax lst)) (list) poset)) (define (poset->rate-eq-defs poset sys) (fold-right (lambda (lst ax) (fold (lambda (x ax) (match-let (((i . n) x)) (let ((en (hash-table-ref sys n))) (if (nemo:quantity? en) (cases nemo:quantity en (REACTION (name initial open transitions conserve power) (append (reaction-transition-eqs name initial open transitions conserve power) ax)) (RATE (name initial rhs power) (let ((fbody0 (rhsexpr/C++ rhs)) (dy (nest-name name) )) (cons (list dy (canonicalize-expr/C++ fbody0)) ax))) (else ax)) ax)))) ax lst)) (list) poset)) (define (poset->reaction-eq-defs poset sys) (fold-right (lambda (lst ax) (fold (lambda (x ax) (match-let (((i . n) x)) (let ((en (hash-table-ref sys n))) (if (nemo:quantity? en) (cases nemo:quantity en (REACTION (name initial open transitions conserve power) (cons (reaction-eq name open transitions conserve) ax)) (else ax)) ax)))) ax lst)) (list) poset)) (define (poset->init-defs poset sys) (fold-right (lambda (lst ax) (fold-right (lambda (x ax) (match-let (((i . n) x)) (let ((en (hash-table-ref sys n))) (if (nemo:quantity? en) (cases nemo:quantity en (REACTION (name initial open transitions conserve power) (if (nemo:rhs? initial) (cons* (state-init name initial) (state-init (nest-state-name name open) name) ax) ax)) (RATE (name initial rhs power) (if (and initial (nemo:rhs? initial)) (cons (state-init name initial) ax) ax)) (else ax)) ax)))) ax lst)) (list) poset)) (define (poset->state-conserve-eq-defs poset sys) (fold-right (lambda (lst ax) (fold (lambda (x ax) (match-let (((i . n) x)) (let ((en (hash-table-ref sys n))) (if (nemo:quantity? en) (cases nemo:quantity en (REACTION (name initial open transitions conserve power) (if (and (list? conserve) (every nemo:conseq? conserve)) (cons (state-conseqs (nest-name name) transitions conserve nest-state-name) ax) ax)) (else ax)) ax)))) ax lst)) (list) poset)) (define (find-locals defs) (concatenate (map (lambda (def) (match def (('let bnds body) (let ((bexprs (map second bnds))) (concatenate (list (map first bnds) (find-locals bexprs ) (find-locals (list body)))))) (('if c t e) (append (find-locals (list t)) (find-locals (list e)))) ((s . rest) (find-locals rest)) (else (list)))) defs))) (define (rate/reaction-power sys n) (let ((en (hash-table-ref sys n))) (if (nemo:quantity? en) (cases nemo:quantity en (REACTION (name initial open transitions conserve power) power) (RATE (name initial rhs power) power) (else #f)) #f))) (define (bucket-partition p lst) (let loop ((lst lst) (ax (list))) (if (null? lst) ax (let ((x (car lst))) (let bkt-loop ((old-bkts ax) (new-bkts (list))) (if (null? old-bkts) (loop (cdr lst) (cons (list x) new-bkts)) (if (p x (caar old-bkts )) (loop (cdr lst) (append (cdr old-bkts) (cons (cons x (car old-bkts)) new-bkts))) (bkt-loop (cdr old-bkts) (cons (car old-bkts) new-bkts))))))))) (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 (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)) '("void* pnode")))) (pp indent ,nl (,rt ,(nest-name n) (,(slp ", " argument-list)) "{" )) (let* ((body0 (rhsexpr/C++ body)) (body1 (canonicalize-expr/C++ body0)) (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 nest-name consts)) ";") ("const " ,sysname "& node = *(reinterpret_cast<" ,sysname "*>(pnode));")) (for-each (lambda (x) (pp indent+ (,(nest-name x) = ,(s+ "node.P_." (nest-name x) ";")))) consts) )) (pp indent+ ,(expr->string/C++ body1 (nest-name rv))) (pp indent+ ,(s+ "return " rv ";")) )) (pp indent "}")) ))) (define (output-dy sysname const-defs state-index-map rate-eq-defs reaction-eq-defs asgn-eq-defs pool-ions mcap i-eqs v-eq indent indent+) (pp indent ,nl (,(s+ "extern \"C\" int " sysname "_dynamics") (,(slp ", " `("double t" "const double y[]" "double f[]" "void* pnode" ))) #\{ )) (let* ( (asgn-eq-defs (map (lambda (def) (list (first def) (canonicalize-expr/C++ (second def)))) asgn-eq-defs)) (rate-eq-defs (map (lambda (def) (list (first def) (canonicalize-expr/C++ (second def)))) rate-eq-defs)) (reaction-eq-defs (map (lambda (def) (list (first def) (canonicalize-expr/C++ (second def)))) reaction-eq-defs)) (i-eqs (map (lambda (def) (list (first def) (canonicalize-expr/C++ (second def)))) i-eqs)) (v-eq (and v-eq (list (first v-eq) (canonicalize-expr/C++ (second v-eq))))) (eqs (append asgn-eq-defs reaction-eq-defs (map (lambda (pool-ion) (let ((n (third pool-ion)) (b (first pool-ion))) (list n b))) pool-ions))) (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 ->string (append eq-locals eq-order (map first state-index-map) (map first i-eqs) (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));") ,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+ "node.P_." n) n)))) const-defs) (let ((vi (lookup-def 'v state-index-map))) (if vi (pp indent+ ,(expr->string/C++ (s+ "y[" vi "]") 'v)))) (for-each (lambda (def) (let ((n (first def)) ) (pp indent+ ,(expr->string/C++ (s+ "y[" (lookup-def n state-index-map) "]") 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 (s+ "f[" (lookup-def (first def) state-index-map) "]")) (b (second def))) (pp indent+ ,(s+ "// rate equation " (first def)) ,(expr->string/C++ b n)))) rate-eq-defs) (for-each (lambda (def) (pp indent+ ,(expr->string/C++ (second def) (first def)))) i-eqs) (if v-eq (let ((vi (lookup-def 'v state-index-map))) (if vi (pp indent+ ,(expr->string/C++ (second v-eq) (s+ "f[" vi "]"))) ))) (pp indent+ ,nl ("return GSL_SUCCESS;")) (pp indent #\}) )) (define (output-parameters sysname const-defs indent indent+) (let* ((parameter-defs (map (lambda (def) (list (first def) (canonicalize-expr/C++ (second def)))) const-defs)) (parameter-locals (find-locals (map second parameter-defs)))) (pp indent ,nl (,(s+ sysname "::Parameters_::Parameters_") () ":")) (let ((const-exprs (slp ",\n" (map (lambda (def) (let* ((n (first def)) (b (second def))) (s+ (nest-name n) " (" (expr->string/C++ b) ")"))) const-defs) ))) (if (not (null? parameter-locals)) (pp indent+ (double ,(slp ", " parameter-locals) ";"))) (pp indent+ ,const-exprs) (pp indent ("{}")) ))) (define (output-init sysname state-index-map steady-state-index-map const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs v-eq pool-ions perm-ions indent indent+) (let* ((N (length state-index-map)) (asgn-eq-defs (map (lambda (def) (list (first def) (canonicalize-expr/C++ (second def)))) asgn-eq-defs)) (init-eq-defs (map (lambda (def) (list (first def) (canonicalize-expr/C++ (second def)))) init-eq-defs)) (reaction-eq-defs (map (lambda (def) (list (first def) (canonicalize-expr/C++ (second def)))) reaction-eq-defs)) (i-eqs (map (lambda (def) (list (first def) (canonicalize-expr/C++ (second def)))) i-eqs)) (v-eq (and v-eq (list (first v-eq) (canonicalize-expr/C++ (second v-eq))))) (init-eqs (append asgn-eq-defs init-eq-defs (map (lambda (pool-ion) (let ((n (third pool-ion)) (b (first 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 (append init-locals init-order (map first state-index-map) (map first i-eqs) (map first const-defs) (map first reaction-eq-defs) )) string=?)) ";")) (for-each (lambda (def) (let ((n (first def)) ) (pp indent+ ,(expr->string/C++ (s+ "p." n) n)))) 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) (if v-eq (let ((vi (lookup-def 'v state-index-map))) (if vi (pp indent+ ,(expr->string/C++ (second v-eq) (s+ "y_[" vi "]")))))) (pp indent #\}) (pp indent ,nl (,(s+ sysname "::State_::State_") (const State_& s) ": r_(s.r_)")) (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 state-index-map const-defs asgn-eq-defs rate-eq-defs reaction-eq-defs i-eqs v-eq 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) (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) (pp indent #\}) ) (define (output-buffers+nodes 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+) (let ((N (length state-index-map))) (pp indent ,nl (,(sprintf #<(proto); P_ = pr.P_; S_ = pr.S_; } EOF sysname sysname sysname))) (pp indent ,nl (,(sprintf #<(proto); S_ = pr.S_; } EOF sysname sysname sysname))) (pp indent ,nl #<(this); } EOF N N sysname N))) (let ((iv (lookup-def 'v state-index-map))) (if iv (pp indent ,nl (,(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); for ( long_t lag = from ; lag < to ; ++lag ) { double tt = 0.0 ; //it's all relative! V_.U_old_ = S_.y_[~A]; // adaptive step integration while (tt < B_.step_) { const int status = gsl_odeiv_evolve_apply(B_.e_, B_.c_, B_.s_, &B_.sys_, // system of ODE &tt, // from t... B_.step_, // ...to t=t+h &B_.IntegrationStep_ , // integration window (written on!) S_.y_); // neuron state if ( status != GSL_SUCCESS ) throw GSLSolverFailure(get_name(), status); } EOF vi))) (let ((isyns (lookup-def 'i-synapses synapse-info)) (pscs (lookup-def 'post-synaptic-conductances synapse-info))) (for-each (lambda (isyn psc) (let ((gi (lookup-def (nest-name (fourth isyn)) state-index-map))) (if gi (pp indent+ (,(sprintf " S_.y_[~A] += B_.spike_~A.get_value(lag);" gi (second psc))) )))) isyns pscs)) (pp indent+ (,(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 #include #include " sysname))) (if (not (null? steady-state-index-map)) (pp indent ("#include "))) ) (define (output-header 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 ("#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\" #include ")) (pp indent "namespace nest {" ,nl) (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 sysname))) (pp indent+ ,nl "struct Parameters_ { ") (for-each (lambda (x) (pp indent+ (,(sprintf "double ~A;" (first x))))) const-defs) (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))) "};" (,(sprintf "double y_[~A];" (length state-index-map))) "int_t r_;" "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 #<" "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 (nemo:nest-translator sys . rest) (define (cid x) (second x)) (define (cn x) (first x)) (let-optionals rest ((dirname ".")) (match-let ((($ nemo:quantity 'DISPATCH dis) (hash-table-ref sys (nemo-intern 'dispatch)))) (let ((imports ((dis 'imports) sys)) (exports ((dis 'exports) sys))) (let* ((indent 0) (indent+ (+ 2 indent )) (eval-const (dis 'eval-const)) (sysname (nest-name ((dis 'sysname) sys))) (prefix (->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)) (gate-complexes (lookup-def 'gate-complexes gate-complex-info)) (perm-ions (map (match-lambda ((comp i e erev) `(,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 (map (lambda (lst) (map nest-name lst)) epools)) (i-gates (lookup-def 'i-gates gate-complex-info)) (capcomp (any (match-lambda ((name 'membrane-capacitance id) (list name id)) (else #f)) components)) (mcap (and capcomp (car ((dis 'component-exports) sys (cid capcomp))))) (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)) (gate (lookup-def 'gate subcomps)) (sts (and gate ((dis 'component-exports) sys (cid gate))))) (if (not (or pore permeability)) (nemo:error 'nemo:nest-translator ": ion channel definition " label "lacks any pore or permeability components")) (cond ((and perm permeability gate) (let* ((i (nest-name (s+ 'i (cn perm)))) (pmax (car ((dis 'component-exports) sys (cid permeability)))) (pwrs (map (lambda (n) (rate/reaction-power sys n)) sts)) (sptms (map (lambda (st pwr) (if pwr `(pow ,st ,pwr) st)) sts pwrs)) (gion `(* ,pmax ,@sptms))) (list i #f gion (nest-name (s+ 'i_ label) )))) ((and perm pore gate) (case (cn perm) ((non-specific) (let* ((i (nest-name 'i)) (e (car permqs)) (gmax (car ((dis 'component-exports) sys (cid pore)))) (pwrs (map (lambda (n) (rate/reaction-power sys n)) sts)) (sptms (map (lambda (st pwr) (if pwr `(pow ,st ,pwr) st)) sts pwrs)) (gion `(* ,gmax ,@sptms))) (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 (n) (rate/reaction-power sys n)) sts)) (sptms (map (lambda (st pwr) (if pwr `(pow ,st ,pwr) st)) sts pwrs)) (gion `(* ,gmax ,@sptms))) (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 gate) (let* ((i (nest-name (s+ 'i (cn acc)))) (gmax (car ((dis 'component-exports) sys (cid pore)))) (pwrs (map (lambda (n) (rate/reaction-power sys n)) sts)) (sptms (map (lambda (st pwr) (if pwr `(pow ,st ,pwr) st)) sts pwrs)) (gion `(* ,gmax ,@sptms))) (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) (fourth 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 (canonicalize-expr/C++ sum1))) (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)) (asgn-eq-defs (poset->asgn-eq-defs poset sys)) (rate-eq-defs (reverse (poset->rate-eq-defs poset sys))) (reaction-eq-defs (poset->reaction-eq-defs poset sys)) (init-eq-defs (poset->init-defs poset sys)) (conserve-eq-defs (map (lambda (eq) (list 0 `(- ,(second eq) ,(first eq)))) (poset->state-conserve-eq-defs poset sys))) (globals (map nest-name (delete-duplicates (append exports (map second perm-ions) (map third perm-ions) (map second acc-ions) (map third acc-ions) (map fourth acc-ions) (map second pool-ions) (map third pool-ions) (map first imports) (map first const-defs) (map first asgn-eq-defs) (map (lambda (gate-complex) (nest-name (s+ 'i_ (first gate-complex)))) gate-complexes ) (map (lambda (i-gate) (nest-name (s+ 'i_ (second i-gate)))) i-gates ) )))) (parameters (map nest-name (map first const-defs))) (v-eq (if (and mcap (member 'v globals)) (list 'v (rhsexpr/C++ `(/ (neg ,(sum (cons "(-node.B_.I_stim_)" i-names))) ,mcap))) (list 'v 0.0))) (v-init-eq (if (and mcap (member 'v globals)) (list 'v (rhsexpr/C++ `(/ (neg ,(sum i-names)) ,mcap))) (list 'v 0.0))) (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 (member 'v globals) (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) (for-each (lambda (p) (let ((pool-ion (car p))) (if (assoc pool-ion perm-ions) (nemo:error 'nemo:nest-translator ": ion species " pool-ion " cannot be declared as both pool and permeating")))) pool-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 () (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))) (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 const-defs state-index-map rate-eq-defs reaction-eq-defs asgn-eq-defs pool-ions mcap 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 const-defs indent indent+) )) ;; initial values function (with-output-to-port cpp-output (lambda () (output-init sysname state-index-map steady-state-index-map const-defs asgn-eq-defs init-eq-defs rate-eq-defs reaction-eq-defs i-eqs v-init-eq pool-ions perm-ions indent indent+) (pp indent ,nl) )) ;; accessors and modifiers for states and parameters (with-output-to-port cpp-output (lambda () (output-accessors+modifiers sysname state-index-map const-defs asgn-eq-defs rate-eq-defs reaction-eq-defs i-eqs v-eq pool-ions perm-ions indent indent+) (pp indent ,nl) )) ;; buffer and node initialization (with-output-to-port cpp-output (lambda () (output-buffers+nodes 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) )) ;; state update (with-output-to-port cpp-output (lambda () (output-update 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) )) ;; 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 () (output-header 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) )) (close-output-port cpp-output) (close-output-port hpp-output) )) )) )) )