-
Notifications
You must be signed in to change notification settings - Fork 2
/
optimization.h
769 lines (746 loc) · 37.9 KB
/
optimization.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
/*
* optimization.h
*
* Copyright 2021-2022 Luka Marohnić
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __OPTIMIZATION_H
#define __OPTIMIZATION_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "first.h"
#include "gen.h"
#include "unary.h"
#include <set>
#include <stack>
#include <sstream>
#ifdef HAVE_LIBGSL
#include <gsl/gsl_multimin.h>
#include <gsl/gsl_siman.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_bspline.h>
#include <gsl/gsl_multifit.h>
#endif
#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC
#define GOLDEN_RATIO 1.61803398875 // used in golden-ratio search method
enum critical_point_classification {
_CPCLASS_UNDECIDED = 0,
_CPCLASS_MIN = 1,
_CPCLASS_MAX = 2,
_CPCLASS_POSSIBLE_MIN = 3,
_CPCLASS_POSSIBLE_MAX = 4,
_CPCLASS_SADDLE = 5
};
enum kernel_density_estimation_method {
_KDE_METHOD_EXACT,
_KDE_METHOD_PIECEWISE,
_KDE_METHOD_LIST
};
enum bandwidth_selection_method {
_KDE_BW_METHOD_DPI,
_KDE_BW_METHOD_ROT
};
enum bvp_output_type {
_BVP_LIST,
_BVP_DIFF,
_BVP_PIECEWISE,
_BVP_SPLINE
};
enum hclust_linkage_type {
_SINGLE_LINKAGE = 1,
_AVERAGE_LINKAGE = 2,
_COMPLETE_LINKAGE = 3,
_WEIGHTED_LINKAGE = 4,
_WARD_LINKAGE = 5,
_MEDIAN_LINKAGE = 6,
_CENTROID_LINKAGE = 7
};
enum hclust_index_function {
_SILHOUETTE_INDEX = 1,
_MCCLAIN_RAO_INDEX = 2,
_DUNN_INDEX = 4,
_ALL_HCLUST_INDICES = 7
};
enum clustering_indices {
_HARTIGAN_CRITERION = 0,
_BANFELD_RAFTERY_INDEX = 1, // min
_DAVIES_BOULDIN_INDEX = 2, // min
_RAY_TURI_INDEX = 4, // min
_SCOTT_SYMONS_INDEX = 8, // min
_CALINSKI_HARABASZ_INDEX = 16, // max
_PBM_INDEX = 32, // max
_RATKOWSKY_LANCE_INDEX = 64, // max
_DET_RATIO_INDEX = 128, // min diff
_LOG_DET_RATIO_INDEX = 256, // min diff
_LOG_SS_RATIO_INDEX = 512, // min diff
_KSQ_DETW_INDEX = 1024, // max diff
_BALL_HALL_INDEX = 2048, // max diff
_TRACE_W_INDEX = 4096, // max diff
_TRACE_WIB_INDEX = 8192, // max diff
_ALL_CLUSTER_INDICES = 16383
};
enum nlp_method {
_NLP_AUTOMATIC = 1,
_NLP_INTERIOR_POINT = 2,
_NLP_NELDER_MEAD = 3,
_NLP_DIFFERENTIAL_EVOLUTION = 4,
_NLP_COBYLA = 5
};
enum nlp_solution_status {
_NLP_OPTIMAL,
_NLP_FAILED,
_NLP_INFEAS,
_NLP_UNBOUNDED,
_NLP_ERROR,
_NLP_PENDING
};
class ipdiff {
/* IPDIFF CLASS (Implicit Partial DIFFerentiation)
* This class is used for implicit differentiation of f with respect to g=0.
* Here, f:R^(n+m)->R, g:R^(n+m)->R^m with rank(g')=m and J(x)=f(x,h(x)) where x in R^n and h is
* the implicit function guaranteed to exist (in a neighborhood of some point x0) by the
* Implicit Function Theorem if rank(g')=m. Function J may now be differentiated wrt x1,x2,...,xn. */
public:
typedef std::vector<int> ivector;
typedef ivector::const_iterator ivector_iter;
typedef std::vector<ivector> ivectors;
typedef std::map<ivector,int> ivector_map;
typedef std::pair<ivector,ivector_map> diffterm;
typedef std::map<diffterm,int> diffterms;
typedef std::map<ivector,gen> pd_map;
private:
vecteur vars; // list of variables [x1,x2,..,xn,y1,y2,..,ym] where x are free and y are dependent
gen f; // the expression f(x1,x2,..,xn,y1,y2,..,ym)
vecteur g; // list [g1,g2,..,gm], it is assumed that gj(x1,x2,..,xn,y1,y2,..,ym)=0 for all j=1,2,..,m
const context *ctx; // giac context
pd_map pdv; // partial derivatives of J
pd_map pdf; // partial derivatives of f
pd_map pdg; // partial derivatives of g
pd_map pdh; // partial derivatives of h
std::map<ivector,diffterms> cterms;
int ord; // the maximal order of the currently computed partial derivatives of h
int nvars; // the number of free variables
int nconstr; // the number of constraints = the number of dependent variables
diffterms derive_diffterms(const diffterms &terms,ivector &sig);
void find_nearest_terms(const ivector &sig,diffterms &match,ivector &excess);
const gen &differentiate(const gen &e,pd_map &pds,const ivector &sig);
void compute_h(const std::vector<diffterms> &grv,int order);
void compute_pd(int order,const ivector &sig=ivector(0));
void raise_order(int order); // compute the missing partial derivatives of h
const gen &get_pd(const pd_map &pds,const ivector &sig) const;
public:
/* construct the ipdiff instance for function f_orig(vars_orig) subject to
* the constraints in g_orig, the Jacobian of g_orig must have maximal rank */
ipdiff(const gen &f_orig,const vecteur &g_orig,const vecteur &vars_orig,GIAC_CONTEXT);
/* return the partial derivative of J represented by sig */
const gen &derivative(const ivector &sig);
/* return the partial derivative of J with respect to the variables in dvars */
const gen &derivative(const vecteur &dvars);
/* store all partial derivatives of the specified order to pd_map */
void partial_derivatives(int order,pd_map &pdmap);
/* return 1/k!*(sum(i=1)^n (xi-ai)*d/dxi)^k f(x)|a */
gen taylor_term(const vecteur &a,int k,bool shift=true);
/* return the Taylor polynomial, with the specified order, of J in the vicinity of a */
gen taylor(const vecteur &a,int order);
/* store grad(J) as vector res */
void gradient(vecteur &res);
/* store Hessian(J) as matrix res */
void hessian(matrice &res);
/* generate all partitions of m into n terms and store them to vector c */
static void ipartition(int m,int n,ivectors &c,const ivector &p=ivector(0));
/* return the sum the elements of a vector v of integers, ignore the last element if drop_last=true */
static int sum_ivector(const ivector &v,bool drop_last=false);
};
class tprob {
/* TPROB CLASS (Transportation PROBlem)
* The class implementing the MODI method for balanced TP with degeneracy handling */
public:
typedef std::pair<int,int> ipair;
typedef std::vector<ipair> ipairs;
private:
const context *ctx;
vecteur demand;
vecteur supply;
gen eps; // epsilon
gen M; // symbol for marking forbidden routes in cost matrix
void north_west_corner(matrice &feas);
ipairs stepping_stone_path(ipairs &path_orig,const matrice &X);
void modi(const matrice &P_orig,matrice &X);
public:
/* construct the TP with supply s and demand d, m marks forbidden routes */
tprob(const vecteur &s,const vecteur &d,const gen &m,GIAC_CONTEXT);
/* solve the transportation problem with the given cost matrix, output in sol */
void solve(const matrice &cost_matrix,matrice &sol);
};
bool is_mcint(const gen &g,int v=-1);
vecteur sort_identifiers(const vecteur &v,GIAC_CONTEXT);
std::vector<int> linearly_dependent_rows(const matrice &m,GIAC_CONTEXT);
bool is_cubic_wrt(const gen &g,const gen &x,gen &a,gen &b,gen &c,gen &d,GIAC_CONTEXT);
bool is_quartic_wrt(const gen &g,const gen &x,gen &a,gen &b,gen &c,gen &d,gen &e,GIAC_CONTEXT);
bool is_definitely_positive(const gen &g,GIAC_CONTEXT);
bool is_positive_definite(const vecteur &mat,int isnum,GIAC_CONTEXT);
bool is_positive_definite_inplace(vecteur &m,bool isnum,GIAC_CONTEXT);
bool is_positive_semidefinite(const matrice &mat,double time_limit,unsigned max_taille,GIAC_CONTEXT);
matrice madd(const matrice &a,const matrice &b);
void madd_inplace(matrice &a,const matrice &b,bool subt=false);
matrice msub(const matrice &a,const matrice &b);
void msub_inplace(matrice &a,const matrice &b);
matrice mscale(const gen &a,const matrice &b);
void mscale_inplace(const gen &a,matrice &b);
void copy_matrice(const matrice &src,matrice &dest);
bool is_string_list(const gen &g);
vecteur data2list(const gen &g,GIAC_CONTEXT);
gen find_minimum(const gen &f,const gen &a,const gen &b,bool global,double eps,int maxiter,GIAC_CONTEXT);
void sortperm(const vecteur &v,std::vector<int> &p,GIAC_CONTEXT);
int argmin(const vecteur &v,GIAC_CONTEXT);
int argmax(const vecteur &v,GIAC_CONTEXT);
int kmeans(const matrice &data,int &k,int min_k,int &max_k,int maxiter,std::vector<int> &res,vecteur *cc,matrice *ind,GIAC_CONTEXT);
void remove_elements_with_indices(vecteur &v,const set<int> &ind);
void remove_elements_with_indices(vecteur &v,const set<pair<int,gen> > &ind);
gen to_algebraic(const gen &g,vecteur &S,GIAC_CONTEXT);
bool is_algebraic(const gen &g,GIAC_CONTEXT);
extern bool is_positive_safe(const gen &g,bool strict,unsigned max_taille,GIAC_CONTEXT);
class nlp_problem {
gen obj,best_obj_val,obj_shift;
int _fevalc; // objective function evaluation counter
matrice bd_rect;
vecteur vars,obj_vars,bnd_vars;
// problem data
vecteur lb,ub,pc_lo,pc_lo_count,pc_hi,pc_hi_count;
vecteur eq_cons,ineq_cons;
vecteur obj_gradient,obj_hessian;
matrice eq_jacobian,ineq_jacobian;
// internal data
matrice saved_points;
matrice nm_simplex; // simplex vertices in Nelder-Mead
matrice nm_yarr; // objective function vaues at simplex vertices
double nm_alpha,nm_beta,nm_gamma,nm_delta;
vecteur initp_sigma;
vecteur cclust_centers,cclust_sizes,cclust_freqs;
vecteur iteration_data;
vecteur penalty_eq,penalty_ineq; // adaptive penalty factors
vecteur initp;
const_iterateur initp_iter; // initial-point iterator
const context *ctx;
int _msg_level; // 0 - quiet, 1 - errors, 2 - errors/warnings, 3 - all output
bool _smooth_obj,_convex_obj,_smooth_constr,_convex_constr,_have_hessian;
bool _linconstr,_linobj;
bool _presolved,_initialized;
bool _has_initial_rect;
bool _compact;
bool _infeas;
bool _iter_data;
bool _debug;
int _penalty_scheme; // 0 - no penalty, 1 - Lagrangian, 2 - multiplicative (see Lampinen & Zelinka, 2000)
int _iter_count;
int _base_vertex_index;
int _spc;
vector<bool> _is_intvar;
set<pair<int,gen> > _fixed_vars;
set<int> _inactive_eq_indices,_inactive_ineq_indices;
stringstream _ss;
vector<int> _sol_stat;
class fxvars {
void assign(const fxvars &other) { n_oldvars=other.n_oldvars; indices=other.indices; names=other.names; values=other.values; }
public:
int n_oldvars;
std::vector<int> indices;
vecteur names;
vecteur values;
fxvars(int nov) { n_oldvars=nov; }
fxvars(const fxvars &other) { assign(other); }
fxvars &operator=(const fxvars &other) { assign(other); return *this; }
};
std::stack<fxvars> fx_subs;
class lineq {
void assign(const lineq &other) { lvars=other.lvars; nlvars=other.nlvars; index=other.index; e=other.e; }
public:
std::vector<int> lvars;
std::vector<int> nlvars;
int index;
gen e;
lineq(const gen &g,int i) { e=g; index=i; }
lineq(const lineq &other) { assign(other); }
lineq &operator=(const lineq &other) { assign(other); return *this; }
};
static std::pair<int,int> make_leqv_sys(const std::vector<int> &ind,const std::vector<lineq> &leqv);
bool eliminate_equalities(const std::vector<lineq> &leqv,vecteur &lsol,vecteur &leq_vars);
bool subs_fxvars(const fxvars &fv);
public:
typedef struct optimum {
int res;
vecteur x;
gen f;
optimum();
} optimum_t;
typedef std::vector<optimum_t> optima_t;
struct meth_parm {
double eps; // optimality tolerance
double tol; // feasibility tolerance
gen penalty; // penalty factors/exponents for constraints (PENALTY[i] corresponds to the i-th constraint)
double scale; // scaling factor for differential evolution (DE)
double cross_prob; // cross-probability for mutation in DE
double reflect_ratio; // ratio used for point reflection in Nelder-Mead (NM)
double expand_ratio; // ratio used for polytope expansion in NM
double contract_ratio; // ratio used for polytope contraction in NM
double shrink_ratio; // ratio used for polytope shrinking in NM
double size; // initial simplex size for NM
double step; // step-size for NM and BFGS
int search_points; // number of starting points, used in multistart and DE
int max_iter; // maximum number of iterations
int msg_level; // filtering messages
bool presolve; // whether to presolve the problem first
bool postprocess; // whether to refine global solution using local methods
int convex; // is this a convex problem? (saves the time required for checking)
int cluster; // number of clusters of initial points (set to 1 for automatic clustering)
bool border; // setting this to false disables automatic bound finding (default: true)
void init_defaults(double eps);
};
class ipt_solver {
/* this class implements interior-point method for solving: min f(x) s.t. c(x)=0, x>=0
* SOURCE: Waechter & Biegler, 2004 */
// fixed internal parameters
double kappa_eps; // positive
double kappa_mu; // in (0,1)
double kappa_Sigma; // >= 1
double kappa_soc; // in (0,1)
double kappa_1; // positive
double tau_min; // positive
double theta_mu; // in (1,2)
gen theta_min; // positive
gen theta_max; // positive
double delta; // positive
double s_max; // positive
double s_theta; // > 1
double s_phi; // > 1
double eta_phi; // in (0,1/2)
double gamma_alpha; // in (0,1]
double gamma_theta; // in (0,1)
double gamma_phi; // in (0,1)
int p_max; // positive
double bardelta_w_min; // positive
double bardelta_w_0; // > bardelta_w_min
double bardelta_w_max; // > bardelta_w_0
double bardelta_c; // positive
double kappa_w_minus; // in (0,1)
double kappa_w_plus; // > 1
double barkappa_w_plus; // > kappa_w_plus
double kappa_c; // positive
double kappa_resto; // positive
double lambda_max; // positive
// other parameters
double eps_tol,feas_tol;
int maxiter;
double delta_w,delta_w_last,delta_c;
double mu_j,tau_j;
#ifdef HAVE_LIBLAPACK
double *factorization,*lapack_work,*lapack_rhs;
int *lapack_ipiv;
#else
matrice factorization;
vecteur ldl_perm;
#endif
gen f,mu,theta_k,theta_resto,phi_k;
std::set<int> dup_ind;
const context *ctx;
nlp_problem &prob;
int nvars,ncons,nslacks;
vecteur c,grad_f,hess_f;
matrice A; // transposed Jacobian of constraints
vecteur x,x_subs,lambda,z;
matrice kkt_mat;
vecteur kkt_rhs,sigma;
matrice F; // filter
bool initialized;
char buf[256];
vecteur iteration_data;
vecteur pprod(const vecteur &vec1,const vecteur &vec2) { return *_pointprod(makesequence(vec1,vec2),ctx)._VECTptr; }
gen linfn(const vecteur &v) { return _max(_abs(v,ctx),ctx); }
vecteur subs_vars(const vecteur &vec,const vecteur &x0,const vecteur &lambda0,const vecteur &z0,double muj=-1);
void compute_dz(const vecteur &x0,const vecteur &dx0,const vecteur &z0,vecteur &dz);
gen E(const gen &mu0,const vecteur &x0,const vecteur &lambda0,const vecteur &z0);
bool IC(const matrice &mat);
void init_filter();
void update_filter(const gen &b_theta,const gen &b_phi);
vecteur init_lambda(const vecteur &x0,const vecteur &z0);
void compute_np(const gen &mu0,const vecteur &x0,vecteur &n0,vecteur &p0) const;
gen constraint_violation(const vecteur &x0) const;
gen barrier_fval(const vecteur &x0) const;
bool filter_accepts(const gen &theta,const gen &phi) const;
bool kkt_init();
int feas_restoration(vecteur &x0,vecteur &lambda0,vecteur &z0,const gen &viol_old,gen &viol);
gen fraction_to_boundary(const vecteur &y,const vecteur &d_y);
int ls_filter_barrier_method(vecteur &x_k,vecteur &lambda_k,vecteur &z_k,double mu0);
void init_parameters();
bool solve_kkt(const matrice &mat,const vecteur &rh,vecteur &sol);
public:
ipt_solver(nlp_problem &p,const meth_parm &parm);
~ipt_solver();
/* Return TRUE if x0 is accepted by the currently active filter */
bool filter_accepts(const vecteur &x0) const { return filter_accepts(constraint_violation(x0),barrier_fval(x0)); }
/* run interior point method for each point in x0 (or in x0) and return results as list of pairs (retval,x) */
bool optimize(optima_t &res);
const vecteur &get_iteration_data() const { return iteration_data; }
vecteur x2vars(const vecteur &x0) const;
vecteur vars2x(const vecteur &x0,const vecteur &x0_orig=vecteur(0)) const;
};
private:
class region {
nlp_problem &prob;
vecteur x_lb,x_ub,c,dc,cx,sl,su;
std::vector<int> dir,kl,ku;
double ftol;
int n,m,maxiter;
const context *ctx;
const ipt_solver *ipt;
char buf[256];
void rs_heur(vecteur &x0) const;
bool mfeas(vecteur &x0,bool store);
gen bisection(const vecteur &x0,int i,const gen &a,const gen &b,int d);
bool strides(const vecteur &x0_orig,int i,int d,int lim,gen &a,gen &b);
bool find_bound(const vecteur &x0,int i,int d,gen &bnd);
public:
/* tol: feasibility tolerance, itlim: iteration limit for strides/bisection */
region(nlp_problem &p,double tol,int itlim);
/* attach/detach ipt solver for premature termination on filter acceptance */
void attach_ipt(const ipt_solver *ipts) { ipt=ipts; }
void detach_ipt() { ipt=NULL; }
/* make the point x0 feasible, returns TRUE if successful */
bool make_feasible(vecteur &x0) { return mfeas(x0,true); }
/* generate a feasible point, returns TRUE if successful */
bool generate_feasible_point(vecteur &x0) { rs_heur(x0); return make_feasible(x0); }
/* approximate the bounding hyperrectangle for this region, may return infinity bounds */
matrice bounding_rect();
};
region *feasible_region;
clock_t _start_time;
void err(const std::string &s,bool translate=true) const
{ if (_msg_level>0) *logptr(ctx) << gettext("Error") << ": " << (translate?gettext(s.c_str()):s.c_str()) << "\n"; }
void err() { err(_ss.str(),false); _ss.str(std::string()); }
void warn(const std::string &s,bool translate=true) const
{ if (_msg_level>1) *logptr(ctx) << gettext("Warning") << ": " << (translate?gettext(s.c_str()):s.c_str()) << "\n"; }
void warn() { warn(_ss.str(),false); _ss.str(std::string()); }
void msg(const std::string &s,bool translate=true) const
{ if (_msg_level>2) *logptr(ctx) << (translate?gettext(s.c_str()):s.c_str()) << "\n"; }
void msg() { msg(_ss.str(),false); _ss.str(std::string()); }
void debug(const std::string &s) const
{ if (!_debug) return; if (_iter_count>0) *logptr(ctx) << _iter_count << ": "; *logptr(ctx) << s << "\n"; }
void debug() { debug(_ss.str()); _ss.str(std::string()); }
gen make_label(const vecteur &pt,const std::string &str,int disp=0) {
return _legende(makesequence(_point(pt,ctx),string2gen(str,false),symb_equal(at_display,change_subtype(disp,_INT_COLOR))),ctx);
}
bool compute_obj_val(const vecteur &x_orig,gen &val,bool print_err=false);
bool subst_hessian(const vecteur &x0,matrice &H,bool full=true) const;
bool is_expression_convex(const vecteur &gradient,matrice &H,bool &hess_ok,bool lt);
bool clamp(vecteur &x0,bool rnd=false) const;
void make_bounded_vars(bool use_bd_rect);
void purge_bounded_vars() { if (!bnd_vars.empty()) _purge(change_subtype(bnd_vars,_SEQ__VECT),ctx); }
void remove_redundant_constraints();
void initialize(int method,const meth_parm &parm);
double initial_size(const meth_parm &parm,double lo=0.02,double hi=0.1) const;
bool initialize_simplex(const vecteur &x0,double size);
void initialize_penalties(const gen &p);
void randomize_ith_component(vecteur &x,int i,bool use_varbnds) const;
bool make_random_initial_point(vecteur &x,gen *fval=NULL,int nsamp=10,double sigma_scale=0.01);
bool restart(vecteur &x,gen *fval=NULL);
void save_point(const vecteur &pt) { if (initp.empty()) saved_points.push_back(pt); }
void clear_saved_points() { saved_points.clear(); }
bool preprocess(); // returns false if infeasibility was detected
void postprocess_point(gen &x0,const vecteur &oldvars,const fxvars &fx,vecteur &csol);
void postprocess(gen &x0); // post-process x0
void reset_timer() { _start_time=clock(); }
double elapsed_secs() { return double(clock()-_start_time)/CLOCKS_PER_SEC; }
int var_count() const { return (int)vars.size()-(int)_fixed_vars.size(); }
int eq_count() const { return (int)eq_cons.size()-(int)_inactive_eq_indices.size(); }
int ineq_count() const { return (int)ineq_cons.size()-(int)_inactive_ineq_indices.size(); }
int eval_count() const { return _fevalc; } // return the total number of objective function evaluations so far
void find_fixed_vars();
void insert_fixed_vars(vecteur &x) const;
gen subs_fixed_vars(const gen &g) const;
vecteur subs_fixed_vars(const vecteur &v) const;
bool find_inactive_eq(const vecteur &eq);
bool find_inactive_ineq(const vecteur &ineq);
vecteur constraints(bool incl_bnds=true,bool all_geq=false) const;
bool is_smooth() const { return _smooth_obj && _smooth_constr; }
bool is_convex() const { return _convex_obj && _convex_constr; }
bool is_unconstrained() const;
bool has_bounded_variables() const;
bool is_feasible(const vecteur &x,double feas_tol,bool check_bounds,set<int> *viol_eq=NULL,set<int> *viol_ineq=NULL,set<int> *viol_bnd=NULL) const;
gen INT(const gen &g) const { return _penalty_scheme==2?_trunc(g,ctx):g; }
bool is_intvar(int i) const { return _is_intvar[i]; }
bool has_intvars() const { return std::find(_is_intvar.begin(),_is_intvar.end(),true)!=_is_intvar.end(); }
int intvar_count() const;
bool is_intsol(const meth_parm &parm,const vecteur &sol) const;
bool is_intvars_all_binary() const;
int minimize_linear(const gen &o,const vecteur &c,vecteur &opt,gen &optval) const;
int nm_iteration(vecteur &best_point,gen &fval,double &ssize,const meth_parm &parm,bool no_gsl=false);
bool de_initialize(iterateur &it,const iterateur &itend,iterateur &kt,iterateur &ft,int &best_k);
bool cobyla(const vecteur &cons,const meth_parm &parm,optima_t &res);
bool differential_evolution(const meth_parm &parm,optimum_t &res);
bool nelder_mead(const meth_parm &parm,optima_t &res);
bool branch_and_bound(const meth_parm &parm,const vecteur &cont_sol,optimum_t &incumbent);
bool branch_var(const meth_parm &parm,const vecteur &sol,const gen &cost,int strategy,int &var);
bool bb_solve_subproblem(const meth_parm &parm,vecteur &active_nodes,gen &fval,optima_t &sub_res,optimum_t &incumbent);
void update_pseudocost(int var,vecteur &pc,vecteur &pc_count,const gen &df,const gen &dx);
bool outer_approximation(const meth_parm &parm,const vecteur &cont_sol,optimum_t &incumbent);
int var2intvar(int var) const;
void get_vars_and_values(const set<pair<int,gen> > &lst,vecteur &v,vecteur &w) const;
void find_best_solution(const meth_parm &parm,optima_t &res,vecteur &opt,gen &optval,int &ret);
#ifdef HAVE_LIBGSL
bool gsl_bfgs(const meth_parm &parm,optima_t &res);
static double gsl_my_f(const gsl_vector *x,void *params);
static void gsl_my_df(const gsl_vector *x,void *params,gsl_vector *df);
static void gsl_my_fdf(const gsl_vector *x,void *params,double *f,gsl_vector *df);
static double gsl_my_uf(double x,void *params);
gsl_multimin_fminimizer *nm_s;
#endif
public:
nlp_problem(const gen &f,const vecteur &g,const vecteur &x,GIAC_CONTEXT);
~nlp_problem();
void set_variable_bounds(const vecteur &L,const vecteur &U) { lb=L; ub=U; }
void set_integer_variable(int i) { _is_intvar[i]=true; }
void enable_debug_messages(bool yes) { _debug=yes; }
void collect_iteration_data(bool yes) { _iter_data=true; }
const vecteur &get_iteration_data() const { return iteration_data; }
int optimize(int method,const meth_parm &parm,const vecteur &ip,vecteur &opt,gen &optval);
/* solve lhs*X=rhs using LSQ and write the result in sol; return TRUE if successful and FALSE on error */
static bool solve_lsq(const matrice &lhs,const vecteur &rhs,vecteur &sol,GIAC_CONTEXT);
static bool ampl_load(const std::string &filename,vecteur &v,vecteur &o,vecteur &c,string &msg,GIAC_CONTEXT);
};
class cluster_crit {
const context *ctx;
const matrice &pts;
gen distf;
int N; // number of observations
int p; // number of variables
int K; // number of clusters
std::vector<int> _ci; // cluster indices for observations
std::vector<int> _n; // cluster sizes
std::map<std::pair<int,int>,gen> Delta_map; // cluster-barycenters-distance map
matrice _mu; // observation and cluster barycenters
vecteur _WGSSk; // sums of squared distances of observations from their barycenters
gen _WGSS; // sum of WGSSk for k=1..K
matrice _T; bool have_T; // total scatter matrix
matrice _WG; bool have_WG; // within-group scatter matrices (for each cluster)
matrice _BG; bool have_BG; // between-group scatter matrix
matrice _WGsum; // sum of matrices WGk for k=1..K
vecteur _TSS; // diagonal of T
vecteur _BGSS; // diagonal of BG
gen _DB_min; // minimal distance between observations from different clusters
gen _DB_max; // maximal distance between observations from different clusters
gen ET; // depends only on the given data; used for computing PBM index
/* return the barycenter of k-th cluster or the
* global barycenter if k is omitted */
const vecteur &mu(int k=-1) { return *_mu[k+1]._VECTptr; }
gen WGSS(int k=-1) { return k<0?_WGSS:_WGSSk[k]; }
const vecteur &T();
const vecteur &WG(int l=-1);
const vecteur &BG();
gen TSS(int k=-1);
gen BGSS(int k=-1);
gen DB(int dir);
int ci(int k) const { return _ci[k]; }
int n(int k) const { return _n[k]; }
gen Delta(int k,int l);
// individual criteria
gen banfeld_raftery();
gen calinski_harabasz();
gen davies_bouldin();
gen pbm();
gen ratkowsky_lance();
gen ray_turi();
gen scott_symons();
gen det_ratio();
gen log_det_ratio();
gen log_ss_ratio();
gen ksq_detW();
gen ball_hall();
gen trace_W();
gen trace_WiB();
// store index value
bool _updated;
std::map<int,vecteur> _vmap;
std::map<int,std::pair<int,double> > _optvals;
void update(int pos,const gen &val,int dir);
public:
cluster_crit(const matrice &data,const gen &dist_func,GIAC_CONTEXT);
void init(int k,const int *indices,const double *bc,const double *wgss);
bool compute_indices(int crit);
vecteur get_index_values(int pos=0) { return _vmap[pos]; }
static int optimal_number_of_clusters(const std::map<int,std::pair<int,double> > &optvals);
int ncopt() const { return optimal_number_of_clusters(_optvals); }
static int name2index(const std::string &name);
};
class hclust { // hierarchical agglomerative clustering
public:
typedef std::pair<double,std::pair<int,int> > drow; // dendrogram row: (delta,a,b)
typedef std::vector<drow> dendrogram;
private:
int N;
const context *ctx;
std::map<int,vecteur> _vmap;
vecteur _kvals;
std::map<int,std::pair<int,double> > _optvals;
std::vector<int> S,ord; // node labels/order
std::vector<std::pair<int,double> > slh_a,slh_s; // silhouette data
std::vector<std::map<int,std::pair<int,double> > > slh_b; // silhouette data
const matrice &points; // input data reference
gen distf; // distance function
double *_dist_cache; // cached distances
double &dist_cache(int i,int j) { return _dist_cache[(i*(2*N-i-3))/2+j-1]; }
double dist(int i,int j,bool cache=false); // compute d(i,j), use caching if CACHE=true
bool mst_linkage(dendrogram &dg,bool cache_distances); // single linkage algorithm
bool nn_chain_linkage(dendrogram &dg,int meth); // complete, average, weighted, and Ward linkage algorithm
double formula(int a,int b,int x,int na,int nb,int nx,double dab,int meth);
int k_low(const dendrogram &dg);
void walk_children(const dendrogram &dg,int &pos,int row);
void reorder_children(dendrogram &dg);
void swap(dendrogram &d,int row);
public:
hclust(const matrice &data,const gen &dist_func,GIAC_CONTEXT);
~hclust();
/* linkage with respect to method METH (linkage type), returns
* false if it fails to compute the distance between a pair of points */
int linkage(dendrogram &dg,std::vector<int> &ind,int meth,int K,int min_k,int max_k);
/* return the order of points which is optimal for drawing DG */
const std::vector<int> &order(dendrogram &dg);
vecteur get_index_values(int pos=0) { return mtran(makevecteur(_kvals,_vmap[pos])); }
static int name2index(const std::string &name);
};
class PermuSort { // permutation sorting in ascending order
const vecteur &v;
const context *ctx;
int as;
class comparator {
const PermuSort &parent;
public:
bool operator()(int i,int j) {
gen res=eval(symbolic(at_inferieur_strict_sort,makesequence(parent.v[i-parent.as],parent.v[j-parent.as])),1,parent.ctx);
return res.is_integer()?(bool)res.val:false;
}
comparator(const PermuSort &p) : parent(p) { }
};
public:
PermuSort(const vecteur &v_in,GIAC_CONTEXT) : v(v_in), ctx(contextptr) { as=array_start(contextptr); }
void sort(std::vector<int> &p);
};
class FDWeights { // finite-difference numerical differentiation
/* implemented according to Sadiq & Viswanath (2014) */
const vecteur &z;
vecteur w_lagrange;
matrice L,R,w;
int N,M;
const context *ctx;
void multbinom(const vecteur &a,vecteur &b,const gen &zeta);
void convolve(const vecteur &a,const vecteur &b,vecteur &c);
void lagrange_weights();
void find_weights(const vecteur &c,int k);
public:
FDWeights(const vecteur &grid_points,int diff_order,GIAC_CONTEXT);
void setz0(const gen &zeta=0);
gen operator()(int k,int m) const { return w[k][m]; } // weight for mth derivative at kth grid-point
};
class siman_config { // a configuration class for simulated annealing
const context *ctx;
const gen &energy_func;
const gen &distance_func;
const gen &modify_func;
gen _obj;
public:
siman_config(const gen &obj_orig,const gen &efunc,const gen &distfunc,const gen &modfunc,GIAC_CONTEXT)
: ctx(contextptr), energy_func(efunc), distance_func(distfunc), modify_func(modfunc) { _obj=obj_orig; }
siman_config(const siman_config &other)
: ctx(other.ctx), energy_func(other.energy_func), distance_func(other.distance_func), modify_func(other.modify_func) { _obj=other.obj(); }
void assign(const siman_config &other) { _obj=other.obj(); }
~siman_config() {}
const gen &obj() const { return _obj; }
bool is_valid() const { return !is_undef(_obj); }
int step_func_nargs() const { return modify_func._SYMBptr->feuille._VECTptr->front()._VECTptr->size(); }
gen energy() { return evalf_double(energy_func(_obj,ctx),1,ctx); }
gen distance(const siman_config &other) { return evalf_double(distance_func(makesequence(_obj,other.obj()),ctx),1,ctx); }
void modify(double step_size) { _obj=modify_func(step_func_nargs()==1?_obj:makesequence(_obj,step_size),ctx); }
};
gen _implicitdiff(const gen &g,GIAC_CONTEXT); // implicit differentiation
gen _box_constraints(const gen &g,GIAC_CONTEXT); // converting a matrix [[L1,U1],[L2,U2],...] to x1=L1..U1,x2=L2..U2,...
gen _minimize(const gen &g,GIAC_CONTEXT); // exact global minimization of a differentiable function over a compact domain
gen _maximize(const gen &g,GIAC_CONTEXT); // exact gloabl maximization
gen _find_minimum(const gen &g,GIAC_CONTEXT); // univariate approximation in a segment using Brent's method
gen _extrema(const gen &g,GIAC_CONTEXT); // exact local extrema
gen _minimax(const gen &g,GIAC_CONTEXT); // minimax polynomial approximation by Remez
gen _tpsolve(const gen &g,GIAC_CONTEXT); // transportation problem solver via MODI
gen _nlpsolve(const gen &g,GIAC_CONTEXT); // (mixed integer) nonlinear programming problem solver
gen _thiele(const gen &g,GIAC_CONTEXT); // rational interpolation using Thiele's algorithm
gen _triginterp(const gen &g,GIAC_CONTEXT); // trigonometric interpolation
gen _ratinterp(const gen &g,GIAC_CONTEXT); // rational interpolation without poles
gen _kernel_density(const gen &g,GIAC_CONTEXT); // kernel density estimation
gen _fitdistr(const gen &g,GIAC_CONTEXT); // distribution fitting to sample data
gen _fitpoly(const gen &g,GIAC_CONTEXT); // fitting a polynomial to a function or data
gen _bvpsolve(const gen &g,GIAC_CONTEXT); // iterative boundary-value problem solver
gen _euler_lagrange(const gen &g,GIAC_CONTEXT); // Euler-Lagrange equations
gen _jacobi_equation(const gen &g,GIAC_CONTEXT); // Jacobi equation
gen _conjugate_equation(const gen &g,GIAC_CONTEXT); // conjugate equation
gen _convex(const gen &g,GIAC_CONTEXT); // function convexity testing
gen _numdiff(const gen &g,GIAC_CONTEXT); // numerical differentiation using Fornberg's algorithm
gen _isolve(const gen &g,GIAC_CONTEXT); // Diophantine equation solver
gen _kmeans(const gen &g,GIAC_CONTEXT); // k-means clustering using Hartigan-Wong algorithm
gen _cluster(const gen &g,GIAC_CONTEXT); // agglomerative hierarchical clustering
gen _levenshtein(const gen &g,GIAC_CONTEXT); // Levenshtein distance between vectors/strings
gen _isposdef(const gen &g,GIAC_CONTEXT); // check whether a symmetric/Hermitian matrix is positive definite
gen _symbol_array(const gen &g,GIAC_CONTEXT); // Create vectors and matrices of symbols
gen _sortperm(const gen &g,GIAC_CONTEXT); // permutation that sorts the given vector in ascending order
gen _siman(const gen &g,GIAC_CONTEXT); // simulated annealing optimizer
gen _frank_wolfe(const gen &g,GIAC_CONTEXT); // Frank-Wolfe minimizer
gen _bspline(const gen &g,GIAC_CONTEXT); // Constructing B-splines from control points
gen _fitspline(const gen &g,GIAC_CONTEXT); // Fitting B-splines to data
extern const unary_function_ptr * const at_implicitdiff;
extern const unary_function_ptr * const at_box_constraints;
extern const unary_function_ptr * const at_minimize;
extern const unary_function_ptr * const at_maximize;
extern const unary_function_ptr * const at_find_minimum;
extern const unary_function_ptr * const at_extrema;
extern const unary_function_ptr * const at_minimax;
extern const unary_function_ptr * const at_tpsolve;
extern const unary_function_ptr * const at_nlpsolve;
extern const unary_function_ptr * const at_thiele;
extern const unary_function_ptr * const at_triginterp;
extern const unary_function_ptr * const at_ratinterp;
extern const unary_function_ptr * const at_kernel_density;
extern const unary_function_ptr * const at_fitdistr;
extern const unary_function_ptr * const at_fitpoly;
extern const unary_function_ptr * const at_bvpsolve;
extern const unary_function_ptr * const at_euler_lagrange;
extern const unary_function_ptr * const at_convex;
extern const unary_function_ptr * const at_numdiff;
extern const unary_function_ptr * const at_isolve;
extern const unary_function_ptr * const at_kmeans;
extern const unary_function_ptr * const at_cluster;
extern const unary_function_ptr * const at_levenshtein;
extern const unary_function_ptr * const at_isposdef;
extern const unary_function_ptr * const at_symbol_array;
extern const unary_function_ptr * const at_sortperm;
extern const unary_function_ptr * const at_siman;
extern const unary_function_ptr * const at_frank_wolfe;
extern const unary_function_ptr * const at_bspline;
extern const unary_function_ptr * const at_fitspline;
extern const unary_function_ptr * const at_geodetic2ecef;
extern const unary_function_ptr * const at_ecef2geodetic;
#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC
#endif // __OPTIMIZATION_H