• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

starwing / amoeba / 17343865714

30 Aug 2025 12:38PM UTC coverage: 99.44% (-0.6%) from 100.0%
17343865714

push

github

starwing
Migrated to Github action

1066 of 1072 relevant lines covered (99.44%)

46405.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.8
/test.c
1
#define AM_IMPLEMENTATION
2
#include "amoeba.h"
3

4
#include <assert.h>
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <setjmp.h>
8
#include <stdarg.h>
9

10
static jmp_buf jbuf;
11
static size_t allmem = 0;
12
static size_t maxmem = 0;
13
static void *END = NULL;
14

15
static void *debug_allocf(void *ud, void *ptr, size_t ns, size_t os) {
14,392✔
16
    void *newptr = NULL;
17
    (void)ud;
18
    allmem += ns;
14,392✔
19
    allmem -= os;
14,392✔
20
    if (maxmem < allmem) maxmem = allmem;
14,392✔
21
    if (ns == 0) free(ptr);
14,392✔
22
    else {
23
        newptr = realloc(ptr, ns);
7,196✔
24
        if (newptr == NULL) longjmp(jbuf, 1);
7,196✔
25
    }
26
#ifdef DEBUG_MEMORY
27
    printf("new(%p):\t+%d, old(%p):\t-%d\n", newptr, (int)ns, ptr, (int)os);
28
#endif
29
    return newptr;
14,392✔
30
}
31

32
static void *null_allocf(void *ud, void *ptr, size_t ns, size_t os)
1✔
33
{ (void)ud, (void)ptr, (void)ns, (void)os; return NULL; }
1✔
34

35
static void am_dumpkey(am_Symbol sym) {
389✔
36
    int ch = 'v';
37
    switch (sym.type) {
389✔
38
    case AM_EXTERNAL: ch = 'v'; break;
39
    case AM_SLACK:    ch = 's'; break;
40
    case AM_ERROR:    ch = 'e'; break;
41
    case AM_DUMMY:    ch = 'd'; break;
42
    }
43
    printf("%c%d", ch, (int)sym.id);
389✔
44
}
389✔
45

46
static void am_dumprow(const am_Row *row) {
141✔
47
    am_Iterator it = am_itertable(&row->terms);
141✔
48
    printf("%g", row->constant);
141✔
49
    while (am_nextentry(&it)) {
426✔
50
        am_Num *term = am_val(am_Num,it);
285✔
51
        am_Num multiplier = *term;
285✔
52
        printf(" %c ", multiplier > 0.0 ? '+' : '-');
285✔
53
        if (multiplier < 0.0) multiplier = -multiplier;
285✔
54
        if (!am_approx(multiplier, 1.0f))
285✔
55
            printf("%g*", multiplier);
56
        am_dumpkey(it.key);
285✔
57
    }
58
    printf("\n");
59
}
141✔
60

61
static void am_dumpsolver(am_Solver *solver) {
37✔
62
    am_Iterator it = am_itertable(&solver->rows);
37✔
63
    int idx = 0;
64
    printf("-------------------------------\n");
65
    printf("solver: ");
66
    am_dumprow(&solver->objective);
37✔
67
    printf("rows(%d):\n", solver->rows.count);
37✔
68
    while (am_nextentry(&it)) {
141✔
69
        printf("%d. ", ++idx);
104✔
70
        am_dumpkey(it.key);
104✔
71
        printf(" = ");
72
        am_dumprow(am_val(am_Row,it));
104✔
73
    }
74
    printf("-------------------------------\n");
75
}
37✔
76

77
static am_Constraint* new_constraint(am_Solver* in_solver, double in_strength,
16✔
78
        am_Id in_term1, double in_factor1, int in_relation,
79
        double in_constant, ...)
80
{
81
    int result;
82
    va_list argp;
83
    am_Constraint* c;
84
    assert(in_solver && in_term1);
16✔
85
    c = am_newconstraint(in_solver, (am_Num)in_strength);
16✔
86
    if(!c) return 0;
16✔
87
    am_addterm(c, in_term1, (am_Num)in_factor1);
16✔
88
    am_setrelation(c, in_relation);
16✔
89
    if(in_constant) am_addconstant(c, (am_Num)in_constant);
16✔
90
    va_start(argp, in_constant);
16✔
91
    while(1) {
14✔
92
        am_Id va_term = va_arg(argp, am_Id);
30✔
93
        double va_factor = va_arg(argp, double);
30✔
94
        if(va_term == 0) break;
30✔
95
        am_addterm(c, va_term, (am_Num)va_factor);
14✔
96
    }
97
    va_end(argp);
16✔
98
    result = am_add(c);
16✔
99
    assert(result == AM_OK);
16✔
100
    return c;
101
}
102

