scs 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +12 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +98 -0
  5. data/ext/scs/extconf.rb +29 -0
  6. data/lib/scs.rb +17 -0
  7. data/lib/scs/ffi.rb +117 -0
  8. data/lib/scs/solver.rb +173 -0
  9. data/lib/scs/version.rb +3 -0
  10. data/vendor/scs/LICENSE.txt +21 -0
  11. data/vendor/scs/Makefile +164 -0
  12. data/vendor/scs/README.md +222 -0
  13. data/vendor/scs/include/aa.h +56 -0
  14. data/vendor/scs/include/cones.h +46 -0
  15. data/vendor/scs/include/ctrlc.h +33 -0
  16. data/vendor/scs/include/glbopts.h +177 -0
  17. data/vendor/scs/include/linalg.h +26 -0
  18. data/vendor/scs/include/linsys.h +64 -0
  19. data/vendor/scs/include/normalize.h +18 -0
  20. data/vendor/scs/include/rw.h +17 -0
  21. data/vendor/scs/include/scs.h +161 -0
  22. data/vendor/scs/include/scs_blas.h +51 -0
  23. data/vendor/scs/include/util.h +65 -0
  24. data/vendor/scs/linsys/amatrix.c +305 -0
  25. data/vendor/scs/linsys/amatrix.h +36 -0
  26. data/vendor/scs/linsys/amatrix.o +0 -0
  27. data/vendor/scs/linsys/cpu/direct/private.c +366 -0
  28. data/vendor/scs/linsys/cpu/direct/private.h +26 -0
  29. data/vendor/scs/linsys/cpu/direct/private.o +0 -0
  30. data/vendor/scs/linsys/cpu/indirect/private.c +256 -0
  31. data/vendor/scs/linsys/cpu/indirect/private.h +31 -0
  32. data/vendor/scs/linsys/cpu/indirect/private.o +0 -0
  33. data/vendor/scs/linsys/external/amd/LICENSE.txt +934 -0
  34. data/vendor/scs/linsys/external/amd/SuiteSparse_config.c +469 -0
  35. data/vendor/scs/linsys/external/amd/SuiteSparse_config.h +254 -0
  36. data/vendor/scs/linsys/external/amd/SuiteSparse_config.o +0 -0
  37. data/vendor/scs/linsys/external/amd/amd.h +400 -0
  38. data/vendor/scs/linsys/external/amd/amd_1.c +180 -0
  39. data/vendor/scs/linsys/external/amd/amd_1.o +0 -0
  40. data/vendor/scs/linsys/external/amd/amd_2.c +1842 -0
  41. data/vendor/scs/linsys/external/amd/amd_2.o +0 -0
  42. data/vendor/scs/linsys/external/amd/amd_aat.c +184 -0
  43. data/vendor/scs/linsys/external/amd/amd_aat.o +0 -0
  44. data/vendor/scs/linsys/external/amd/amd_control.c +64 -0
  45. data/vendor/scs/linsys/external/amd/amd_control.o +0 -0
  46. data/vendor/scs/linsys/external/amd/amd_defaults.c +37 -0
  47. data/vendor/scs/linsys/external/amd/amd_defaults.o +0 -0
  48. data/vendor/scs/linsys/external/amd/amd_dump.c +179 -0
  49. data/vendor/scs/linsys/external/amd/amd_dump.o +0 -0
  50. data/vendor/scs/linsys/external/amd/amd_global.c +16 -0
  51. data/vendor/scs/linsys/external/amd/amd_global.o +0 -0
  52. data/vendor/scs/linsys/external/amd/amd_info.c +119 -0
  53. data/vendor/scs/linsys/external/amd/amd_info.o +0 -0
  54. data/vendor/scs/linsys/external/amd/amd_internal.h +304 -0
  55. data/vendor/scs/linsys/external/amd/amd_order.c +199 -0
  56. data/vendor/scs/linsys/external/amd/amd_order.o +0 -0
  57. data/vendor/scs/linsys/external/amd/amd_post_tree.c +120 -0
  58. data/vendor/scs/linsys/external/amd/amd_post_tree.o +0 -0
  59. data/vendor/scs/linsys/external/amd/amd_postorder.c +206 -0
  60. data/vendor/scs/linsys/external/amd/amd_postorder.o +0 -0
  61. data/vendor/scs/linsys/external/amd/amd_preprocess.c +118 -0
  62. data/vendor/scs/linsys/external/amd/amd_preprocess.o +0 -0
  63. data/vendor/scs/linsys/external/amd/amd_valid.c +92 -0
  64. data/vendor/scs/linsys/external/amd/amd_valid.o +0 -0
  65. data/vendor/scs/linsys/external/amd/changes +11 -0
  66. data/vendor/scs/linsys/external/qdldl/LICENSE +201 -0
  67. data/vendor/scs/linsys/external/qdldl/README.md +120 -0
  68. data/vendor/scs/linsys/external/qdldl/changes +4 -0
  69. data/vendor/scs/linsys/external/qdldl/qdldl.c +298 -0
  70. data/vendor/scs/linsys/external/qdldl/qdldl.h +177 -0
  71. data/vendor/scs/linsys/external/qdldl/qdldl.o +0 -0
  72. data/vendor/scs/linsys/external/qdldl/qdldl_types.h +21 -0
  73. data/vendor/scs/linsys/gpu/gpu.c +41 -0
  74. data/vendor/scs/linsys/gpu/gpu.h +85 -0
  75. data/vendor/scs/linsys/gpu/indirect/private.c +304 -0
  76. data/vendor/scs/linsys/gpu/indirect/private.h +36 -0
  77. data/vendor/scs/scs.mk +181 -0
  78. data/vendor/scs/src/aa.c +224 -0
  79. data/vendor/scs/src/aa.o +0 -0
  80. data/vendor/scs/src/cones.c +802 -0
  81. data/vendor/scs/src/cones.o +0 -0
  82. data/vendor/scs/src/ctrlc.c +77 -0
  83. data/vendor/scs/src/ctrlc.o +0 -0
  84. data/vendor/scs/src/linalg.c +84 -0
  85. data/vendor/scs/src/linalg.o +0 -0
  86. data/vendor/scs/src/normalize.c +93 -0
  87. data/vendor/scs/src/normalize.o +0 -0
  88. data/vendor/scs/src/rw.c +167 -0
  89. data/vendor/scs/src/rw.o +0 -0
  90. data/vendor/scs/src/scs.c +978 -0
  91. data/vendor/scs/src/scs.o +0 -0
  92. data/vendor/scs/src/scs_version.c +5 -0
  93. data/vendor/scs/src/scs_version.o +0 -0
  94. data/vendor/scs/src/util.c +196 -0
  95. data/vendor/scs/src/util.o +0 -0
  96. data/vendor/scs/test/data/small_random_socp +0 -0
  97. data/vendor/scs/test/minunit.h +13 -0
  98. data/vendor/scs/test/problem_utils.h +93 -0
  99. data/vendor/scs/test/problems/rob_gauss_cov_est.h +85 -0
  100. data/vendor/scs/test/problems/small_lp.h +50 -0
  101. data/vendor/scs/test/problems/small_random_socp.h +33 -0
  102. data/vendor/scs/test/random_socp_prob.c +171 -0
  103. data/vendor/scs/test/run_from_file.c +69 -0
  104. data/vendor/scs/test/run_tests +2 -0
  105. data/vendor/scs/test/run_tests.c +32 -0
  106. metadata +203 -0
