| 1 | """ |
|---|
| 2 | This example illustrates a great speedup that can be achieved |
|---|
| 3 | via using oofun and oovar vs "classic" style, |
|---|
| 4 | even for unconstrained functions, |
|---|
| 5 | provided the solver deals with at least 1st derivatives, |
|---|
| 6 | so scipy_cobyla, goldenSection, scipy_fminbound, scipy_powell |
|---|
| 7 | or GLP solvers are inappropriate |
|---|
| 8 | |
|---|
| 9 | The speedup is due to changes in derivatives numerical approximation approach: |
|---|
| 10 | instead of handling whole dF/dx = d(g(f))/dx |
|---|
| 11 | we find dg/df, df/dx and |
|---|
| 12 | dF/dx = dg/df * df/dx |
|---|
| 13 | |
|---|
| 14 | Here's example of unconstrained problem, but constrained ones can be used as well |
|---|
| 15 | for NLP, NSP, NLSP, LSP classes |
|---|
| 16 | |
|---|
| 17 | Concider the NL problem |
|---|
| 18 | g(f(x)) -> min |
|---|
| 19 | g is costly and g derivative are not available |
|---|
| 20 | f(x) = (x[0]-0)^2 + (x[1]-1)^2 + ... + (x[N-1]-(N-1))^2 |
|---|
| 21 | see below for definition of g |
|---|
| 22 | here I have chosed g: R -> R for the sake of simplicity, |
|---|
| 23 | but R^m -> R^k can be handled as well |
|---|
| 24 | """ |
|---|
| 25 | def CostlyFunction(z): |
|---|
| 26 | counter['g'] += 1 |
|---|
| 27 | r = z |
|---|
| 28 | for k in xrange(1, K+2): |
|---|
| 29 | r += z ** (1 / k**1.5) |
|---|
| 30 | return r |
|---|
| 31 | |
|---|
| 32 | def f(z): |
|---|
| 33 | counter['f'] += 1 |
|---|
| 34 | return ((z-aN)**2).sum() |
|---|
| 35 | |
|---|
| 36 | solver = 'scipy_ncg'# try also scipy_cg, scipy_ncg, ralg, algencan etc |
|---|
| 37 | N, K = 150, 500 |
|---|
| 38 | ftol, xtol, gtol = 1e-6, 1e-6, 1e-6 |
|---|
| 39 | iprint = 5 |
|---|
| 40 | |
|---|
| 41 | from scikits.openopt import NLP, oofun, oovar |
|---|
| 42 | from numpy import arange, zeros |
|---|
| 43 | aN = arange(N) |
|---|
| 44 | |
|---|
| 45 | """ 1: using oovar & oofun """ |
|---|
| 46 | counter = {'f':0, 'g':0} |
|---|
| 47 | v = oovar('v', size = N) # start value will be zeros(N) |
|---|
| 48 | ff = oofun(f, input = v) |
|---|
| 49 | g = oofun(CostlyFunction, input = ff) |
|---|
| 50 | p = NLP(g, maxIter=1e4, iprint=iprint, ftol=ftol, xtol=xtol, gtol=gtol) |
|---|
| 51 | print 'using oofun:' |
|---|
| 52 | r = p.solve(solver) |
|---|
| 53 | print 'evals f:', counter['f'], ' evals of costly func g:', counter['g'] |
|---|
| 54 | """ 2: classic """ |
|---|
| 55 | counter = {'f':0, 'g':0} |
|---|
| 56 | g = CostlyFunction |
|---|
| 57 | p = NLP(lambda x: g(f(x)), x0=zeros(N), maxIter=1e4, ftol=ftol, xtol=xtol, gtol=gtol, iprint=iprint) |
|---|
| 58 | print '\nwithout oofun:' |
|---|
| 59 | r = p.solve(solver) |
|---|
| 60 | print 'evals f:', counter['f'], ' evals of costly func g:', counter['g'] |
|---|
| 61 | """ |
|---|
| 62 | using oofun: |
|---|
| 63 | ----------------------------------------------------- |
|---|
| 64 | solver: scipy_ncg problem: unnamed goal: minimum |
|---|
| 65 | iter objFunVal |
|---|
| 66 | 0 2.228e+06 |
|---|
| 67 | 5 4.876e+04 |
|---|
| 68 | 10 4.953e+02 |
|---|
| 69 | 15 4.924e+02 |
|---|
| 70 | 20 4.901e+02 |
|---|
| 71 | 25 4.881e+02 |
|---|
| 72 | 30 4.862e+02 |
|---|
| 73 | 31 4.862e+02 |
|---|
| 74 | istop: 1000 |
|---|
| 75 | Solver: Time Elapsed = 1.51 CPU Time Elapsed = 1.49 |
|---|
| 76 | objFunValue: 486.20891 |
|---|
| 77 | evals f: 17887 evals of costly func g: 305 |
|---|
| 78 | |
|---|
| 79 | without oofun: |
|---|
| 80 | ----------------------------------------------------- |
|---|
| 81 | solver: scipy_ncg problem: unnamed goal: minimum |
|---|
| 82 | iter objFunVal |
|---|
| 83 | 0 2.228e+06 |
|---|
| 84 | 5 4.957e+02 |
|---|
| 85 | 10 4.926e+02 |
|---|
| 86 | 15 4.903e+02 |
|---|
| 87 | 20 4.882e+02 |
|---|
| 88 | 25 4.864e+02 |
|---|
| 89 | 27 4.861e+02 |
|---|
| 90 | istop: 1000 |
|---|
| 91 | Solver: Time Elapsed = 15.09 CPU Time Elapsed = 14.29 |
|---|
| 92 | objFunValue: 486.07635 |
|---|
| 93 | evals f: 13660 evals of costly func g: 13660 |
|---|
| 94 | """ |
|---|