103
static void test_all(void) {
1✔
104
    am_Solver *solver;
105
    am_Id xl, xm, xr, xd;
106
    am_Num vxl, vxm, vxr, vxd;
107
    am_Constraint *c1, *c2, *c3, *c4, *c5, *c6;
108
    int ret = setjmp(jbuf);
1✔
109
    printf("\n\n==========\ntest all\n");
110
    printf("ret = %d\n", ret);
111
    if (ret < 0) { perror("setjmp"); return; }
1✔
112
    else if (ret != 0) { printf("out of memory!\n"); return; }
1✔
113

114
    solver = am_newsolver(null_allocf, NULL);
1✔
115
    assert(solver == NULL);
1✔
116

117
    solver = am_newsolver(NULL, NULL);
1✔
118
    assert(solver != NULL);
1✔
119
    am_delsolver(solver);
1✔
120

121
    solver = am_newsolver(debug_allocf, NULL);
1✔
122
    xl = am_newvariable(solver, &vxl);
1✔
123
    xm = am_newvariable(solver, &vxm);
1✔
124
    xr = am_newvariable(solver, &vxr);
1✔
125

126
    assert(!am_hasedit(solver, 0));
1✔
127
    assert(!am_hasedit(solver, xl));
1✔
128
    assert(!am_hasedit(solver, xm));
1✔
129
    assert(!am_hasedit(solver, xr));
1✔
130
    assert(!am_hasconstraint(NULL));
131

132
    xd = am_newvariable(solver, &vxd);
1✔
133
    am_delvariable(solver, xd);
1✔
134

135
    assert(am_setrelation(NULL, AM_GREATEQUAL) == AM_FAILED);
136

137
    c1 = am_newconstraint(solver, AM_REQUIRED);
1✔
138
    am_addterm(c1, xl, 1.0);
1✔
139
    am_setrelation(c1, AM_GREATEQUAL);
1✔
140
    ret = am_add(c1);
1✔
141
    assert(ret == AM_OK);
1✔
142
    am_dumpsolver(solver);
1✔
143

144
    assert(am_setrelation(c1, AM_GREATEQUAL) == AM_FAILED);
1✔
145
    assert(am_setstrength(c1, AM_REQUIRED-10) == AM_OK);
1✔
146
    assert(am_setstrength(c1, AM_REQUIRED) == AM_OK);
1✔
147

148
    assert(am_hasconstraint(c1));
×
149
    assert(!am_hasedit(solver, xl));
1✔
150

151
    c2 = am_newconstraint(solver, AM_REQUIRED);
1✔
152
    am_addterm(c2, xl, 1.0);
1✔
153
    am_setrelation(c2, AM_EQUAL);
1✔
154
    ret = am_add(c2);
1✔
155
    assert(ret == AM_OK);
1✔
156
    am_dumpsolver(solver);
1✔
157

158
    am_resetsolver(solver);
1✔
159
    am_delconstraint(c1);
1✔
160
    am_delconstraint(c2);
1✔
161
    am_dumpsolver(solver);
1✔
162

163
    /* c1: 2*xm == xl + xr */
164
    c1 = am_newconstraint(solver, AM_REQUIRED);
1✔
165
    am_addterm(c1, xm, 2.0);
1✔
166
    am_setrelation(c1, AM_EQUAL);
1✔
167
    am_addterm(c1, xl, 1.0);
1✔
168
    am_addterm(c1, xr, 1.0);
1✔
169
    ret = am_add(c1);
1✔
170
    printf("c1: marker=%d other=%d\n", c1->marker.id, c1->other.id);
1✔
171
    assert(c1->marker.type == AM_DUMMY && c1->other.type == AM_EXTERNAL);
1✔
172
    assert(ret == AM_OK);
1✔
173
    am_dumpsolver(solver);
1✔
174

175
    /* c2: xl + 10 <= xr */
176
    c2 = am_newconstraint(solver, AM_REQUIRED);
1✔
177
    am_addterm(c2, xl, 1.0);
1✔
178
    am_addconstant(c2, 10.0);
179
    am_setrelation(c2, AM_LESSEQUAL);
1✔
180
    am_addterm(c2, xr, 1.0);
1✔
181
    ret = am_add(c2);
1✔
182
    printf("c2: marker=%d other=%d\n", c2->marker.id, c2->other.id);
1✔
183
    assert(c2->marker.type == AM_SLACK && c2->other.type == AM_EXTERNAL);
1✔
184
    assert(ret == AM_OK);
1✔
185
    am_dumpsolver(solver);
1✔
186

187
    /* c3: xr <= 100 */
188
    c3 = am_newconstraint(solver, AM_REQUIRED);
1✔
189
    am_addterm(c3, xr, 1.0);
1✔
190
    am_setrelation(c3, AM_LESSEQUAL);
1✔
191
    am_addconstant(c3, 100.0);
192
    ret = am_add(c3);
1✔
193
    printf("c3: marker=%d other=%d\n", c3->marker.id, c3->other.id);
1✔
194
    assert(c3->marker.type == AM_SLACK && c3->other.type == AM_EXTERNAL);
1✔
195
    assert(ret == AM_OK);
1✔
196
    am_dumpsolver(solver);
1✔
197

198
    /* c4: xl >= 0 */
199
    c4 = am_newconstraint(solver, AM_REQUIRED);
1✔
200
    am_addterm(c4, xl, 1.0);
1✔
201
    am_setrelation(c4, AM_GREATEQUAL);
1✔
202
    am_addconstant(c4, 0.0);
203
    ret = am_add(c4);
1✔
204
    printf("c4: marker=%d other=%d\n", c4->marker.id, c4->other.id);
1✔
205
    assert(c4->marker.type == AM_SLACK && c4->other.type == AM_EXTERNAL);
1✔
206
    assert(ret == AM_OK);
1✔
207
    am_dumpsolver(solver);
1✔
208

209
    c5 = am_cloneconstraint(c4, AM_REQUIRED);
1✔
210
    ret = am_add(c5);
1✔
211
    assert(ret == AM_OK);
1✔
212
    am_dumpsolver(solver);
1✔
213
    am_remove(c5);
1✔
214

215
    c5 = am_newconstraint(solver, AM_REQUIRED);
1✔
216
    am_addterm(c5, xl, 1.0);
1✔
217
    am_setrelation(c5, AM_EQUAL);
1✔
218
    am_addconstant(c5, 0.0);
219
    ret = am_add(c5);
1✔
220
    assert(ret == AM_OK);
1✔
221

222
    c6 = am_cloneconstraint(c4, AM_REQUIRED);
1✔
223
    ret = am_add(c6);
1✔
224
    assert(ret == AM_OK);
1✔
225
    am_dumpsolver(solver);
1✔
226

227
    am_resetconstraint(c6);
1✔
228
    am_delconstraint(c6);
1✔
229

230
    am_remove(c1);
1✔
231
    am_remove(c2);
1✔
232
    am_remove(c3);
1✔
233
    am_remove(c4);
1✔
234
    am_dumpsolver(solver);
1✔
235
    ret |= am_add(c4);
1✔
236
    ret |= am_add(c3);
1✔
237
    ret |= am_add(c2);
1✔
238
    ret |= am_add(c1);
1✔
239
    assert(ret == AM_OK);
1✔
240

241
    am_clearedits(solver);
1✔
242
    am_resetsolver(solver);
1✔
243
    printf("after reset\n");
244

245
    am_dumpsolver(solver);
1✔
246
    ret |= am_add(c1);
1✔
247
    ret |= am_add(c2);
1✔
248
    ret |= am_add(c3);
1✔
249
    ret |= am_add(c4);
1✔
250
    assert(ret == AM_OK);
1✔
251

252
    printf("after initialize\n");
253
    am_dumpsolver(solver);
1✔
254
    am_updatevars(solver);
1✔
255
    printf("xl: %f, xm: %f, xr: %f\n", vxl, vxm, vxr);
1✔
256

257
    am_addedit(solver, xm, AM_MEDIUM);
1✔
258
    am_dumpsolver(solver);
1✔
259
    am_updatevars(solver);
1✔
260
    printf("xl: %f, xm: %f, xr: %f\n", vxl, vxm, vxr);
1✔
261

262
    assert(am_hasedit(solver, xm));
1✔
263
    am_clearedits(solver);
1✔
264

265
    printf("suggest to 0.0\n");
266
    am_suggest(solver, xm, 0.0);
1✔
267
    am_dumpsolver(solver);
1✔
268
    am_updatevars(solver);
1✔
269
    printf("xl=%f xm=%f xr=%f\n", vxl, vxm, vxr);
1✔
270
    assert(vxl == 0.f && vxm == 5.f && vxr == 10.f);
1✔
271

272
    /* make other as infeasible */
273
    printf("suggest to 100.0\n");
274
    am_suggest(solver, xm, 100.0);
1✔
275
    am_dumpsolver(solver);
1✔
276
    am_updatevars(solver);
1✔
277
    assert(vxl == 90.f && vxm == 95.f && vxr == 100.f);
1✔
278

279
    printf("suggest to 70.0\n");
280
    am_suggest(solver, xm, 70.0);
1✔
281
    am_updatevars(solver);
1✔
282
    am_dumpsolver(solver);
1✔
283
    assert(vxl == 40.f && vxm == 70.f && vxr == 100.f);
1✔
284

285
    printf("restore xr to 10.0\n");
286
    am_suggest(solver, xr, 10.0);
1✔
287
    am_updatevars(solver);
1✔
288
    am_dumpsolver(solver);
1✔
289
    assert(vxl == 0.f && vxm == 5.f && vxr == 10.f);
1✔
290
    am_deledit(solver, xr);
1✔
291

292
    printf("suggest to 60.0\n");
293
    am_suggest(solver, xm, 60.0);
1✔
294
    am_updatevars(solver);
1✔
295
    am_dumpsolver(solver);
1✔
296
    assert(vxl == 55.f && vxm == 60.f && vxr == 65.f);
1✔
297

298
    printf("suggest to 50.0\n");
299
    am_suggest(solver, xm, 50.0);
1✔
300
    am_updatevars(solver);
1✔
301
    am_dumpsolver(solver);
1✔
302
    assert(vxl == 45.f && vxm == 50.f && vxr == 55.f);
1✔
303

304
    printf("suggest to 40.0\n");
305
    am_suggest(solver, xm, 40.0);
1✔
306
    am_updatevars(solver);
1✔
307
    am_dumpsolver(solver);
1✔
308
    assert(vxl == 35.f && vxm == 40.f && vxr == 45.f);
1✔
309

310
    am_deledit(solver, xm);
1✔
311
    am_updatevars(solver);
1✔
312
    am_dumpsolver(solver);
1✔
313

314
    printf("xl: %f, xm: %f, xr: %f\n", vxl, vxm, vxr);
1✔
315

316
    /* test dead vars */
317
    assert(am_refcount(solver, xm) == 2); /* xm & c1 */
1✔
318
    am_suggest(solver, xm, 50);
1✔
319
    assert(am_refcount(solver, xm) == 4); /* xm & c1 & edit & dirty */
1✔
320
    am_deledit(solver, xm); 
1✔
321
    assert(am_refcount(solver, xm) == 3); /* xm & c1 & dirty */
1✔
322
    am_delvariable(solver, xm);
1✔
323
    assert(am_refcount(solver, xm) == 2); /* c1 & dirty */
1✔
324
    am_delconstraint(c1);
1✔
325
    assert(am_refcount(solver, xm) == 1); /* dirty */
1✔
326
    am_updatevars(solver);
1✔
327
    am_dumpsolver(solver);
1✔
328

329
    am_delsolver(solver);
1✔
330
    printf("allmem = %d\n", (int)allmem);
1✔
331
    printf("maxmem = %d\n", (int)maxmem);
1✔
332
    assert(allmem == 0);
1✔
333
    maxmem = 0;
1✔
334
}
335

