-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathoptimpack.h
2512 lines (2288 loc) · 88.1 KB
/
optimpack.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
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* optimpack.h --
*
* Common definitions for OptimPack library.
*
*-----------------------------------------------------------------------------
*
* This file is part of OptimPack (https://github.com/emmt/OptimPack).
*
* Copyright (C) 2014-2016 Éric Thiébaut
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*-----------------------------------------------------------------------------
*/
#ifndef OPTIMPACK_H_
#define OPTIMPACK_H_ 1
#include <stdio.h>
#include <stddef.h>
/**
* @defgroup LimitedMemory Limited memory methods.
* @defgroup NLCG Non-linear conjugate gradient methods.
* @defgroup VariableMetric Variable metric methods.
* @defgroup LineSearch Line search methods.
* @defgroup ReverseCommunication Reverse communication model.
* @defgroup Objects Management of objects and derived types.
* @defgroup Vectors Vectors to store variables and vector spaces.
* @defgroup Operators Operators acting on vectors.
* @defgroup Error Reporting of errors.
* @defgroup TrustRegion Trust region methods.
* @defgroup Utilities Miscellaneous utility functions and macros.
* @defgroup LowLevel Low-level API to implement objects.
* @defgroup LinearAlgebra BLAS/LAPACK/LINPACK-like linear algebra routines for small arrays.
*
* @mainpage Optimization of large scale problems
*
* OptimPack is a library for large scale optimization problems. Its primary
* focus is solving large inverse problems as image reconstruction.
*
*
* @section LargeScale Large scale optimization
*
* OptimPack implements limited memory optimization methods dedicated to the
* minimization of function of a large number of variables. We routinely use
* these method to solve image restoration problems with millions, of even
* billions, of variables. Two families of methods are provided: non-linear
* conjugate gradients and variable metric methods. These methods require the
* objective function and its gradient thus the objective function has to be \e
* smooth that is to say \e differentiable.
*
* @subsection ReverseCommunicationDriver General reverse communication driver
*
* @ref LimitedMemory
*
* @ref NLCG
*
* @ref VariableMetric
*
* @ref LineSearch
*
*
* @section ManagementOfObjects Management of objects and derived types
*
* OptimPack implements a simple object-oriented API with various object
* classes. The most basic reason of this choice is to correctly manage data
* and structures which may be shared between different piece of code. All
* OptimPack objects inherit from @ref Objects::opk_object "opk_object"
* whose instances maintain a reference count and take care of releasing
* ressources when objects are no longer in use (understand \e referenced).
* This memory management model is lightweight and very effective and but is
* not as sophisticated as, say a garbage collector which allows for circular
* references (circular references must be avoided in OptimPack).
*
* @subsection BasicObjects Basic objects
* @ref Objects
*
* @subsection VectorSpaces Vectors and vector spaces
*
* A high level driver is provided by OptimPack to the implemented limited
* memory optimization methods. At a lower level, these methods operate on
* variables which can be stored in any form suitable to the application needs.
* OptimPack will never directly access the components of these variables and
* only applies a limited set of operations (dot product, scaling, linear
* combination, *etc.*) to the variables. These operations are very similar to
* the one available to \e vectors in mathematics and the notions of vectors
* and associated vector spaces, operators and linear algebra are central to
* OptimPack (and to optimization in general).
*
* @ref Vectors
*
* @ref Operators
*
* OptimPack provides a simple memory model to store variables (as conventional
* C arrays of float/double values) but no memory model is imposed. For
* instance, you may have your variables stored in non-conventional memory (GPU)
* or distributed between several machines. The only requirement is to provide
* OptimPack with a set of functions to manipulate your own implementation of
* vectors.
*
*
* @section Linear Algebra
*
* OptimPack has a number of linear algebra routines for small and simple
* arrays mostly ported from the LINPACK library (in FORTRAN).
*
* @ref LinearAlgebra
*/
/*---------------------------------------------------------------------------*/
/*
* Miscellaneous macros.
*
* OPK_BEGIN_C_DECLS - Start declarations of C elements (functions, variables,
* types, structures, etc.).
* OPK_END_C_DECLS - Terminate C declarations.
*
* <OPK_BEGIN_C_DECLS> should be used at the beginning of your declarations,
* so that C++ compilers don't mangle their names. Use <OPK_END_C_DECLS> at
* the end of C declarations.
*/
#ifdef __cplusplus
# define OPK_BEGIN_C_DECLS extern "C" {
# define OPK_END_C_DECLS }
#else /* not __cplusplus */
# define OPK_BEGIN_C_DECLS
# define OPK_END_C_DECLS
#endif /* __cplusplus */
/**
* Macro `OPK_JOIN(a,b)` joins its two arguments, possibly after performing
* macro expansion of `a` and `b`.
*/
#define OPK_JOIN(a,b) OPK_JOIN2_(a,b)
#define OPK_JOIN2(a,b) OPK_JOIN2_(a,b)
#define OPK_JOIN3(a,b,c) OPK_JOIN3_(a,b,c)
#define OPK_JOIN4(a,b,c,d) OPK_JOIN4_(a,b,c,d)
#define OPK_JOIN5(a,b,c,d,e) OPK_JOIN5_(a,b,c,d,e)
#define OPK_JOIN6(a,b,c,d,e,f) OPK_JOIN6_(a,b,c,d,e,f)
#define OPK_JOIN7(a,b,c,d,e,f,g) OPK_JOIN7_(a,b,c,d,e,f,g)
#define OPK_JOIN8(a,b,c,d,e,f,g,h) OPK_JOIN8_(a,b,c,d,e,f,g,h)
#define OPK_JOIN9(a,b,c,d,e,f,g,h,i) OPK_JOIN9_(a,b,c,d,e,f,g,h,i)
/**
* Macro `OPK_STRINGIFY(x)` wraps its argument in "" (double quotation marks),
* possibly after performing macro expansion of the argument.
*/
#define OPK_STRINGIFY(x) OPK_STRINGIFY_(x)
/* Stringify/concatenate arguments without expansion. */
#if defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus)
# define OPK_STRINGIFY_(x) # x
# define OPK_JOIN2_(a,b) a##b
# define OPK_JOIN3_(a,b,c) a##b##c
# define OPK_JOIN4_(a,b,c,d) a##b##c##d
# define OPK_JOIN5_(a,b,c,d,e) a##b##c##d##e
# define OPK_JOIN6_(a,b,c,d,e,f) a##b##c##d##e##f
# define OPK_JOIN7_(a,b,c,d,e,f,g) a##b##c##d##e##f##g
# define OPK_JOIN8_(a,b,c,d,e,f,g,h) a##b##c##d##e##f##g##h
# define OPK_JOIN9_(a,b,c,d,e,f,g,h,i) a##b##c##d##e##f##g##h##i
#else
# define OPK_STRINGIFY_(x) "x"
# define OPK_JOIN2_(a,b) a/**/b
# define OPK_JOIN3_(a,b,c) a/**/b/**/c
# define OPK_JOIN4_(a,b,c,d) a/**/b/**/c/**/d
# define OPK_JOIN5_(a,b,c,d,e) a/**/b/**/c/**/d/**/e
# define OPK_JOIN6_(a,b,c,d,e,f) a/**/b/**/c/**/d/**/e/**/f
# define OPK_JOIN7_(a,b,c,d,e,f,g) a/**/b/**/c/**/d/**/e/**/f/**/g
# define OPK_JOIN8_(a,b,c,d,e,f,g,h) a/**/b/**/c/**/d/**/e/**/f/**/g/**/h
# define OPK_JOIN9_(a,b,c,d,e,f,g,h,i) a/**/b/**/c/**/d/**/e/**/f/**/g/**/h/**/i
#endif
/*---------------------------------------------------------------------------*/
/**
* Macro `OPK_ABS(a)` gives the absolute value of `a`.
*
* Beware that `a` is evaluated twice.
*/
#define OPK_ABS(a) ((a) >= 0 ? (a) : -(a))
/**
* Macro `OPK_MIN(a,b)` yields the minimum value between `a` and `b`.
*/
#define OPK_MIN(a,b) ((a) <= (b) ? (a) : (b))
/**
* Macro `OPK_MAX(a,b)` yields the maximum value between `a` and `b`.
*/
#define OPK_MAX(a,b) ((a) >= (b) ? (a) : (b))
/**
* Macro `OPK_HOW_MANY(a,b)` yields the minimal number of chunks with `b`
* elements needed to store `a` elements. Both `a` and `b` must be integers.
*/
#define OPK_HOW_MANY(a,b) ((((b) - 1) + (a))/(b))
/**
* Macro `OPK_ROUND_UP(a,b)` yields the integer `a` rounded up to a multiple of
* integer `b`.
*/
#define OPK_ROUND_UP(a,b) (OPK_HOW_MANY(a,b)*(b))
/**
* Macro `OPK_ADDRESS(type,base,offset)` yields a `type*` address at `offset`
* (in bytes) from `base` address.
*/
#define OPK_ADDRESS(type, base, offset) ((type*)((char*)(base) + (offset)))
/**
* Macro `OPK_OFFSET(type, field)` yields the offset (in bytes) of member
* `field` in structure/class `type`.
*/
#ifdef offsetof
# define OPK_OFFSET(type, field) offsetof(type, field)
#elif 1
# define OPK_OFFSET(type, field) ((size_t)((char*)&((type*)0)->field))
#else
# define OPK_OFFSET(type, field) ((char*)&((type*)0)->field - (char*)0)
#endif
/**
* Macro `OPK_LOOP(var,cnt)` yields a simple loop over variable `var` from 0 to
* `cnt` - 1.
*/
#define OPK_LOOP(var, cnt) for (var = 0; var < cnt; ++var)
/** Yields |a|*sign(b). */
#define opk_sign(a, b) ({ typeof(a) _1 = (a); typeof(b) _2 = (b); \
((_1 < 0) == ((b) < 0)) ? _1 : -_1;})
/** Yield absolute value. */
#define opk_abs(a) ({ typeof(a) _1 = (a); _1 >= 0 ? _1 : -_1; })
/** Yield minimum of two values. */
#define opk_min(a, b) ({ typeof(a) _1 = (a); typeof(b) _2 = (b); \
_1 <= _2 ? _1 : _2;})
/** Yield maximum of two values. */
#define opk_max(a, b) ({ typeof(a) _1 = (a); typeof(b) _2 = (b); \
_1 >= _2 ? _1 : _2;})
/*---------------------------------------------------------------------------*/
/**
* Macro `OPK_NEW(type)` allocates an object of structure/class `type`.
*/
#define OPK_NEW(type) ((type *)malloc(sizeof(type)))
/**
* Macro `OPK_ALLOC(type,number)` allocates an array of `number` items of
* structure/class `type`.
*/
#define OPK_ALLOC(type, number) ((type *)malloc((number)*sizeof(type)))
/**
* Macro `OPK_FREE(ptr)` frees pointer `ptr` if non-null.
*/
#define OPK_FREE(ptr) if (! (ptr)) ; else free(ptr)
/*---------------------------------------------------------------------------*/
OPK_BEGIN_C_DECLS
#define OPK_STATUS_LIST_ \
OPK_STATUS_( 0, OPK_SUCCESS, "Success") \
OPK_STATUS_( 1, OPK_INVALID_ARGUMENT, "Invalid argument") \
OPK_STATUS_( 2, OPK_INSUFFICIENT_MEMORY, "Insufficient memory") \
OPK_STATUS_( 3, OPK_ILLEGAL_ADDRESS, "Illegal address") \
OPK_STATUS_( 4, OPK_NOT_IMPLEMENTED, "Not implemented") \
OPK_STATUS_( 5, OPK_CORRUPTED_WORKSPACE, "Corrupted workspace") \
OPK_STATUS_( 6, OPK_BAD_SPACE, "Bad variable space") \
OPK_STATUS_( 7, OPK_OUT_OF_BOUNDS_INDEX, "Out of bounds index") \
OPK_STATUS_( 8, OPK_NOT_STARTED, "Line search not started") \
OPK_STATUS_( 9, OPK_NOT_A_DESCENT, "Not a descent direction") \
OPK_STATUS_(10, OPK_STEP_CHANGED, "Step changed") \
OPK_STATUS_(11, OPK_STEP_OUTSIDE_BRACKET, "Step outside bracket") \
OPK_STATUS_(12, OPK_STPMIN_GT_STPMAX, \
"Lower step bound larger than upper bound") \
OPK_STATUS_(13, OPK_STPMIN_LT_ZERO, \
"Minimal step length less than zero") \
OPK_STATUS_(14, OPK_STEP_LT_STPMIN, "Step lesser than lower bound") \
OPK_STATUS_(15, OPK_STEP_GT_STPMAX, "Step greater than upper bound") \
OPK_STATUS_(16, OPK_FTOL_TEST_SATISFIED, \
"Convergence within variable tolerance") \
OPK_STATUS_(17, OPK_GTOL_TEST_SATISFIED, \
"Convergence within function tolerance") \
OPK_STATUS_(18, OPK_XTOL_TEST_SATISFIED, \
"Convergence within gradient tolerance") \
OPK_STATUS_(19, OPK_STEP_EQ_STPMAX, "Step blocked at upper bound") \
OPK_STATUS_(20, OPK_STEP_EQ_STPMIN, "Step blocked at lower bound") \
OPK_STATUS_(21, OPK_ROUNDING_ERRORS_PREVENT_PROGRESS, \
"Rounding errors prevent progress") \
OPK_STATUS_(22, OPK_NOT_POSITIVE_DEFINITE, \
"Operator is not positive definite") \
OPK_STATUS_(23, OPK_BAD_PRECONDITIONER, \
"Preconditioner is not positive definite") \
OPK_STATUS_(24, OPK_INFEASIBLE_BOUNDS, "Box set is infeasible") \
OPK_STATUS_(25, OPK_WOULD_BLOCK, \
"Variables cannot be improved (would block)") \
OPK_STATUS_(26, OPK_UNDEFINED_VALUE, "Undefined value") \
OPK_STATUS_(27, OPK_TOO_MANY_EVALUATIONS, "Too many evaluations") \
OPK_STATUS_(28, OPK_TOO_MANY_ITERATIONS, "Too many iterations")
/**
* Values returned by OptimPack routines.
*
* `OPK_SUCCESS` indicates that the routine was successfull, any other value
* indicate a failure or a warning.
*/
typedef enum {
#define OPK_STATUS_(a,b,c) b = a,
OPK_STATUS_LIST_
#undef OPK_STATUS_
OPK_MAX_STATUS
} opk_status;
/**
* Retrieve a textual description for a given status.
*
* @param status - The status code.
*
* @return A pointer to a string describing the status or an empty string, "",
* if the status does not correspond to any known status.
*/
extern const char*
opk_get_reason(opk_status status);
/**
* Retrieve OptimPack status from C library error code.
*
* This function is needed to figure out the kind of errors for the few
* routines which do not return a status (mostly the ones which create
* objects).
*
* @param code The error code, usually `errno`.
*
* @return The OptimPack status corresponding to the error.
*/
extern opk_status opk_guess_status(int code);
/**
* Copy a string.
*
* @param dst - The destination buffer to copy the soruce (can be `NULL`).
* @param size - The number of available bytes in `buf`.
* @param src - The source string; `NULL` is considered as being the
* same as an empty string "".
* @return The minimum number of bytes required to store the source
* string (including the terminating '\0' character).
*/
extern size_t
opk_copy_string(char* dst, size_t size, const char* src);
/**
* Get a constant given its name.
*
* This function is mostly need for OptimPack wrappers in other languages than
* C to avoid hardcoding the constants of the library. For now this function
* is not particularly efficient so it should be sparsely used.
*
* @param name - The name of the constant; for instance: `"OPK_SUCCESS"`.
* @param ptr - The address where to store the value of the constant.
*
* @return `OPK_SUCCESS` or `OPK_INVALID_ARGUMENT` if the name is unknown.
*/
extern opk_status
opk_get_integer_constant(const char* name, long* ptr);
/*---------------------------------------------------------------------------*/
/* DATA TYPES */
/**
* Integer data type used for array indices in OptimPack.
*/
typedef ptrdiff_t opk_index;
/**
* Possible boolean (logical) values.
*/
typedef enum {
OPK_FALSE = 0,
OPK_TRUE = 1
} opk_bool;
/** Type of the variables in a conventional array. */
typedef enum {
OPK_FLOAT, /**< Variables are single precision floating point numbers. */
OPK_DOUBLE /**< Variables are double precision floating point numbers. */
} opk_eltype;
/*---------------------------------------------------------------------------*/
/* BASIC OBJECTS */
/**
* @addtogroup Objects
* @{
*
* Users of OptimPack library normally do not need to known exactly the
* contents of an object. They simply use the functions of the library to
* manipulate object pointers as opaque structure pointers.
*
* Developpers who need to implement derived types or specific variants of
* existing types must include the header `optimpack-private.h` to unveil
* the definitions of the structures representing the OptimPack objects.
*/
/**
* Opaque basic object type.
*/
typedef struct opk_object_ opk_object;
/**
* Hold a reference on an object.
*
* This function increments the reference count of its argument and returns it.
* If the argument is `NULL`, nothing is done. Every call to this function must
* be balanced by a call to `opk_drop_object()`.
*
* It is a good practice to hold a reference whenever a persistent structure
* (e.g., another object) remembers the object. To limit the number of casts,
* the macro `OPK_HOLD()` can be used instead.
*
* @param obj - The object to lock (can be NULL).
*
* @return Its argument (with one more reference if not NULL).
*/
extern opk_object*
opk_hold_object(opk_object* obj);
/**
* Drop a reference on an object.
*
* This function decrements the reference count of its argument and delete it
* if there are no other references. If the argument is `NULL`, nothing is
* done. To effectively delete an object, there must be a call to this
* function for every call to `opk_hold_object()` on this object plus one (to
* release the reference by the creator of the object).
*
* @param obj - The object to release (can be `NULL`).
*/
extern void
opk_drop_object(opk_object* obj);
/**
* Get the number of references on an object.
*
* @param obj - The object (can be `NULL`).
*
* @return The number of references set on the object. If the object address
* is `NULL`, the result is zero; otherwise, the result is greater of
* equal one.
*/
extern opk_index
opk_get_object_references(opk_object* obj);
/**
* Macro to set a reference on an object whatever its type. Compared to the
* function `opk_hold_object()`, this macro casts its argument to be an
* `opk_object` pointer. The result is the argument cast as a basic object
* pointer.
*/
#define OPK_HOLD(obj) opk_hold_object((opk_object*)(obj))
/**
* Macro to drop an object whatever its type. Compared to the function
* `opk_drop_object()`, this macro casts its argument to be an `opk_object`
* pointer.
*/
#define OPK_DROP(obj) opk_drop_object((opk_object*)(obj))
/**
* Macro to query the number of references on an object whatever its type.
* Compared to the function `opk_get_object_references()`, this macro casts its
* argument to be a `opk_object` pointer.
*/
#define OPK_REFS(obj) opk_get_object_references((opk_object*)(obj))
#define OPK_HOLD_VSPACE(vsp) ((opk_vspace*)OPK_HOLD(vsp))
#define OPK_HOLD_VECTOR(vec) ((opk_vector*)OPK_HOLD(vec))
#define OPK_HOLD_LNSRCH(lns) ((opk_lnsrch*)OPK_HOLD(lns))
#define OPK_HOLD_OPERATOR(op) ((opk_operator*)OPK_HOLD(op))
#define OPK_HOLD_CONVEXSET(set) ((opk_convexset*)OPK_HOLD(set))
/** @} */
/*---------------------------------------------------------------------------*/
/* VECTORS AND VECTOR SPACES */
/**
* @addtogroup Vectors
* @{
*/
/** Opaque vector type. This sub-type inherits from `opk_object`. */
typedef struct opk_vector_ opk_vector;
/** Opaque vector space type. This sub-type inherits from `opk_object`. */
typedef struct opk_vspace_ opk_vspace;
/** Prototype of function to release client data. */
typedef void opk_free_proc(void*);
/**
* Create a vector space for array of double's in conventional memory.
*
* This particular type of vector space deals with arrays of values stored
* contiguously and accessible as conventional arrays. This include arrays
* allocated from the heap, dynamically allocated with `malloc()`, arrays in
* shared memory, memory mapped files, etc.
*
* To create vectors belonging to this kind of vector space, as for any type
* of vector spaces, it is possible to call `opk_vcreate()` but it is also
* possible to call `opk_wrap_simple_double_vector()` to wrap an existing
* array (of the correct size and type of course) into a vector.
*
* @param size - The number of elements of the vectors of the space.
*
* @return A new vector space or `NULL` in case of errors.
*/
extern opk_vspace*
opk_new_simple_double_vector_space(opk_index size);
/**
* Wrap an existing array into a simple vector.
*
* This function creates a new vector whose elements are stored into an array
* provided by the caller. The caller is responsible of ensuring that the
* memory is sufficiently large (the array has at least `vspace->size`
* elements) and correctly aligned.
*
* When the vector is destroyed, the function `free_client_data()`, if not
* `NULL`, is called with argument `client_data` to release ressources. Then
* the container is freed. If function `free_client_data()` is `NULL`, it is
* assumed that the caller is responsible of releasing the data when no longer
* needed.
*
* A typical usage is:
* ~~~~~~~~~~{.c}
* #define N 1000
* opk_vspace* vspace = opk_new_simple_double_vector_space(N);
*
* double heap_array[N];
* opk_vector* v1 = opk_wrap_simple_double_vector(vspace, heap_array,
* NULL, NULL);
*
* double* dynamic_array = (double*)malloc(N*sizeof(double));
* opk_vector* v2 = opk_wrap_simple_double_vector(vspace, dynamic_array,
* free, dynamic_array);
* ~~~~~~~~~~
*
* which creates two vectors, `v1` and `v2`, which are respectively wrapped
* around an array allocated on the heap and around a dynamically allocated
* array.
*
* In the above example, the `client_data` and the `data` are the same but the
* possible distinction is needed to allow for using of various kind of
* objects which contain an array of values that can be wrapped into a
* vector. For objects of type `object_type`, we can do something like:
* ~~~~~~~~~~{.c}
* object_type* obj = ...;
* opk_vspace* vspace = opk_new_simple_double_vector_space(get_number(obj));
* opk_vector* v = opk_wrap_simple_double_vector(vspace, get_data(obj),
* delete_object,
* (void*)obj);
* ~~~~~~~~~~
* where `get_number()` returns the number of elements stored in the data part
* of the object, `get_data()` returns the address of these elements, and
* `delete_object()` delete the object. Of course, if one prefers to keep the
* control on the object management, passing `NULL` for the
* `free_client_data()` function is always possible.
*
* @param vspace - The vector space which will own the vector.
* @param data - The array of values, must have at least `vspace->size`
* elements.
* @param free_client_data - Function called to release ressources. If not
* `NULL`, it is called with argument `client_data` when the
* vector is destroyed.
* @param client_data - Anything required by the `free_client_data()` method.
*
* @return A new vector of `vspace`, `NULL` in case of error.
*/
extern opk_vector*
opk_wrap_simple_double_vector(opk_vspace* vspace, double data[],
void (*free_client_data)(void*),
void* client_data);
extern double*
opk_get_simple_double_vector_data(opk_vector* v);
extern void*
opk_get_simple_double_vector_client_data(opk_vector* v);
extern opk_free_proc*
opk_get_simple_double_vector_free_client_data(opk_vector* v);
/**
* Re-wrap an array into an existing simple vector.
*
* This functions replaces the contents of a simple wrapped vector. It is
* assumed that the vector `vect` is a wrapped vector, that the new data
* `new_data` is correctly aligned and large enough. If the former
* `free_client_data()` method of the wrapped vector `vect` is not `NULL` and
* if either the new `free_client_data()` method or the new `client_data`
* differ from the former ones, then the former `free_client_data()` method is
* applied to the former `client_data`.
*
* Re-wrapping is considered as a hack which merely saves the time needed to
* allocate a container for a wrapped vector. It is the caller responsibility
* to ensure that all the assumptions hold. In many cases dropping the old
* vector and wrapping the arguments into a new vector is safer.
*
* @param vect - The vector to re-wrap.
* @param new_data - The new array of values.
* @param new_free_client_data - The new method to free client data.
* @param new_client_data - The new client data.
*
* @return `OPK_SUCCESS` or `OPK_FAILURE`. In case of failure, global variable
* `errno` is set to: `EFAULT` if `vect` or `new_data` are `NULL`,
* `EINVAL` if `vect` is not a vector of the correct kind.
*/
extern int
opk_rewrap_simple_double_vector(opk_vector* vect, double new_data[],
void (*new_free_client_data)(void*),
void* new_client_data);
/**
* Create a vector space for array of float's in conventional memory.
*
* See `opk_new_simple_double_vector_space()` for a description.
*/
extern opk_vspace*
opk_new_simple_float_vector_space(opk_index size);
/**
* Wrap an existing array into a simple vector.
*
* See `opk_wrap_simple_double_vector()` for a description.
*/
extern opk_vector*
opk_wrap_simple_float_vector(opk_vspace* vspace, float data[],
void (*free_client_data)(void*),
void* client_data);
extern float*
opk_get_simple_float_vector_data(opk_vector* v);
extern void*
opk_get_simple_float_vector_client_data(opk_vector* v);
extern opk_free_proc*
opk_get_simple_float_vector_free_client_data(opk_vector* v);
extern int
opk_rewrap_simple_float_vector(opk_vector* v, float new_data[],
void (*new_free_client_data)(void*),
void* new_client_data);
/**
* Create a vector instance.
*
* This functions creates a new vector of a given vector space. The contents
* of the vector is undefined. The caller holds a reference on the returned
* vector which has to be released with the function `opk_drop_object()` or
* with the macro `OPK_DROP()`.
*
* @param vspace - The vector space which owns the vector to create.
*
* @return A new vector of the vector space; `NULL` in case of error.
*/
extern opk_vector*
opk_vcreate(opk_vspace* vspace);
/**
* Print vector contents.
*
* @param file - The output file stream, `stdout` is used if `NULL`.
* @param name - The name of the vector, can be `NULL`.
* @param nmax - The maximum number of elements to print. The vector size is
* used if this parameter is not strictly positive.
*/
extern void
opk_vprint(FILE* file, const char* name, const opk_vector* vect,
opk_index nmax);
/**
* Fetch a specific vector component.
*
* This function is by no means intended to be efficient and should be avoided
* except for debugging purposes.
*
* @param vect - A vector.
* @param k - The index of the compoent to peek.
* @param ptr - The address to store the component value (as a double
* precision floating point).
*
* @return A standard status.
*/
extern opk_status
opk_vpeek(const opk_vector* vect, opk_index k, double* ptr);
/**
* Set the value of a specific vector component.
*
* This function is by no means intended to be efficient and should be avoided
* except for debugging purposes.
*
* @param vect - A vector.
* @param k - The index of the component to set.
* @param value - The value to store in the component (as a double precision
* floating point).
*
* @return A standard status.
*/
extern opk_status
opk_vpoke(opk_vector* vect, opk_index k, double value);
/**
* Copy the values of a conventional array into a vector.
*
* @param dst - The destination vector.
* @param src - The source array.
* @param type - The type of the elements of the source array.
* @param n - The number of elements in the source array.
*
* @return A standard status. The number of elements of the source must match
* those of the destination.
*/
extern opk_status
opk_vimport(opk_vector* dst, const void* src, opk_eltype type, opk_index n);
/**
* Copy the values of a vector into a conventional array.
*
* @param dst - The destination array.
* @param type - The type of the elements of the destination array.
* @param n - The number of elements in the destination array.
* @param src - The source vector.
*
* @return A standard status. The number of elements of the source must match
* those of the destination.
*/
opk_status
opk_vexport(void* dst, opk_eltype type, opk_index n, const opk_vector* src);
/**
* Fill a vector with zeros.
*
* This functions set all elements of a vector to zero.
*
* @param vect - The vector to fill.
*/
extern void
opk_vzero(opk_vector* vect);
/**
* Fill a vector with a given value.
*
* This functions set all elements of a vector to the given value.
*
* @param vect - The vector to fill.
* @param alpha - The value.
*/
extern void
opk_vfill(opk_vector* vect, double alpha);
/**
* Copy vector contents.
*
* This functions copies the contents of the source vector into the destination
* vector. Both vectors must belong to the same vector space.
*
* @param dst - The destination vector.
* @param src - The source vector.
*/
extern void
opk_vcopy(opk_vector* dst, const opk_vector* src);
/**
* Scale a vector by a scalar.
*
* This functions multiplies the elements of the source vector by the given
* value and stores the result into the destination vector. Both vectors must
* belong to the same vector space. The operation is optimized for specfific
* values of `alpha`: with `alpha = 1`, the operation is the same as
* `opk_vcopy()`; with `alpha = 0`, the operation is the same as `opk_vzero()`.
*
* @param dst - The destination vector.
* @param alpha - The scale factor.
* @param src - The source vector.
*/
extern void
opk_vscale(opk_vector* dst,
double alpha, const opk_vector* src);
/**
* Exchange vector contents.
*
* This functions exchanges the contents of two vectors. Both vectors must
* belong to the same vector space.
*
* @param x - A vector.
* @param y - Another vector.
*/
extern void
opk_vswap(opk_vector* x, opk_vector* y);
/**
* Compute the inner product of two vectors.
*
* This functions computes the inner product, also known as scalar product, of
* two vectors. Both vectors must belong to the same vector space.
*
* @param x - A vector.
* @param y - Another vector.
*
* @return The inner product of the two vectors, that is the sum of the product
* of their elements.
*/
extern double
opk_vdot(const opk_vector* x, const opk_vector* y);
/**
* Compute the inner product of three vectors.
*
* This functions computes the sum of the componentwise product of the elements
* of three vectors. All three vectors must belong to the same vector space.
*
* @param w - A vector.
* @param x - Another vector.
* @param y - Yet another vector.
*
* @return The sum of the componentwise product of the elements of three
* vectors.
*/
extern double
opk_vdot3(const opk_vector* w, const opk_vector* x, const opk_vector* y);
/**
* Compute the L2 norm of a vector.
*
* This functions computes the L2 norm, also known as the Euclidean norm, of a
* vector.
*
* @param v - A vector.
*
* @return The Euclidean norm of the vector, that is the square root of the sum
* of its squared elements.
*/
extern double
opk_vnorm2(const opk_vector* v);
/**
* Compute the L1 norm of a vector.
*
* This functions computes the L1 norm of a vector.
*
* @param v - A vector.
*
* @return The L1 norm of the vector, that is the sum of the absolute values of
* its elements.
*/
extern double
opk_vnorm1(const opk_vector* v);
/**
* Compute the infinite norm of a vector.
*
* This functions computes the infinite norm of a vector.
*
* @param v - A vector.
*
* @return The infinite norm of the vector, that is the maximum absolute value
* of its elements.
*/
extern double
opk_vnorminf(const opk_vector* v);
/**
* Compute the elementwise product of two vectors.
*
* All vectors must belong to the same vector space.
*
* @param dst - The destination vector.
* @param x - A vector.
* @param y - Another vector.
*/
extern void
opk_vproduct(opk_vector* dst,
const opk_vector* x,
const opk_vector* y);
/**
* Compute the linear combination of two vectors.
*
* This functions stores in the destination vector `dst` the linear combination
* `alpha*x + beta*y` where `alpha` and `beta` are two scalars while `x` and
* `y` are two vectors. All vectors must belong to the same vector space.
*
* @param dst - The destination vector.
* @param alpha - The factor for the vector `x`.
* @param x - A vector.
* @param beta - The factor for the vector `y`.
* @param y - Another vector.
*/
extern void
opk_vaxpby(opk_vector* dst,
double alpha, const opk_vector* x,
double beta, const opk_vector* y);
/**
* Compute the linear combination of three vectors.
*
* This functions stores in the destination vector `dst` the linear combination
* `alpha*x + beta*y + gamma*z` where `alpha`, `beta` and `gamma` are three
* scalars while `x`, `y` and `z` are three vectors. All vectors must belong
* to the same vector space.
*
* @param dst - The destination vector.
* @param alpha - The factor for the vector `x`.
* @param x - A vector.
* @param beta - The factor for the vector `y`.
* @param y - Another vector.
* @param gamma - The factor for the vector `z`.
* @param z - Yet another vector.
*/
extern void
opk_vaxpbypcz(opk_vector* dst,
double alpha, const opk_vector* x,
double beta, const opk_vector* y,
double gamma, const opk_vector* z);
/** @} */
/*---------------------------------------------------------------------------*/
/* OPERATORS */
/**
* @addtogroup Operators
* @{
*/
/** Opaque operator type. This sub-type inherits from `opk_object`. */
typedef struct opk_operator_ opk_operator;
extern opk_status
opk_apply_direct(opk_operator* op, opk_vector* dst,
const opk_vector* src);
extern opk_status
opk_apply_adjoint(opk_operator* op, opk_vector* dst,
const opk_vector* src);
extern opk_status
opk_apply_inverse(opk_operator* op, opk_vector* dst,
const opk_vector* src);
/** @} */
/*---------------------------------------------------------------------------*/
/* ERROR MANAGEMENT */
/**
* @addtogroup Error
* @{
*/
typedef void opk_error_handler(const char* message);
extern opk_error_handler*
opk_get_error_handler(void);
/**
* Set the error handler.
*
* @param handler - The new error handler or NULL to restore the default
* handler.