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