NEURON
hocprax.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 /*
3 Hoc interface to praxis.
4 
5 See praxis.cpp in the scopmath library about
6 tolerance (t0), maxstepsize (h0), and printmode (prin).
7 These are set with
8  attr_praxis(t0, h0, prin)
9 
10 Minimise an interpreted hoc function or compiled hoc function with
11  double x[n]
12  fit_praxis(n, "funname", &x[0], "afterquad statement")
13 where n is the number of variables on which funname depends and
14 x is a vector containing on entry a guess of the point of minimum
15 and on exit contains the estimated point of minimum.
16 (The third arg may be a Vector)
17 Funname will be called with 2 args to be retrieved by $1 and $&2[i].
18 afterquad statement (if the arg exists , will be executed
19 at the end of each main loop iteration (complete conjugate gradient search
20 followed by calculation of quadratic form)
21 eg.
22 
23 double x[2]
24 attr_praxis(1e-5, 1, -1)
25 func f() {
26  return $&0[0]^2 + 2*$&0[1]^4
27 }
28 fit_praxis(2, "f", &x)
29 
30 After fit_praxis exits, (or on execution of afterquad stmt)
31 one can retrieve the i'th principal value
32 with pval_praxis(i). If you also want the i'th principal axis then use
33 double a[n]
34 pval = pval_praxis(i, &a)
35 also can use
36 pval = pval_praxis(i, Vector)
37 */
38 
39 #include <stdlib.h>
40 #include "hocdec.h"
41 #include "nrnpy.h"
42 #include "parse.hpp"
43 #include "scoplib.h"
44 
45 extern double chkarg(int, double, double);
46 extern IvocVect* vector_new2(IvocVect* vec);
47 extern void vector_delete(IvocVect* vec);
48 extern int nrn_praxis_ran_index;
49 extern Object** hoc_objgetarg(int);
50 
51 static double efun(double*, long int);
53 
54 static double tolerance, machep, maxstepsize;
55 static long int printmode;
56 /* for prax_pval to know the proper size, following has to be the value
57 at return of previous prax call
58 */
59 static long int nvar;
60 
61 static Object* efun_py;
63 static void* vec_py_save;
64 
65 void stop_praxis(void) {
66  int i = 1;
67  if (ifarg(1)) {
68  i = (int) chkarg(1, 0., 1e5);
69  }
70  i = praxis_stop(i);
71  hoc_retpushx((double) i);
72 }
73 
74 /* want to get best result if user does a stoprun */
75 static double minerr, *minarg; /* too bad this is not recursive */
76 
77 void fit_praxis(void) {
78  char* after_quad;
79  int i;
80  double err, fmin;
81  double* px;
82  /* allow nested calls to fit_praxis. I.e. store all the needed
83  statics specific to this invocation with proper reference
84  counting and then unref/destoy on exit from this invocation.
85  Before the prax call save the statics from earlier invocation
86  without increasing the
87  ref count and on exit restore without decreasing the ref count.
88  */
89 
90  /* save before setting statics, restore after prax */
91  double minerrsav, *minargsav, maxstepsizesav, tolerancesav;
92  long int printmodesav;
93  Symbol* efun_sym_sav;
94  Object *efun_py_save, *efun_py_arg_save;
95  void* vec_py_save_save;
96 
97  /* store statics specified by this invocation */
98  /* will be copied just before calling prax */
99  double minerr_, *minarg_;
100  long int nvar_;
101  Symbol* efun_sym_;
102  Object *efun_py_, *efun_py_arg_;
103  void* vec_py_save_;
104 
105  minerr_ = 0.0;
106  nvar_ = 0;
107  minarg_ = NULL;
108  efun_sym_ = NULL;
109  efun_py_ = NULL;
110  efun_py_arg_ = NULL;
111  vec_py_save_ = NULL;
112 
113  fmin = 0.;
114 
115  if (hoc_is_object_arg(1)) {
117  efun_py_ = *hoc_objgetarg(1);
118  hoc_obj_ref(efun_py_);
119  efun_py_arg_ = *vector_pobj(vector_arg(2));
120  hoc_obj_ref(efun_py_arg_);
121  vec_py_save_ = vector_new2(static_cast<IvocVect*>(efun_py_arg_->u.this_pointer));
122  nvar_ = vector_capacity(static_cast<IvocVect*>(vec_py_save_));
123  px = vector_vec(static_cast<IvocVect*>(vec_py_save_));
124  } else {
125  nvar_ = (int) chkarg(1, 0., 1e6);
126  efun_sym_ = hoc_lookup(gargstr(2));
127  if (!efun_sym_ || (efun_sym_->type != FUNCTION && efun_sym_->type != FUN_BLTIN)) {
128  hoc_execerror(gargstr(2), "not a function name");
129  }
130 
131  if (!hoc_is_pdouble_arg(3)) {
132  IvocVect* vec = vector_arg(3);
133  if (vector_capacity(vec) != nvar_) {
134  hoc_execerror("first arg not equal to size of Vector", 0);
135  }
136  px = vector_vec(vec);
137  } else {
138  px = hoc_pgetarg(3);
139  }
140  }
141  minarg_ = (double*) ecalloc(nvar_, sizeof(double));
142 
143  if (maxstepsize == 0.) {
144  hoc_execerror("call attr_praxis first to set attributes", 0);
145  }
146  machep = 1e-15;
147 
148  if (ifarg(4)) {
149  after_quad = gargstr(4);
150  } else {
151  after_quad = (char*) 0;
152  }
153 
154  /* save the values set by earlier invocation */
155  minerrsav = minerr;
156  minargsav = minarg;
157  tolerancesav = tolerance;
158  maxstepsizesav = maxstepsize;
159  printmodesav = printmode;
160  efun_sym_sav = hoc_efun_sym;
161  efun_py_save = efun_py;
162  efun_py_arg_save = efun_py_arg;
163  vec_py_save_save = vec_py_save;
164 
165 
166  /* copy this invocation values to the statics */
167  minerr = minerr_;
168  minarg = minarg_;
169  nvar = nvar_;
170  hoc_efun_sym = efun_sym_;
171  efun_py = efun_py_;
172  efun_py_arg = efun_py_arg_;
173  vec_py_save = vec_py_save_;
174 
175 
176  minerr = 1e9;
177  err = praxis(&tolerance, &machep, &maxstepsize, nvar, &printmode, px, efun, &fmin, after_quad);
178  err = minerr;
179  if (minerr < 1e9) {
180  for (i = 0; i < nvar; ++i) {
181  px[i] = minarg[i];
182  }
183  }
184 
185  /* restore the values set by earlier invocation */
186  minerr = minerrsav;
187  minarg = minargsav;
188  tolerance = tolerancesav;
189  maxstepsize = maxstepsizesav;
190  printmode = printmodesav;
191  nvar = nvar_; /* in case one calls prax_pval */
192  hoc_efun_sym = efun_sym_sav;
193  efun_py = efun_py_save;
194  efun_py_arg = efun_py_arg_save;
195  vec_py_save = vec_py_save_save;
196 
197  if (efun_py_) {
198  double* px = vector_vec(static_cast<IvocVect*>(efun_py_arg_->u.this_pointer));
199  for (i = 0; i < nvar_; ++i) {
200  px[i] = minarg_[i];
201  }
202  hoc_obj_unref(efun_py_);
203  hoc_obj_unref(efun_py_arg_);
204  vector_delete(static_cast<IvocVect*>(vec_py_save_));
205  }
206  if (minarg_) {
207  free(minarg_);
208  }
209  hoc_retpushx(err);
210 }
211 
212 void hoc_after_prax_quad(char* s) {
213  efun(minarg, nvar);
215 }
216 
217 void attr_praxis(void) {
218  if (ifarg(2)) {
219  tolerance = *getarg(1);
220  maxstepsize = *getarg(2);
221  printmode = (int) chkarg(3, 0., 3.);
222  hoc_retpushx(0.);
223  } else {
224  int old = nrn_praxis_ran_index;
225  if (ifarg(1)) {
226  nrn_praxis_ran_index = (int) chkarg(1, 0., 1e9);
227  }
228  hoc_retpushx((double) old);
229  }
230 }
231 
232 void pval_praxis(void) {
233  int i;
234  i = (int) chkarg(1, 0., (double) (nvar - 1));
235  if (ifarg(2)) {
236  int j;
237  double *p1, *p2;
238  p1 = praxis_paxis(i);
239  if (!hoc_is_pdouble_arg(2)) {
240  IvocVect* vec = vector_arg(2);
241  vector_resize(vec, nvar);
242  p2 = vector_vec(vec);
243  } else {
244  p2 = hoc_pgetarg(2);
245  }
246  for (j = 0; j < nvar; ++j) {
247  p2[j] = p1[j];
248  }
249  }
250  hoc_retpushx(praxis_pval(i));
251 }
252 
253 static double efun(double* v, long int n) {
254  int i;
255  double err;
256  if (efun_py) {
257  double* px = vector_vec(static_cast<IvocVect*>(efun_py_arg->u.this_pointer));
258  for (i = 0; i < n; ++i) {
259  px[i] = v[i];
260  }
262  for (i = 0; i < n; ++i) {
263  v[i] = px[i];
264  }
265  } else {
266  hoc_pushx((double) n);
267  hoc_pushpx(v);
268  err = hoc_call_func(hoc_efun_sym, 2);
269  }
270  if (!stoprun && err < minerr) {
271  minerr = err;
272  for (i = 0; i < n; ++i) {
273  minarg[i] = v[i];
274  }
275  }
276  return err;
277 }
char * gargstr(int narg)
Definition: code2.cpp:227
#define v
Definition: md1redef.h:11
#define i
Definition: md1redef.h:19
int hoc_is_object_arg(int narg)
Definition: code.cpp:876
double hoc_call_func(Symbol *s, int narg)
Definition: code.cpp:1477
void vector_resize(IvocVect *v, int n)
Definition: ivocvect.cpp:302
void hoc_pushpx(double *d)
Definition: code.cpp:834
void hoc_retpushx(double x)
Definition: hocusr.cpp:154
IvocVect * vector_arg(int i)
Definition: ivocvect.cpp:265
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1844
Object ** vector_pobj(IvocVect *v)
Definition: ivocvect.cpp:296
double * hoc_pgetarg(int narg)
Definition: oc_ansi.h:253
Symbol * hoc_lookup(const char *)
Definition: symbol.cpp:59
int hoc_is_pdouble_arg(int narg)
Definition: code.cpp:868
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1881
#define assert(ex)
Definition: hocassrt.h:24
#define getarg
Definition: hocdec.h:17
void stop_praxis(void)
Definition: hocprax.cpp:65
Object ** hoc_objgetarg(int)
Definition: code.cpp:1614
static long int printmode
Definition: hocprax.cpp:55
double chkarg(int, double, double)
Definition: code2.cpp:626
static Object * efun_py
Definition: hocprax.cpp:61
void attr_praxis(void)
Definition: hocprax.cpp:217
static Object * efun_py_arg
Definition: hocprax.cpp:62
void hoc_after_prax_quad(char *s)
Definition: hocprax.cpp:212
int nrn_praxis_ran_index
void vector_delete(IvocVect *vec)
Definition: ivocvect.cpp:262
static double efun(double *, long int)
Definition: hocprax.cpp:253
static double minerr
Definition: hocprax.cpp:75
static double * minarg
Definition: hocprax.cpp:75
static double tolerance
Definition: hocprax.cpp:54
void fit_praxis(void)
Definition: hocprax.cpp:77
static double machep
Definition: hocprax.cpp:54
IvocVect * vector_new2(IvocVect *vec)
Definition: ivocvect.cpp:293
static double maxstepsize
Definition: hocprax.cpp:54
void pval_praxis(void)
Definition: hocprax.cpp:232
static Symbol * hoc_efun_sym
Definition: hocprax.cpp:52
static long int nvar
Definition: hocprax.cpp:59
static void * vec_py_save
Definition: hocprax.cpp:63
Object * hoc_thisobject
Definition: hoc_oop.cpp:121
int hoc_obj_run(const char *, Object *)
Definition: hoc_oop.cpp:315
void hoc_pushx(double)
Definition: code.cpp:779
double * vector_vec(IvocVect *v)
Definition: ivocvect.cpp:19
bool stoprun
Definition: nrnoc_aux.cpp:19
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
void * ecalloc(size_t n, size_t size)
Definition: nrnoc_aux.cpp:85
int vector_capacity(IvocVect *v)
Definition: ivocvect.cpp:16
impl_ptrs methods
Collection of pointers to functions with python-version-specific implementations.
Definition: nrnpy.cpp:21
int const size_t const size_t n
Definition: nrngsl.h:10
#define FUNCTION(a, b)
Definition: nrngsl.h:5
size_t j
s
Definition: multisend.cpp:521
int ifarg(int)
Definition: code.cpp:1607
static double praxis_efun(Object *ho, Object *v)
Definition: nrnpy_p2h.cpp:318
#define NULL
Definition: spdefs.h:105
Definition: hocdec.h:173
void * this_pointer
Definition: hocdec.h:178
union Object::@47 u
Definition: model.h:47
short type
Definition: model.h:48
double(* praxis_efun)(Object *pycallable, Object *hvec)
Definition: nrnpy.h:50