336
static void test_binarytree(void) {
1✔
337
    const int NUM_ROWS = 9;
338
    const int X_OFFSET = 0;
339
    int nPointsCount, nResult, nRow;
340
    int nCurrentRowPointsCount = 1;
341
    int nCurrentRowFirstPointIndex = 0;
342
    am_Constraint *pC;
343
    am_Solver *pSolver;
344
    am_Id *arrX, *arrY;
345
    am_Num *numX, *numY;
346

347
    printf("\n\n==========\ntest binarytree\n");
348
    arrX = (am_Id*)malloc(2048 * sizeof(am_Id));
1✔
349
    if (arrX == NULL) return;
1✔
350
    arrY = arrX + 1024;
1✔
351

352
    numX = (am_Num*)malloc(2048 * sizeof(am_Num));
1✔
353
    if (numX == NULL) return;
1✔
354
    numY = numX + 1024;
1✔
355

356
    /* Create set of rules to distribute vertexes of a binary tree like this one:
357
     *      0
358
     *     / \
359
     *    /   \
360
     *   1     2
361
     *  / \   / \
362
     * 3   4 5   6
363
     */
364

365
    pSolver = am_newsolver(debug_allocf, NULL);
1✔
366

367
    /* Xroot=500, Yroot=10 */
368
    arrX[0] = am_newvariable(pSolver, &numX[0]);
1✔
369
    arrY[0] = am_newvariable(pSolver, &numY[0]);
1✔
370
    am_addedit(pSolver, arrX[0], AM_STRONG);
1✔
371
    am_addedit(pSolver, arrY[0], AM_STRONG);
1✔
372
    am_suggest(pSolver, arrX[0], 500.0f + X_OFFSET);
1✔
373
    am_suggest(pSolver, arrY[0], 10.0f);
1✔
374

375
    for (nRow = 1; nRow < NUM_ROWS; nRow++) {
9✔
376
        int nPreviousRowFirstPointIndex = nCurrentRowFirstPointIndex;
377
        int nPoint, nParentPoint = 0;
378
        nCurrentRowFirstPointIndex += nCurrentRowPointsCount;
8✔
379
        nCurrentRowPointsCount *= 2;
8✔
380

381
        for (nPoint = 0; nPoint < nCurrentRowPointsCount; nPoint++) {
518✔
382
            int nIndex = nCurrentRowFirstPointIndex + nPoint;
510✔
383
            arrX[nIndex] = am_newvariable(pSolver, &numX[nIndex]);
510✔
384
            arrY[nIndex] = am_newvariable(pSolver, &numY[nIndex]);
510✔
385

386
            /* Ycur = Yprev_row + 15 */
387
            pC = am_newconstraint(pSolver, AM_REQUIRED);
510✔
388
            am_addterm(pC, arrY[nCurrentRowFirstPointIndex + nPoint], 1.0);
510✔
389
            am_setrelation(pC, AM_EQUAL);
510✔
390
            am_addterm(pC, arrY[nCurrentRowFirstPointIndex - 1], 1.0);
510✔
391
            am_addconstant(pC, 15.0);
392
            nResult = am_add(pC);
510✔
393
            assert(nResult == AM_OK);
510✔
394

395
            if (nPoint > 0) {
510✔
396
                /* Xcur >= XPrev + 5 */
397
                pC = am_newconstraint(pSolver, AM_REQUIRED);
502✔
398
                am_addterm(pC, arrX[nCurrentRowFirstPointIndex + nPoint], 1.0);
502✔
399
                am_setrelation(pC, AM_GREATEQUAL);
502✔
400
                am_addterm(pC, arrX[nCurrentRowFirstPointIndex + nPoint - 1], 1.0);
502✔
401
                am_addconstant(pC, 5.0);
402
                nResult = am_add(pC);
502✔
403
                assert(nResult == AM_OK);
502✔
404
            } else {
405
                /* When these lines added it crashes at the line 109 */
406
                pC = am_newconstraint(pSolver, AM_REQUIRED);
8✔
407
                am_addterm(pC, arrX[nCurrentRowFirstPointIndex + nPoint], 1.0);
8✔
408
                am_setrelation(pC, AM_GREATEQUAL);
8✔
409
                am_addconstant(pC, 0.0);
410
                nResult = am_add(pC);
8✔
411
                assert(nResult == AM_OK);
8✔
412
            }
413

414
            if ((nPoint % 2) == 1) {
510✔
415
                /* Xparent = 0.5 * Xcur + 0.5 * Xprev */
416
                pC = am_newconstraint(pSolver, AM_REQUIRED);
255✔
417
                am_addterm(pC, arrX[nPreviousRowFirstPointIndex + nParentPoint], 1.0);
255✔
418
                am_setrelation(pC, AM_EQUAL);
255✔
419
                am_addterm(pC, arrX[nCurrentRowFirstPointIndex + nPoint], 0.5);
255✔
420
                am_addterm(pC, arrX[nCurrentRowFirstPointIndex + nPoint - 1], 0.5);
255✔
421
                /* It crashes here (at the 3rd call of am_add(...))!  */
422
                nResult = am_add(pC);
255✔
423
                assert(nResult == AM_OK);
255✔
424

425
                nParentPoint++;
255✔
426
            }
427
        }
428
    }
429
    nPointsCount = nCurrentRowFirstPointIndex + nCurrentRowPointsCount;
430
    (void)nPointsCount;
431

432
    /*{
433
        int i;
434
        for (i = 0; i < nPointsCount; i++)
435
            printf("Point %d: (%f, %f)\n", i,
436
                    am_value(arrX[i]), am_value(arrY[i]));
437
    }*/
438

439
    am_delsolver(pSolver);
1✔
440
    printf("allmem = %d\n", (int)allmem);
1✔
441
    printf("maxmem = %d\n", (int)maxmem);
1✔
442
    assert(allmem == 0);
1✔
443
    free(arrX);
1✔
444
    maxmem = 0;
1✔
445
}
446