@@ -0,0 +1,469 @@
1
+ /* ========================================================================== */
2
+ /* === SuiteSparse_config =================================================== */
3
+ /* ========================================================================== */
4
+
5
+ /* SuiteSparse configuration : memory manager and printf functions. */
6
+
7
+ /* Copyright (c) 2013, Timothy A. Davis. No licensing restrictions
8
+ * apply to this file or to the SuiteSparse_config directory.
9
+ * Author: Timothy A. Davis.
10
+ */
11
+
12
+ #include <math.h>
13
+ #include <stdlib.h>
14
+
15
+ #ifndef NPRINT
16
+ #include <stdio.h>
17
+ #endif
18
+
19
+ #ifdef MATLAB_MEX_FILE
20
+ #include "mex.h"
21
+ #include "matrix.h"
22
+ #endif
23
+
24
+ #ifndef NULL
25
+ #define NULL ((void *) 0)
26
+ #endif
27
+
28
+ #include "SuiteSparse_config.h"
29
+
30
+ /* -------------------------------------------------------------------------- */
31
+ /* SuiteSparse_config : a global extern struct */
32
+ /* -------------------------------------------------------------------------- */
33
+
34
+ /* The SuiteSparse_config struct is available to all SuiteSparse functions and
35
+ to all applications that use those functions. It must be modified with
36
+ care, particularly in a multithreaded context. Normally, the application
37
+ will initialize this object once, via SuiteSparse_start, possibily followed
38
+ by application-specific modifications if the applications wants to use
39
+ alternative memory manager functions.
40
+
41
+ The user can redefine these global pointers at run-time to change the
42
+ memory manager and printf function used by SuiteSparse.
43
+
44
+ If -DNMALLOC is defined at compile-time, then no memory-manager is
45
+ specified. You must define them at run-time, after calling
46
+ SuiteSparse_start.
47
+
48
+ If -DPRINT is defined a compile time, then printf is disabled, and
49
+ SuiteSparse will not use printf.
50
+ */
51
+
52
+ struct SuiteSparse_config_struct SuiteSparse_config =
53
+ {
54
+ _scs_malloc, _scs_calloc, _scs_realloc, _scs_free, _scs_printf,
55
+ SuiteSparse_hypot,
56
+ SuiteSparse_divcomplex
57
+
58
+ } ;
59
+
60
+ /* -------------------------------------------------------------------------- */
61
+ /* SuiteSparse_start */
62
+ /* -------------------------------------------------------------------------- */
63
+
64
+ /* All applications that use SuiteSparse should call SuiteSparse_start prior
65
+ to using any SuiteSparse function. Only a single thread should call this
66
+ function, in a multithreaded application. Currently, this function is
67
+ optional, since all this function currently does is to set the four memory
68
+ function pointers to NULL (which tells SuiteSparse to use the default
69
+ functions). In a multi- threaded application, only a single thread should
70
+ call this function.
71
+
72
+ Future releases of SuiteSparse might enforce a requirement that
73
+ SuiteSparse_start be called prior to calling any SuiteSparse function.
74
+ */
75
+
76
+ void SuiteSparse_start ( void )
77
+ {
78
+ SuiteSparse_config.malloc_func = _scs_malloc ;
79
+ SuiteSparse_config.calloc_func = _scs_calloc ;
80
+ SuiteSparse_config.realloc_func = _scs_realloc ;
81
+ SuiteSparse_config.free_func = _scs_free ;
82
+ SuiteSparse_config.printf_func = _scs_printf ;
83
+ /* math functions */
84
+ SuiteSparse_config.hypot_func = SuiteSparse_hypot ;
85
+ SuiteSparse_config.divcomplex_func = SuiteSparse_divcomplex ;
86
+ }
87
+
88
+ /* -------------------------------------------------------------------------- */
89
+ /* SuiteSparse_finish */
90
+ /* -------------------------------------------------------------------------- */
91
+
92
+ /* This currently does nothing, but in the future, applications should call
93
+ SuiteSparse_start before calling any SuiteSparse function, and then
94
+ SuiteSparse_finish after calling the last SuiteSparse function, just before
95
+ exiting. In a multithreaded application, only a single thread should call
96
+ this function.
97
+
98
+ Future releases of SuiteSparse might use this function for any
99
+ SuiteSparse-wide cleanup operations or finalization of statistics.
100
+ */
101
+
102
+ void SuiteSparse_finish ( void )
103
+ {
104
+ /* do nothing */ ;
105
+ }
106
+
107
+ /* -------------------------------------------------------------------------- */
108
+ /* SuiteSparse_malloc: malloc wrapper */
109
+ /* -------------------------------------------------------------------------- */
110
+
111
+ void *SuiteSparse_malloc /* pointer to allocated block of memory */
112
+ (
113
+ size_t nitems, /* number of items to malloc */
114
+ size_t size_of_item /* sizeof each item */
115
+ )
116
+ {
117
+ void *p ;
118
+ size_t size ;
119
+ if (nitems < 1) nitems = 1 ;
120
+ if (size_of_item < 1) size_of_item = 1 ;
121
+ size = nitems * size_of_item ;
122
+
123
+ if (size != ((scs_float) nitems) * size_of_item)
124
+ {
125
+ /* size_t overflow */
126
+ p = NULL ;
127
+ }
128
+ else
129
+ {
130
+ p = (void *) (SuiteSparse_config.malloc_func) (size) ;
131
+ }
132
+ return (p) ;
133
+ }
134
+
135
+
136
+ /* -------------------------------------------------------------------------- */
137
+ /* SuiteSparse_calloc: calloc wrapper */
138
+ /* -------------------------------------------------------------------------- */
139
+
140
+ void *SuiteSparse_calloc /* pointer to allocated block of memory */
141
+ (
142
+ size_t nitems, /* number of items to calloc */
143
+ size_t size_of_item /* sizeof each item */
144
+ )
145
+ {
146
+ void *p ;
147
+ size_t size ;
148
+ if (nitems < 1) nitems = 1 ;
149
+ if (size_of_item < 1) size_of_item = 1 ;
150
+ size = nitems * size_of_item ;
151
+
152
+ if (size != ((scs_float) nitems) * size_of_item)
153
+ {
154
+ /* size_t overflow */
155
+ p = NULL ;
156
+ }
157
+ else
158
+ {
159
+ p = (void *) (SuiteSparse_config.calloc_func) (nitems, size_of_item) ;
160
+ }
161
+ return (p) ;
162
+ }
163
+
164
+ /* -------------------------------------------------------------------------- */
165
+ /* SuiteSparse_realloc: realloc wrapper */
166
+ /* -------------------------------------------------------------------------- */
167
+
168
+ /* If p is non-NULL on input, it points to a previously allocated object of
169
+ size nitems_old * size_of_item. The object is reallocated to be of size
170
+ nitems_new * size_of_item. If p is NULL on input, then a new object of that
171
+ size is allocated. On success, a pointer to the new object is returned,
172
+ and ok is returned as 1. If the allocation fails, ok is set to 0 and a
173
+ pointer to the old (unmodified) object is returned.
174
+ */
175
+
176
+ void *SuiteSparse_realloc /* pointer to reallocated block of memory, or
177
+ to original block if the realloc failed. */
178
+ (
179
+ size_t nitems_new, /* new number of items in the object */
180
+ size_t nitems_old, /* old number of items in the object */
181
+ size_t size_of_item, /* sizeof each item */
182
+ void *p, /* old object to reallocate */
183
+ int *ok /* 1 if successful, 0 otherwise */
184
+ )
185
+ {
186
+ size_t size ;
187
+ if (nitems_old < 1) nitems_old = 1 ;
188
+ if (nitems_new < 1) nitems_new = 1 ;
189
+ if (size_of_item < 1) size_of_item = 1 ;
190
+ size = nitems_new * size_of_item ;
191
+
192
+ if (size != ((scs_float) nitems_new) * size_of_item)
193
+ {
194
+ /* size_t overflow */
195
+ (*ok) = 0 ;
196
+ }
197
+ else if (p == NULL)
198
+ {
199
+ /* a fresh object is being allocated */
200
+ p = SuiteSparse_malloc (nitems_new, size_of_item) ;
201
+ (*ok) = (p != NULL) ;
202
+ }
203
+ else if (nitems_old == nitems_new)
204
+ {
205
+ /* the object does not change; do nothing */
206
+ (*ok) = 1 ;
207
+ }
208
+ else
209
+ {
210
+ /* change the size of the object from nitems_old to nitems_new */
211
+ void *pnew ;
212
+ pnew = (void *) (SuiteSparse_config.realloc_func) (p, size) ;
213
+ if (pnew == NULL)
214
+ {
215
+ if (nitems_new < nitems_old)
216
+ {
217
+ /* the attempt to reduce the size of the block failed, but
218
+ the old block is unchanged. So pretend to succeed. */
219
+ (*ok) = 1 ;
220
+ }
221
+ else
222
+ {
223
+ /* out of memory */
224
+ (*ok) = 0 ;
225
+ }
226
+ }
227
+ else
228
+ {
229
+ /* success */
230
+ p = pnew ;
231
+ (*ok) = 1 ;
232
+ }
233
+ }
234
+ return (p) ;
235
+ }
236
+
237
+ /* -------------------------------------------------------------------------- */
238
+ /* SuiteSparse_free: free wrapper */
239
+ /* -------------------------------------------------------------------------- */
240
+
241
+ void *SuiteSparse_free /* always returns NULL */
242
+ (
243
+ void *p /* block to free */
244
+ )
245
+ {
246
+ if (p)
247
+ {
248
+ (SuiteSparse_config.free_func) (p) ;
249
+ }
250
+ return (NULL) ;
251
+ }
252
+
253
+
254
+ /* -------------------------------------------------------------------------- */
255
+ /* SuiteSparse_tic: return current wall clock time */
256
+ /* -------------------------------------------------------------------------- */
257
+
258
+ /* Returns the number of seconds (tic [0]) and nanoseconds (tic [1]) since some
259
+ * unspecified but fixed time in the past. If no timer is installed, zero is
260
+ * returned. A scalar scs_float precision value for 'tic' could be used, but this
261
+ * might cause loss of precision because clock_getttime returns the time from
262
+ * some distant time in the past. Thus, an array of size 2 is used.
263
+ *
264
+ * The timer is enabled by default. To disable the timer, compile with
265
+ * -DNTIMER. If enabled on a POSIX C 1993 system, the timer requires linking
266
+ * with the -lrt library.
267
+ *
268
+ * example:
269
+ *
270
+ * scs_float tic [2], r, s, t ;
271
+ * SuiteSparse_tic (tic) ; // start the timer
272
+ * // do some work A
273
+ * t = SuiteSparse_toc (tic) ; // t is time for work A, in seconds
274
+ * // do some work B
275
+ * s = SuiteSparse_toc (tic) ; // s is time for work A and B, in seconds
276
+ * SuiteSparse_tic (tic) ; // restart the timer
277
+ * // do some work C
278
+ * r = SuiteSparse_toc (tic) ; // s is time for work C, in seconds
279
+ *
280
+ * A scs_float array of size 2 is used so that this routine can be more easily
281
+ * ported to non-POSIX systems. The caller does not rely on the POSIX
282
+ * <time.h> include file.
283
+ */
284
+
285
+ #ifdef SUITESPARSE_TIMER_ENABLED
286
+
287
+ #include <time.h>
288
+
289
+ void SuiteSparse_tic
290
+ (
291
+ scs_float tic [2] /* output, contents undefined on input */
292
+ )
293
+ {
294
+ /* POSIX C 1993 timer, requires -librt */
295
+ struct timespec t ;
296
+ clock_gettime (CLOCK_MONOTONIC, &t) ;
297
+ tic [0] = (scs_float) (t.tv_sec) ;
298
+ tic [1] = (scs_float) (t.tv_nsec) ;
299
+ }
300
+
301
+ #else
302
+
303
+ void SuiteSparse_tic
304
+ (
305
+ scs_float tic [2] /* output, contents undefined on input */
306
+ )
307
+ {
308
+ /* no timer installed */
309
+ tic [0] = 0 ;
310
+ tic [1] = 0 ;
311
+ }
312
+
313
+ #endif
314
+
315
+
316
+ /* -------------------------------------------------------------------------- */
317
+ /* SuiteSparse_toc: return time since last tic */
318
+ /* -------------------------------------------------------------------------- */
319
+
320
+ /* Assuming SuiteSparse_tic is accurate to the nanosecond, this function is
321
+ * accurate down to the nanosecond for 2^53 nanoseconds since the last call to
322
+ * SuiteSparse_tic, which is sufficient for SuiteSparse (about 104 days). If
323
+ * additional accuracy is required, the caller can use two calls to
324
+ * SuiteSparse_tic and do the calculations differently.
325
+ */
326
+
327
+ scs_float SuiteSparse_toc /* returns time in seconds since last tic */
328
+ (
329
+ scs_float tic [2] /* input, not modified from last call to SuiteSparse_tic */
330
+ )
331
+ {
332
+ scs_float toc [2] ;
333
+ SuiteSparse_tic (toc) ;
334
+ return ((toc [0] - tic [0]) + 1e-9 * (toc [1] - tic [1])) ;
335
+ }
336
+
337
+
338
+ /* -------------------------------------------------------------------------- */
339
+ /* SuiteSparse_time: return current wallclock time in seconds */
340
+ /* -------------------------------------------------------------------------- */
341
+
342
+ /* This function might not be accurate down to the nanosecond. */
343
+
344
+ scs_float SuiteSparse_time /* returns current wall clock time in seconds */
345
+ (
346
+ void
347
+ )
348
+ {
349
+ scs_float toc [2] ;
350
+ SuiteSparse_tic (toc) ;
351
+ return (toc [0] + 1e-9 * toc [1]) ;
352
+ }
353
+
354
+
355
+ /* -------------------------------------------------------------------------- */
356
+ /* SuiteSparse_version: return the current version of SuiteSparse */
357
+ /* -------------------------------------------------------------------------- */
358
+
359
+ int SuiteSparse_version
360
+ (
361
+ int version [3]
362
+ )
363
+ {
364
+ if (version != NULL)
365
+ {
366
+ version [0] = SUITESPARSE_MAIN_VERSION ;
367
+ version [1] = SUITESPARSE_SUB_VERSION ;
368
+ version [2] = SUITESPARSE_SUBSUB_VERSION ;
369
+ }
370
+ return (SUITESPARSE_VERSION) ;
371
+ }
372
+
373
+ /* -------------------------------------------------------------------------- */
374
+ /* SuiteSparse_hypot */
375
+ /* -------------------------------------------------------------------------- */
376
+
377
+ /* There is an equivalent routine called hypot in <math.h>, which conforms
378
+ * to ANSI C99. However, SuiteSparse does not assume that ANSI C99 is
379
+ * available. You can use the ANSI C99 hypot routine with:
380
+ *
381
+ * #include <math.h>
382
+ *i SuiteSparse_config.hypot_func = hypot ;
383
+ *
384
+ * Default value of the SuiteSparse_config.hypot_func pointer is
385
+ * SuiteSparse_hypot, defined below.
386
+ *
387
+ * s = hypot (x,y) computes s = sqrt (x*x + y*y) but does so more accurately.
388
+ * The NaN cases for the scs_float relops x >= y and x+y == x are safely ignored.
389
+ *
390
+ * Source: Algorithm 312, "Absolute value and square root of a complex number,"
391
+ * P. Friedland, Comm. ACM, vol 10, no 10, October 1967, page 665.
392
+ */
393
+
394
+ scs_float SuiteSparse_hypot (scs_float x, scs_float y)
395
+ {
396
+ scs_float s, r ;
397
+ x = fabs (x) ;
398
+ y = fabs (y) ;
399
+ if (x >= y)
400
+ {
401
+ if (x + y == x)
402
+ {
403
+ s = x ;
404
+ }
405
+ else
406
+ {
407
+ r = y / x ;
408
+ s = x * sqrt (1.0 + r*r) ;
409
+ }
410
+ }
411
+ else
412
+ {
413
+ if (y + x == y)
414
+ {
415
+ s = y ;
416
+ }
417
+ else
418
+ {
419
+ r = x / y ;
420
+ s = y * sqrt (1.0 + r*r) ;
421
+ }
422
+ }
423
+ return (s) ;
424
+ }
425
+
426
+ /* -------------------------------------------------------------------------- */
427
+ /* SuiteSparse_divcomplex */
428
+ /* -------------------------------------------------------------------------- */
429
+
430
+ /* c = a/b where c, a, and b are complex. The real and imaginary parts are
431
+ * passed as separate arguments to this routine. The NaN case is ignored
432
+ * for the scs_float relop br >= bi. Returns 1 if the denominator is zero,
433
+ * 0 otherwise.
434
+ *
435
+ * This uses ACM Algo 116, by R. L. Smith, 1962, which tries to avoid
436
+ * underflow and overflow.
437
+ *
438
+ * c can be the same variable as a or b.
439
+ *
440
+ * Default value of the SuiteSparse_config.divcomplex_func pointer is
441
+ * SuiteSparse_divcomplex.
442
+ */
443
+
444
+ int SuiteSparse_divcomplex
445
+ (
446
+ scs_float ar, scs_float ai, /* real and imaginary parts of a */
447
+ scs_float br, scs_float bi, /* real and imaginary parts of b */
448
+ scs_float *cr, scs_float *ci /* real and imaginary parts of c */
449
+ )
450
+ {
451
+ scs_float tr, ti, r, den ;
452
+ if (fabs (br) >= fabs (bi))
453
+ {
454
+ r = bi / br ;
455
+ den = br + r * bi ;
456
+ tr = (ar + ai * r) / den ;
457
+ ti = (ai - ar * r) / den ;
458
+ }
459
+ else
460
+ {
461
+ r = br / bi ;
462
+ den = r * br + bi ;
463
+ tr = (ar * r + ai) / den ;
464
+ ti = (ai * r - ar) / den ;
465
+ }
466
+ *cr = tr ;
467
+ *ci = ti ;
468
+ return (den == 0.) ;
469
+ }