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 "parse.hpp"
42 
43 #if defined(__cplusplus)
44 extern "C" {
45 #endif
46 
47 extern double praxis(double* t0,
48  double* machep,
49  double* h0,
50  long int nval,
51  long int* prin,
52  double* x,
53  double (*f)(double*, long int),
54  double* fmin,
55  char* after_quad);
56 extern double praxis_pval(int), *praxis_paxis(int);
57 extern int praxis_stop(int);
58 
59 #if defined(__cplusplus)
60 }
61 #endif
62 
63 extern int stoprun;
64 extern double chkarg(int, double, double);
65 
66 extern void vector_resize(IvocVect*, int);
67 extern double* vector_vec(IvocVect*);
68 extern IvocVect* vector_arg(int); // TODO: IvocVect?
70 extern void vector_delete(IvocVect* vec);
73 extern int nrn_praxis_ran_index;
74 extern Object** hoc_objgetarg(int);
75 
76 static double efun(double*, long int);
78 
79 static double tolerance, machep, maxstepsize;
80 static long int printmode;
81 /* for prax_pval to know the proper size, following has to be the value
82 at return of previous prax call
83 */
84 static long int nvar;
85 
86 double (*nrnpy_praxis_efun)(Object* pycallable, Object* hvec);
87 static Object* efun_py;
89 static void* vec_py_save;
90 
91 void stop_praxis(void) {
92  int i = 1;
93  if (ifarg(1)) {
94  i = (int) chkarg(1, 0., 1e5);
95  }
96  i = praxis_stop(i);
97  hoc_retpushx((double) i);
98 }
99 
100 /* want to get best result if user does a stoprun */
101 static double minerr, *minarg; /* too bad this is not recursive */
102 
103 void fit_praxis(void) {
104  char* after_quad;
105  int i;
106  double err, fmin;
107  double* px;
108  /* allow nested calls to fit_praxis. I.e. store all the needed
109  statics specific to this invocation with proper reference
110  counting and then unref/destoy on exit from this invocation.
111  Before the prax call save the statics from earlier invocation
112  without increasing the
113  ref count and on exit restore without decreasing the ref count.
114  */
115 
116  /* save before setting statics, restore after prax */
117  double minerrsav, *minargsav, maxstepsizesav, tolerancesav;
118  long int printmodesav, nvarsav;
119  Symbol* efun_sym_sav;
120  Object *efun_py_save, *efun_py_arg_save;
121  void* vec_py_save_save;
122 
123  /* store statics specified by this invocation */
124  /* will be copied just before calling prax */
125  double minerr_, *minarg_;
126  long int nvar_;
127  Symbol* efun_sym_;
128  Object *efun_py_, *efun_py_arg_;
129  void* vec_py_save_;
130 
131  minerr_ = 0.0;
132  nvar_ = 0;
133  minarg_ = NULL;
134  efun_sym_ = NULL;
135  efun_py_ = NULL;
136  efun_py_arg_ = NULL;
137  vec_py_save_ = NULL;
138 
139  fmin = 0.;
140 
141  if (hoc_is_object_arg(1)) {
143  efun_py_ = *hoc_objgetarg(1);
144  hoc_obj_ref(efun_py_);
145  efun_py_arg_ = *vector_pobj(vector_arg(2));
146  hoc_obj_ref(efun_py_arg_);
147  vec_py_save_ = vector_new2(static_cast<IvocVect*>(efun_py_arg_->u.this_pointer));
148  nvar_ = vector_capacity(static_cast<IvocVect*>(vec_py_save_));
149  px = vector_vec(static_cast<IvocVect*>(vec_py_save_));
150  } else {
151  nvar_ = (int) chkarg(1, 0., 1e6);
152  efun_sym_ = hoc_lookup(gargstr(2));
153  if (!efun_sym_ || (efun_sym_->type != FUNCTION && efun_sym_->type != FUN_BLTIN)) {
154  hoc_execerror(gargstr(2), "not a function name");
155  }
156 
157  if (!hoc_is_pdouble_arg(3)) {
158  IvocVect* vec = vector_arg(3);
159  if (vector_capacity(vec) != nvar_) {
160  hoc_execerror("first arg not equal to size of Vector", 0);
161  }
162  px = vector_vec(vec);
163  } else {
164  px = hoc_pgetarg(3);
165  }
166  }
167  minarg_ = (double*) ecalloc(nvar_, sizeof(double));
168 
169  if (maxstepsize == 0.) {
170  hoc_execerror("call attr_praxis first to set attributes", 0);
171  }
172  machep = 1e-15;
173 
174  if (ifarg(4)) {
175  after_quad = gargstr(4);
176  } else {
177  after_quad = (char*) 0;
178  }
179 
180  /* save the values set by earlier invocation */
181  minerrsav = minerr;
182  minargsav = minarg;
183  tolerancesav = tolerance;
184  maxstepsizesav = maxstepsize;
185  printmodesav = printmode;
186  nvarsav = nvar;
187  efun_sym_sav = hoc_efun_sym;
188  efun_py_save = efun_py;
189  efun_py_arg_save = efun_py_arg;
190  vec_py_save_save = vec_py_save;
191 
192 
193  /* copy this invocation values to the statics */
194  minerr = minerr_;
195  minarg = minarg_;
196  nvar = nvar_;
197  hoc_efun_sym = efun_sym_;
198  efun_py = efun_py_;
199  efun_py_arg = efun_py_arg_;
200  vec_py_save = vec_py_save_;
201 
202 
203  minerr = 1e9;
204  err = praxis(&tolerance, &machep, &maxstepsize, nvar, &printmode, px, efun, &fmin, after_quad);
205  err = minerr;
206  if (minerr < 1e9) {
207  for (i = 0; i < nvar; ++i) {
208  px[i] = minarg[i];
209  }
210  }
211 
212  /* restore the values set by earlier invocation */
213  minerr = minerrsav;
214  minarg = minargsav;
215  tolerance = tolerancesav;
216  maxstepsize = maxstepsizesav;
217  printmode = printmodesav;
218  nvar = nvar_; /* in case one calls prax_pval */
219  hoc_efun_sym = efun_sym_sav;
220  efun_py = efun_py_save;
221  efun_py_arg = efun_py_arg_save;
222  vec_py_save = vec_py_save_save;
223 
224  if (efun_py_) {
225  double* px = vector_vec(static_cast<IvocVect*>(efun_py_arg_->u.this_pointer));
226  for (i = 0; i < nvar_; ++i) {
227  px[i] = minarg_[i];
228  }
229  hoc_obj_unref(efun_py_);
230  hoc_obj_unref(efun_py_arg_);
231  vector_delete(static_cast<IvocVect*>(vec_py_save_));
232  }
233  if (minarg_) {
234  free(minarg_);
235  }
236  hoc_retpushx(err);
237 }
238 
239 extern "C" void hoc_after_prax_quad(char* s) {
240  efun(minarg, nvar);
242 }
243 
244 void attr_praxis(void) {
245  if (ifarg(2)) {
246  tolerance = *getarg(1);
247  maxstepsize = *getarg(2);
248  printmode = (int) chkarg(3, 0., 3.);
249  hoc_retpushx(0.);
250  } else {
251  int old = nrn_praxis_ran_index;
252  if (ifarg(1)) {
253  nrn_praxis_ran_index = (int) chkarg(1, 0., 1e9);
254  }
255  hoc_retpushx((double) old);
256  }
257 }
258 
259 void pval_praxis(void) {
260  int i;
261  i = (int) chkarg(1, 0., (double) (nvar - 1));
262  if (ifarg(2)) {
263  int j;
264  double *p1, *p2;
265  p1 = praxis_paxis(i);
266  if (!hoc_is_pdouble_arg(2)) {
267  IvocVect* vec = vector_arg(2);
268  vector_resize(vec, nvar);
269  p2 = vector_vec(vec);
270  } else {
271  p2 = hoc_pgetarg(2);
272  }
273  for (j = 0; j < nvar; ++j) {
274  p2[j] = p1[j];
275  }
276  }
278 }
279 
280 static double efun(double* v, long int n) {
281  int i;
282  double err;
283  if (efun_py) {
284  double* px = vector_vec(static_cast<IvocVect*>(efun_py_arg->u.this_pointer));
285  for (i = 0; i < n; ++i) {
286  px[i] = v[i];
287  }
289  for (i = 0; i < n; ++i) {
290  v[i] = px[i];
291  }
292  } else {
293  int i;
294  hoc_pushx((double) n);
295  hoc_pushpx(v);
296  err = hoc_call_func(hoc_efun_sym, 2);
297  }
298  if (!stoprun && err < minerr) {
299  minerr = err;
300  for (i = 0; i < n; ++i) {
301  minarg[i] = v[i];
302  }
303  }
304  return err;
305 }
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
int hoc_is_object_arg(int narg)
Definition: code.cpp:756
double hoc_call_func(Symbol *s, int narg)
Definition: code.cpp:1462
void hoc_pushpx(double *d)
Definition: code.cpp:716
void hoc_retpushx(double x)
Definition: hocusr.cpp:154
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1810
Symbol * hoc_lookup(const char *)
int hoc_is_pdouble_arg(int narg)
Definition: code.cpp:748
double * hoc_pgetarg(int narg)
Definition: code.cpp:1623
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1828
#define assert(ex)
Definition: hocassrt.h:32
void * ecalloc(size_t n, size_t size)
Definition: symbol.cpp:215
#define getarg
Definition: hocdec.h:15
#define gargstr
Definition: hocdec.h:14
int vector_capacity(IvocVect *)
double(* nrnpy_praxis_efun)(Object *pycallable, Object *hvec)
Definition: hocprax.cpp:86
int stoprun
Definition: fadvance.cpp:166
void stop_praxis(void)
Definition: hocprax.cpp:91
Object ** hoc_objgetarg(int)
Definition: code.cpp:1587
static long int printmode
Definition: hocprax.cpp:80
int praxis_stop(int)
void vector_resize(IvocVect *, int)
double chkarg(int, double, double)
Definition: code2.cpp:638
static Object * efun_py
Definition: hocprax.cpp:87
void attr_praxis(void)
Definition: hocprax.cpp:244
double * praxis_paxis(int)
static Object * efun_py_arg
Definition: hocprax.cpp:88
void hoc_after_prax_quad(char *s)
Definition: hocprax.cpp:239
int nrn_praxis_ran_index
double * vector_vec(IvocVect *)
void vector_delete(IvocVect *vec)
static double efun(double *, long int)
Definition: hocprax.cpp:280
static double minerr
Definition: hocprax.cpp:101
static double * minarg
Definition: hocprax.cpp:101
static double tolerance
Definition: hocprax.cpp:79
void fit_praxis(void)
Definition: hocprax.cpp:103
static double machep
Definition: hocprax.cpp:79
IvocVect * vector_arg(int)
Definition: ivocvect.cpp:397
IvocVect * vector_new2(IvocVect *vec)
static double maxstepsize
Definition: hocprax.cpp:79
Object ** vector_pobj(IvocVect *v)
void pval_praxis(void)
Definition: hocprax.cpp:259
static Symbol * hoc_efun_sym
Definition: hocprax.cpp:77
static long int nvar
Definition: hocprax.cpp:84
static void * vec_py_save
Definition: hocprax.cpp:89
double praxis_pval(int)
double praxis(double *t0, double *machep, double *h0, long int nval, long int *prin, double *x, double(*f)(double *, long int), double *fmin, char *after_quad)
int hoc_obj_run(const char *, Object *)
Definition: hoc_oop.cpp:322
int ifarg(int)
Definition: code.cpp:1581
void hoc_pushx(double)
Object * hoc_thisobject
Definition: hoc_oop.cpp:122
#define v
Definition: md1redef.h:4
#define i
Definition: md1redef.h:12
int const size_t const size_t n
Definition: nrngsl.h:11
#define FUNCTION(a, b)
Definition: nrngsl.h:6
size_t j
#define e
Definition: passive0.cpp:22
#define NULL
Definition: sptree.h:16
Definition: hocdec.h:227
void * this_pointer
Definition: hocdec.h:232
union Object::@39 u
Definition: model.h:57
short type
Definition: model.h:58