447
static void test_unbounded(void) {
1✔
448
    am_Solver *solver;
449
    am_Id x, y;
450
    am_Num vx, vy;
451
    am_Constraint *c;
452
    int ret = setjmp(jbuf);
1✔
453
    printf("\n\n==========\ntest unbounded\n");
454
    printf("ret = %d\n", ret);
455
    if (ret < 0) { perror("setjmp"); return; }
1✔
456
    else if (ret != 0) { printf("out of memory!\n"); return; }
1✔
457

458
    solver = am_newsolver(debug_allocf, NULL);
1✔
459
    x = am_newvariable(solver, &vx);
1✔
460
    y = am_newvariable(solver, &vy);
1✔
461

462
    /* 10.0 == 0.0 */
463
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
464
    am_addconstant(c, 10.0);
465
    am_setrelation(c, AM_EQUAL);
1✔
466
    ret = am_add(c);
1✔
467
    printf("ret = %d\n", ret);
468
    assert(ret == AM_UNSATISFIED);
1✔
469
    am_dumpsolver(solver);
1✔
470

471
    /* 0.0 == 0.0 */
472
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
473
    am_addconstant(c, 0.0);
474
    am_setrelation(c, AM_EQUAL);
1✔
475
    ret = am_add(c);
1✔
476
    printf("ret = %d\n", ret);
477
    assert(ret == AM_OK);
1✔
478
    am_dumpsolver(solver);
1✔
479

480
    am_resetsolver(solver);
1✔
481

482
    /* x >= 10.0 */
483
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
484
    ret = am_addterm(c, x, 1.0);
1✔
485
    printf("addterm = %d\n", ret);
486
    assert(ret == AM_OK);
1✔
487
    am_setrelation(c, AM_GREATEQUAL);
1✔
488
    am_addconstant(c, 10.0);
489
    ret = am_add(c);
1✔
490
    printf("ret = %d\n", ret);
491
    assert(ret == AM_OK);
1✔
492
    am_dumpsolver(solver);
1✔
493

494
    /* x == 2*y */
495
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
496
    am_addterm(c, x, 1.0);
1✔
497
    am_setrelation(c, AM_EQUAL);
1✔
498
    am_addterm(c, y, 2.0);
1✔
499
    ret = am_add(c);
1✔
500
    printf("ret = %d\n", ret);
501
    assert(ret == AM_OK);
1✔
502
    am_dumpsolver(solver);
1✔
503

504
    /* y == 3*x */
505
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
506
    am_addterm(c, y, 1.0);
1✔
507
    am_setrelation(c, AM_EQUAL);
1✔
508
    am_addterm(c, x, 3.0);
1✔
509
    ret = am_add(c);
1✔
510
    printf("ret = %d\n", ret);
511
    assert(ret == AM_UNBOUND);
1✔
512
    am_dumpsolver(solver);
1✔
513

514
    am_resetsolver(solver);
1✔
515

516
    /* x >= 10.0 */
517
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
518
    am_addterm(c, x, 1.0);
1✔
519
    am_setrelation(c, AM_GREATEQUAL);
1✔
520
    am_addconstant(c, 10.0);
521
    ret = am_add(c);
1✔
522
    printf("ret = %d\n", ret);
523
    assert(ret == AM_OK);
1✔
524
    am_dumpsolver(solver);
1✔
525

526
    /* x <= 0.0 */
527
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
528
    am_addterm(c, x, 1.0);
1✔
529
    am_setrelation(c, AM_LESSEQUAL);
1✔
530
    ret = am_add(c);
1✔
531
    printf("ret = %d\n", ret);
532
    assert(ret == AM_UNBOUND);
1✔
533
    am_dumpsolver(solver);
1✔
534

535
    printf("x: %f\n", vx);
1✔
536

537
    am_resetsolver(solver);
1✔
538

539
    /* x == 10.0 */
540
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
541
    am_addterm(c, x, 1.0);
1✔
542
    am_setrelation(c, AM_EQUAL);
1✔
543
    am_addconstant(c, 10.0);
544
    ret = am_add(c);
1✔
545
    printf("ret = %d\n", ret);
546
    assert(ret == AM_OK);
1✔
547
    am_dumpsolver(solver);
1✔
548

549
    /* x == 20.0 */
550
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
551
    am_addterm(c, x, 1.0);
1✔
552
    am_setrelation(c, AM_EQUAL);
1✔
553
    am_addconstant(c, 20.0);
554
    ret = am_add(c);
1✔
555
    printf("ret = %d\n", ret);
556
    assert(ret == AM_UNSATISFIED);
1✔
557
    am_dumpsolver(solver);
1✔
558

559
    /* x == 10.0 */
560
    c = am_newconstraint(solver, AM_REQUIRED);
1✔
561
    am_addterm(c, x, 1.0);
1✔
562
    am_setrelation(c, AM_EQUAL);
1✔
563
    am_addconstant(c, 10.0);
564
    ret = am_add(c);
1✔
565
    printf("ret = %d\n", ret);
566
    assert(ret == AM_OK);
1✔
567
    am_dumpsolver(solver);
1✔
568

569
    am_delsolver(solver);
1✔
570
    printf("allmem = %d\n", (int)allmem);
1✔
571
    printf("maxmem = %d\n", (int)maxmem);
1✔
572
    assert(allmem == 0);
1✔
573
    maxmem = 0;
1✔
574
}
575

576
static void test_strength(void) {
1✔
577
    am_Solver *solver;
578
    am_Id x, y;
579
    am_Num vx, vy;
580
    am_Constraint *c;
581
    int ret = setjmp(jbuf);
1✔
582
    printf("\n\n==========\ntest strength\n");
583
    printf("ret = %d\n", ret);
584
    if (ret < 0) { perror("setjmp"); return; }
1✔
585
    else if (ret != 0) { printf("out of memory!\n"); return; }
1✔
586

587
    solver = am_newsolver(debug_allocf, NULL);
1✔
588
    am_autoupdate(solver, 1);
589
    x = am_newvariable(solver, &vx);
1✔
590
    y = am_newvariable(solver, &vy);
1✔
591

592
    /* x <= y */
593
    new_constraint(solver, AM_STRONG, x, 1.0, AM_LESSEQUAL, 0.0,
1✔
594
            y, 1.0, END);
595
    new_constraint(solver, AM_MEDIUM, x, 1.0, AM_EQUAL, 50, END);
1✔
596
    c = new_constraint(solver, AM_MEDIUM-10, y, 1.0, AM_EQUAL, 40, END);
1✔
597
    printf("%f, %f\n", vx, vy);
1✔
598
    assert(vx == 50);
1✔
599
    assert(vy == 50);
1✔
600

601
    am_setstrength(c, AM_MEDIUM+10);
1✔
602
    printf("%f, %f\n", vx, vy);
1✔
603
    assert(vx == 40);
1✔
604
    assert(vy == 40);
1✔
605

606
    am_setstrength(c, AM_MEDIUM-10);
1✔
607
    printf("%f, %f\n", vx, vy);
1✔
608
    assert(vx == 50);
1✔
609
    assert(vy == 50);
1✔
610

611
    am_delsolver(solver);
1✔
612
    printf("allmem = %d\n", (int)allmem);
1✔
613
    printf("maxmem = %d\n", (int)maxmem);
1✔
614
    assert(allmem == 0);
1✔
615
    maxmem = 0;
1✔
616
}
617

618
static void test_suggest(void) {
1✔
619
#if 1
620
    /* This should be valid but fails the (enter.id != 0) assertion in am_dual_optimize() */
621
    am_Num strength1 = AM_REQUIRED;
622
    am_Num strength2 = AM_REQUIRED;
623
    am_Num width = 76;
624
#else
625
    /* This mostly works, but still insists on forcing left_child_l = 0 which it should not */
626
    am_Num strength1 = AM_STRONG;
627
    am_Num strength2 = AM_WEAK;
628
    am_Num width = 76;
629
#endif
630
    am_Num delta = 0;
631
    am_Num pos;
632
    am_Solver *solver;
633
    am_Id splitter_l,     splitter_w,     splitter_r;
634
    am_Id left_child_l,   left_child_w,   left_child_r;
635
    am_Id splitter_bar_l, splitter_bar_w, splitter_bar_r;
636
    am_Id right_child_l,  right_child_w,  right_child_r;
637
    am_Num vsplitter_l,     vsplitter_w,     vsplitter_r;
638
    am_Num vleft_child_l,   vleft_child_w,   vleft_child_r;
639
    am_Num vsplitter_bar_l, vsplitter_bar_w, vsplitter_bar_r;
640
    am_Num vright_child_l,  vright_child_w,  vright_child_r;
641
    int ret = setjmp(jbuf);
1✔
642
    printf("\n\n==========\ntest suggest\n");
643
    printf("ret = %d\n", ret);
644
    if (ret < 0) { perror("setjmp"); return; }
1✔
645
    else if (ret != 0) { printf("out of memory!\n"); return; }
1✔
646

647
    solver = am_newsolver(debug_allocf, NULL);
1✔
648
    splitter_l     = am_newvariable(solver, &vsplitter_l);
1✔
649
    splitter_w     = am_newvariable(solver, &vsplitter_w);
1✔
650
    splitter_r     = am_newvariable(solver, &vsplitter_r);
1✔
651
    left_child_l   = am_newvariable(solver, &vleft_child_l);
1✔
652
    left_child_w   = am_newvariable(solver, &vleft_child_w);
1✔
653
    left_child_r   = am_newvariable(solver, &vleft_child_r);
1✔
654
    splitter_bar_l = am_newvariable(solver, &vsplitter_bar_l);
1✔
655
    splitter_bar_w = am_newvariable(solver, &vsplitter_bar_w);
1✔
656
    splitter_bar_r = am_newvariable(solver, &vsplitter_bar_r);
1✔
657
    right_child_l  = am_newvariable(solver, &vright_child_l);
1✔
658
    right_child_w  = am_newvariable(solver, &vright_child_w);
1✔
659
    right_child_r  = am_newvariable(solver, &vright_child_r);
1✔
660

661
    /* splitter_r = splitter_l + splitter_w */
662
    /* left_child_r = left_child_l + left_child_w */
663
    /* splitter_bar_r = splitter_bar_l + splitter_bar_w */
664
    /* right_child_r = right_child_l + right_child_w */
665
    new_constraint(solver, AM_REQUIRED, splitter_r, 1.0, AM_EQUAL, 0.0,
1✔
666
            splitter_l, 1.0, splitter_w, 1.0, END);
667
    new_constraint(solver, AM_REQUIRED, left_child_r, 1.0, AM_EQUAL, 0.0,
1✔
668
            left_child_l, 1.0, left_child_w, 1.0, END);
669
    new_constraint(solver, AM_REQUIRED, splitter_bar_r, 1.0, AM_EQUAL, 0.0,
1✔
670
            splitter_bar_l, 1.0, splitter_bar_w, 1.0, END);
671
    new_constraint(solver, AM_REQUIRED, right_child_r, 1.0, AM_EQUAL, 0.0,
1✔
672
            right_child_l, 1.0, right_child_w, 1.0, END);
673

674
    /* splitter_bar_w = 6 */
675
    /* splitter_bar_l >= splitter_l + delta */
676
    /* splitter_bar_r <= splitter_r - delta */
677
    /* left_child_r = splitter_bar_l */
678
    /* right_child_l = splitter_bar_r */
679
    new_constraint(solver, AM_REQUIRED, splitter_bar_w, 1.0, AM_EQUAL, 6.0, END);
1✔
680
    new_constraint(solver, AM_REQUIRED, splitter_bar_l, 1.0, AM_GREATEQUAL,
1✔
681
            delta, splitter_l, 1.0, END);
682
    new_constraint(solver, AM_REQUIRED, splitter_bar_r, 1.0, AM_LESSEQUAL,
1✔
683
            -delta, splitter_r, 1.0, END);
684
    new_constraint(solver, AM_REQUIRED, left_child_r, 1.0, AM_EQUAL, 0.0,
1✔
685
            splitter_bar_l, 1.0, END);
686
    new_constraint(solver, AM_REQUIRED, right_child_l, 1.0, AM_EQUAL, 0.0,
1✔
687
            splitter_bar_r, 1.0, END);
688

689
    /* right_child_r >= splitter_r + 1 */
690
    /* left_child_w = 256 */
691
    new_constraint(solver, strength1, right_child_r, 1.0, AM_GREATEQUAL, 1.0,
1✔
692
            splitter_r, 1.0, END);
693
    new_constraint(solver, strength2, left_child_w, 1.0, AM_EQUAL, 256.0, END);
1✔
694

695
    /* splitter_l = 0 */
696
    /* splitter_r = 76 */
697
    new_constraint(solver, AM_REQUIRED, splitter_l, 1.0, AM_EQUAL, 0.0, END);
1✔
698
    new_constraint(solver, AM_REQUIRED, splitter_r, 1.0, AM_EQUAL, width, END);
1✔
699

700
    printf("\n\n==========\ntest suggest\n");
701
    for(pos = -10; pos < 86; pos++) {
97✔
702
        am_suggest(solver, splitter_bar_l, pos);
96✔
703
        printf("pos: %4g | ", pos);
704
        printf("splitter_l l=%2g, w=%2g, r=%2g | ", vsplitter_l,
96✔
705
                vsplitter_w, vsplitter_r);
706
        printf("left_child_l l=%2g, w=%2g, r=%2g | ", vleft_child_l,
96✔
707
                vleft_child_w, vleft_child_r);
708
        printf("splitter_bar_l l=%2g, w=%2g, r=%2g | ", vsplitter_bar_l,
96✔
709
                vsplitter_bar_w, vsplitter_bar_r);
710
        printf("right_child_l l=%2g, w=%2g, r=%2g | ", vright_child_l,
96✔
711
                vright_child_w, vright_child_r);
712
        printf("\n");
713
    }
714

715
    am_delsolver(solver);
1✔
716
    printf("allmem = %d\n", (int)allmem);
1✔
717
    printf("maxmem = %d\n", (int)maxmem);
1✔
718
    assert(allmem == 0);
1✔
719
    maxmem = 0;
1✔
720
}
721

722
static void test_dirty(void) {
1✔
723
    am_Solver *solver;
724
    am_Id xl, xr, xw, xwc;
725
    am_Num vxl, vxr, vxw, vxwc;
726
    am_Constraint *c1, *c2;
727
    int ret = setjmp(jbuf);
1✔
728
    printf("\n\n==========\ntest dirty\n");
729
    printf("ret = %d\n", ret);
730
    if (ret < 0) { perror("setjmp"); return; }
1✔
731
    else if (ret != 0) { printf("out of memory!\n"); return; }
1✔
732

733
    solver = am_newsolver(debug_allocf, NULL);
1✔
734

735
    xl  = am_newvariable(solver, &vxl);
1✔
736
    xr  = am_newvariable(solver, &vxr);
1✔
737
    xw  = am_newvariable(solver, &vxw);
1✔
738
    xwc = am_newvariable(solver, &vxwc);
1✔
739

740
    /* c1: xw == xr -xl */
741
    c1 = am_newconstraint(solver, AM_REQUIRED);
1✔
742
    ret = 0;
743
    ret |= am_addterm(c1, xw, 1.0);
1✔
744
    ret |= am_setrelation(c1, AM_EQUAL);
1✔
745
    ret |= am_addterm(c1, xr, 1.0);
1✔
746
    ret |= am_addterm(c1, xl, -1.0);
1✔
747
    ret |= am_add(c1);
1✔
748
    assert(ret == AM_OK);
1✔
749

750
    am_updatevars(solver);
1✔
751
    printf("xl: %f, xr:%f, xw:%f\n", vxl, vxr, vxw);
1✔
752

753
    /* c1: xwc == xw */
754
    c2 = am_newconstraint(solver, AM_REQUIRED);
1✔
755
    ret = 0;
756
    ret |= am_addterm(c2, xwc, 1.0);
1✔
757
    ret |= am_setrelation(c2, AM_EQUAL);
1✔
758
    ret |= am_addterm(c2, xw, 1.0);
1✔
759
    ret |= am_add(c2);
1✔
760
    assert(ret == AM_OK);
1✔
761

762
    /* Sets dirty bit? Related to crash. */
763
    am_suggest(solver, xwc, 10);
1✔
764

765
    am_updatevars(solver);
1✔
766
    printf("xl:%f, xr:%f, xw:%f, xwc:%f\n", vxl, vxr, vxw, vxwc);
1✔
767

768
    /* Remove xwc and c2 */
769
    am_deledit(solver, xwc);
1✔
770
    am_remove(c2);
1✔
771
    /* Adding an am_updatevars(solver); here somehow solves the issue. */
772
    am_delconstraint(c2);
1✔
773
    am_delvariable(solver, xwc);
1✔
774

775
    /* Causes crash: amoeba.h:482: am_sym2var: Assertion `ve != NULL' failed. */
776
    am_updatevars(solver);
1✔
777
    printf("xl:%f, xr:%f, xw:%f\n", vxl, vxr, vxw);
1✔
778

779
    /* Manual cleanup */
780
    am_delconstraint(c1);
1✔
781
    am_remove(c1);
1✔
782

783
    am_delvariable(solver, xl);
1✔
784
    am_delvariable(solver, xr);
1✔
785
    am_delvariable(solver, xw);
1✔
786

787
    am_delsolver(solver);
1✔
788
}
789

790
void test_cycling(void) {
1✔
791
    am_Solver *solver;
792
    am_Id va, vb, vc, vd;
793
    am_Num vva, vvb, vvc, vvd;
794

795
    int ret = setjmp(jbuf);
1✔
796
    printf("\n\n==========\ntest cycling\n");
797
    printf("ret = %d\n", ret);
798
    if (ret < 0) { perror("setjmp"); return; }
1✔
799
    else if (ret != 0) { printf("out of memory!\n"); return; }
1✔
800

801
    solver = am_newsolver(debug_allocf, NULL);
1✔
802
    va = am_newvariable(solver, &vva);
1✔
803
    vb = am_newvariable(solver, &vvb);
1✔
804
    vc = am_newvariable(solver, &vvc);
1✔
805
    vd = am_newvariable(solver, &vvd);
1✔
806

807
    am_addedit(solver, va, AM_STRONG);
1✔
808
    printf("after edit\n");
809
    am_dumpsolver(solver);
1✔
810

811
    /* vb == va */
812
    {
813
        am_Constraint * c = am_newconstraint(solver, AM_REQUIRED);
1✔
814
        int ret = 0;
815
        ret |= am_addterm(c, vb, 1.0);
1✔
816
        ret |= am_setrelation(c, AM_EQUAL);
1✔
817
        ret |= am_addterm(c, va, 1.0);
1✔
818
        ret |= am_add(c);
1✔
819
        assert(ret == AM_OK);
1✔
820
        am_dumpsolver(solver);
1✔
821
    }
822

823
    /* vb == vc */
824
    {
825
        am_Constraint * c = am_newconstraint(solver, AM_REQUIRED);
1✔
826
        int ret = 0;
827
        ret |= am_addterm(c, vb, 1.0);
1✔
828
        ret |= am_setrelation(c, AM_EQUAL);
1✔
829
        ret |= am_addterm(c, vc, 1.0);
1✔
830
        ret |= am_add(c);
1✔
831
        assert(ret == AM_OK);
1✔
832
        am_dumpsolver(solver);
1✔
833
    }
834

835
    /* vc == vd */
836
    {
837
        am_Constraint * c = am_newconstraint(solver, AM_REQUIRED);
1✔
838
        int ret = 0;
839
        ret |= am_addterm(c, vc, 1.0);
1✔
840
        ret |= am_setrelation(c, AM_EQUAL);
1✔
841
        ret |= am_addterm(c, vd, 1.0);
1✔
842
        ret |= am_add(c);
1✔
843
        assert(ret == AM_OK);
1✔
844
        am_dumpsolver(solver);
1✔
845
    }
846

847
    /* vd == va */
848
    {
849
        am_Constraint * c = am_newconstraint(solver, AM_REQUIRED);
1✔
850
        int ret = 0;
851
        ret |= am_addterm(c, vd, 1.0);
1✔
852
        ret |= am_setrelation(c, AM_EQUAL);
1✔
853
        ret |= am_addterm(c, va, 1.0);
1✔
854
        ret |= am_add(c);
1✔
855
        assert(ret == AM_OK); /* asserts here */
1✔
856
        am_dumpsolver(solver);
1✔
857
    }
858

859
    am_delsolver(solver);
1✔
860
}
861

862
int main(void) {
1✔
863
    test_binarytree();
1✔
864
    test_unbounded();
1✔
865
    test_strength();
1✔
866
    test_suggest();
1✔
867
    test_cycling();
1✔
868
    test_dirty();
1✔
869
    test_all();
1✔
870
    return 0;
871
}
872

873
/* cc: flags='-ggdb -Wall -fprofile-arcs -ftest-coverage -O2 -Wextra -pedantic -std=c89' */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc