main.cpp 47 KB
Newer Older
Gauthier Quesnel's avatar
2019    
Gauthier Quesnel committed
1
/* Copyright (C) 2016-2019 INRA
Gauthier Quesnel's avatar
Gauthier Quesnel committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * 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.
 */

23
#include <baryonyx/core-out>
24
#include <baryonyx/core-utils>
25

26
27
28
29
#include "main.hpp"

#include <fmt/color.h>
#include <fmt/format.h>
30
#include <fmt/ostream.h>
Gauthier Quesnel's avatar
Gauthier Quesnel committed
31

32
#include <chrono>
Gauthier Quesnel's avatar
Gauthier Quesnel committed
33
#include <fstream>
Gauthier Quesnel's avatar
Gauthier Quesnel committed
34
#include <iomanip>
Gauthier Quesnel's avatar
Gauthier Quesnel committed
35
#include <limits>
36
#include <sstream>
37
38
#include <string>
#include <tuple>
39
#include <utility>
Gauthier Quesnel's avatar
Gauthier Quesnel committed
40

Gauthier Quesnel's avatar
Gauthier Quesnel committed
41
#include <cctype>
Gauthier Quesnel's avatar
Gauthier Quesnel committed
42
#include <cstring>
43

44
#ifndef _WIN32
45
#include <unistd.h>
46
47
#else
#include <windows.h>
48
#endif
Gauthier Quesnel's avatar
Gauthier Quesnel committed
49

50
51
52
53
54
55
56
57
58
59
60
61
62
#ifndef _WIN32
pid_t
get_pid() noexcept
{
    return ::getpid();
}
#else
DWORD
get_pid() noexcept
{
    return ::GetCurrentProcessId();
}
#endif
63

64
65
66
67
68
69
70
71
72
73
74
75
76
77
static void
solver_started_cb(const baryonyx::solver_parameters& params)
{
    fmt::print("Solver starts\n");

    fmt::print(" * Global parameters:\n"
               "  - limit: {}\n"
               "  - time-limit: {:.10g}s\n"
               "  - floating-point-type: {}\n"
               "  - print-level: {}\n"
               "  - auto-tune: {}\n"
               "  - observation: {}\n",
               params.limit,
               params.time_limit,
78
               params.float_type,
79
               params.print_level,
80
81
               params.mode,
               params.observer);
82

83
84
85
86
87
88
89
90
    if (params.solver == baryonyx::solver_parameters::solver_type::bastert) {
        fmt::print(" * In The Middle parameters:\n"
                   "  - preprocessing: {}\n"
                   "  - constraint-order: {}\n"
                   "  - theta: {:.10g}\n"
                   "  - delta: {:.10g}\n"
                   "  - kappa: {:.10g} {:.10g} {:.10g}\n"
                   "  - alpha: {:.10g}\n"
91
                   "  - w: {:.10g}\n"
92
                   "  - norm: {}\n",
93
94
                   params.pre_order,
                   params.order,
95
96
97
98
99
100
101
                   params.theta,
                   params.delta,
                   params.kappa_min,
                   params.kappa_step,
                   params.kappa_max,
                   params.alpha,
                   params.w,
102
                   params.cost_norm);
103
104
105
106
107
108
109
110
111
112
113

        fmt::print(" * Pushes system parameters:\n"
                   "  - pushes-limit: {}\n"
                   "  - pushing-objective-amplifier: {:.10g}\n"
                   "  - pushing-iteration-limit: {}\n"
                   "  - pushing-k-factor: {:.10g}\n",
                   params.pushes_limit,
                   params.pushing_objective_amplifier,
                   params.pushing_iteration_limit,
                   params.pushing_k_factor);

114
        fmt::print(" * Solver initialization parameters:\n"
115
                   "  - init-policy: {}\n"
116
                   "  - init-policy-random: {}\n",
117
                   params.init_policy,
118
                   params.init_policy_random);
119

120
        fmt::print(" * Optimizer initialization parameters:\n"
121
122
123
124
125
126
127
                   "  - init-population-size: {}\n"
                   "  - init-crossover-bastert-insertion: {}\n"
                   "  - init-crossover-solution-selection-mean: {}\n"
                   "  - init-crossover-solution-selection-stddev: {}\n"
                   "  - init-mutation-variable-mean: {}\n"
                   "  - init-mutation-variable-stddev: {}\n"
                   "  - init-mutation-value-mean: {}\n"
128
129
130
131
                   "  - init-mutation-value-stddev: {}\n"
                   "  - init-kappa-improve-start: {}\n"
                   "  - init-kappa-improve-increase: {}\n"
                   "  - init-kappa-improve-stop: {}\n",
132
133
134
135
136
137
138
                   params.init_population_size,
                   params.init_crossover_bastert_insertion,
                   params.init_crossover_solution_selection_mean,
                   params.init_crossover_solution_selection_stddev,
                   params.init_mutation_variable_mean,
                   params.init_mutation_variable_stddev,
                   params.init_mutation_value_mean,
139
140
141
142
                   params.init_mutation_value_stddev,
                   params.init_kappa_improve_start,
                   params.init_kappa_improve_increase,
                   params.init_kappa_improve_stop);
143
144
145
146
    } else {
        fmt::print(" * Random solvers:\n"
                   "  - random: bernouilli with p=0.5\n");
    }
147
148
149
}

static void
150
151
solver_updated_cb(int remaining_constraints,
                  double value,
152
153
154
                  long int loop,
                  double duration,
                  long int reinit_number)
155
{
156
    if (remaining_constraints > 0) {
157
158
159
160
161
162
        fmt::print(
          "  - Constraints remaining: {} (loop: {} t: {}s reinit: {})\n",
          remaining_constraints,
          loop,
          duration,
          reinit_number);
163
    } else {
164
        if (loop >= 0)
165
166
167
168
169
170
            fmt::print(
              "  - Solution found: {:f} (loop: {} t: {}s reinit: {})\n",
              value,
              loop,
              duration,
              reinit_number);
171
        else
172
173
            fmt::print("  - Solution found via push: {:f} (loop: {} t: {}s "
                       "reinit: {})\n",
174
175
                       value,
                       -loop,
176
177
                       duration,
                       reinit_number);
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
    }
}

static void
solver_finished_cb(const baryonyx::result& r)
{
    fmt::print("Solver finished\n");

    switch (r.status) {
    case baryonyx::result_status::success:
        if (r.loop >= 0)
            fmt::print("Best solution found: {:.10g} in {} loop and {}s\n",
                       r.solutions.back().value,
                       r.loop,
                       r.duration);
        else
            fmt::print(
              "Best solution found via push: {:.10g} in {} loop and {}s\n",
              r.solutions.back().value,
              -r.loop,
              r.duration);
        break;
    case baryonyx::result_status::internal_error:
        fmt::print("No solution. Internal error\n");
        break;
    case baryonyx::result_status::uninitialized:
        fmt::print("No solution. Uninitialized error\n");
        break;
    case baryonyx::result_status::kappa_max_reached:
        fmt::print(
          "No solution. Constraint remaining: {}. Kappa reached in {}s.\n",
          r.remaining_constraints,
          r.duration);
        break;
    case baryonyx::result_status::time_limit_reached:
        fmt::print("No solution. Constraint remaining: {}. Time limit reached "
                   "at {}s.\n",
                   r.remaining_constraints,
                   r.duration);
        break;
    case baryonyx::result_status::limit_reached:
        fmt::print("No solution. Constraint remaining: {}. Loop limit reached "
                   "in {}s.\n",
                   r.remaining_constraints,
                   r.duration);
        break;
224
225
226
    case baryonyx::result_status::empty_context:
        fmt::print("Context uninitialized\n");
        break;
227
228
229
    }
}

230
231
232
233
234
235
236
237
238
239
240
241
/**
 * @brief Tries to split the argument between name and value.
 * @details The split consists to return left and right part arround the
 *     characters `=' or `:'.
 *
 * @param param String to split.
 * @return Return left and right part in success, otherwise only the left part
 *     if the splitting characters are not found or an empty tuple if all is
 *     empty.
 */
constexpr static std::tuple<std::string_view, std::string_view>
split_argument(const std::string_view param)
242
{
243
    auto position = param.find_first_of(":=");
244

245
246
247
    if (position == std::string_view::npos) /* If nothing is found, return an
                                               empty tuple.*/
        return {};
248

249
250
    if (position + 1 >= param.size())
        return std::make_tuple(param, std::string_view{});
251

252
253
254
    return std::make_tuple(param.substr(0, position),
                           param.substr(position + 1));
}
255

256
257
258
259
constexpr static bool
starts_with(std::string_view str, std::string_view to_found) noexcept
{
    return !(str.find(to_found));
260
}
261

262
263
struct get_param
{
264
    constexpr get_param(int argc_, const char** argv_)
265
266
267
268
269
      : argv(argv_)
      , argc(argc_)
      , i(0)
    {}

270
271
272
273
    constexpr std::optional<std::string_view> operator()(
      int arg_position,
      const std::string_view longp,
      const std::string_view shortp) noexcept
274
    {
275
276
        std::string_view arg(argv[arg_position]);
        i = arg_position;
277

278
279
280
281
282
283
        if (starts_with(arg, longp) && arg.size() > longp.size() &&
            (arg[longp.size()] == '=' || arg[longp.size()] == ':'))
            return arg.substr(longp.size() + 1);

        if (starts_with(arg, shortp) && arg.size() > shortp.size())
            return arg.substr(shortp.size());
284

285
286
287
        if (arg_position + 1 < argc) {
            if (arg == longp) {
                i = arg_position + 1;
288
289
290
                return argv[i];
            }

291
292
            if (arg == shortp) {
                i = arg_position + 1;
293
294
295
296
                return argv[i];
            }
        }

297
        return std::nullopt;
298
299
300
301
302
303
304
    }

    const char** argv;
    int argc;
    int i;
};

305
306
307
static void
help() noexcept
{
308
309
    fmt::print(
      "Baryonyx v{}.{}.{}", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
310

311
312
    fmt::print(
      "\nGeneral options:\n"
313
314
      "  --help|-h                     This help message\n"
      "  --param|-p [name][:|=][value] Add a new parameter (name is"
315
316
      " [a-z][A-Z]_) value can be a double, an integer otherwise a"
      " string.\n"
317
318
      "  --disable-preprocessing|-np   Disable preprocessing\n"
      "  --optimize|-O                 Optimize model (default "
319
      "feasibility search only)\n"
320
      "  --auto:[manual,nlopt]|-a      Automatic parameters optimization\n"
321
      "  --check filename.sol          Check if the solution is correct."
322
323
      "  --random                      Use the random solver instead of "
      "bastert and wedelin\n"
324
      "\n"
325
      "  --quiet                       Remove any verbose message\n"
326
      "  --verbose|-v int              Set verbose level\n"
Gauthier Quesnel's avatar
Gauthier Quesnel committed
327
328
      "  --bench|-b file_name.csv      Select the bench mode and store in "
      "file_name.csv\n\n"
Gauthier Quesnel's avatar
Gauthier Quesnel committed
329
      "  --debug                       Enable a debug mode\n"
330
331
332
333
334
      "Parameter list for in the middle heuristic\n"
      " * Global parameters"
      "  - limit: integer ]-oo, +oo[ in loop number\n"
      "  - time-limit: real [0, +oo[ in seconds\n"
      "  - floating-point-type: float double longdouble\n"
335
      "  - observer-type: none (default), pnm, file\n"
Gauthier Quesnel's avatar
Gauthier Quesnel committed
336
      "  - storage-type: one bound five\n"
337
338
      "  - print-level: [0, 2]\n"
      " * In The Middle parameters\n"
Gauthier Quesnel's avatar
Gauthier Quesnel committed
339
      "  - preprocessing: none memory less-greater-equal (or any "
340
      "combination), p1, p2, p3, p4\n"
341
      "  - constraint-order: none reversing random-sorting "
342
      "infeasibility-decr infeasibility-incr lagrangian-decr lagrangian-incr "
Gauthier Quesnel's avatar
Gauthier Quesnel committed
343
      "pi-sign-change\n"
344
345
346
347
348
349
350
      "  - theta: real [0, 1]\n"
      "  - delta: real [0, +oo[\n"
      "  - kappa-min: real [0, 1[\n"
      "  - kappa-step: real [0, 1[\n"
      "  - kappa-max: real [0, 1[\n"
      "  - alpha: integer [0, 2]\n"
      "  - w: integer [0, +oo[\n"
351
      "  - norm: l1 l2 loo none random\n"
352
353
354
355
356
357
      " * Pushes system parameters\n"
      "  - pushes-limit: integer [0, +oo[\n"
      "  - pushing-objective-amplifier: real [0, +oo[\n"
      "  - pushing-iteration-limit: integer [0, +oo[\n"
      "  - pushing-k-factor: real [0, +oo[\n"
      " * Initialization parameters\n"
358
      "  - init-policy: bastert pessimistic-solve optimistic-solve cycle\n"
359
360
361
362
363
364
365
366
      "  - init-population-size: integer [5, +oo[\n"
      "  - init-crossover-bastert-insertion:real [0, 1]\n"
      "  - init-crossover-solution-selection-mean:real [0, 1]\n"
      "  - init-crossover-solution-selection-stddev:real [0, 1]\n"
      "  - init-mutation-variable-mean:real [0, 1]\n"
      "  - init-mutation-variable-stddev:real [0, 1]\n"
      "  - init-mutation-value-mean:real [0, 1]\n"
      "  - init-mutation-value-stddev:real [0, 1]\n");
367
368
}

369
370
constexpr static bool
is_equal(std::string_view name, const char* longf, char shortf = '\0')
371
372
373
374
{
    if (name.compare(0, std::string::npos, longf) == 0)
        return true;

375
    if (shortf != '\0' && name.size() == 2 && name[1] == shortf)
376
377
378
379
380
        return true;

    return false;
}

381
382
constexpr static std::optional<double>
assign_0oo(std::string_view value)
383
{
384
    auto result = ::to_double(value);
385

386
387
388
389
    if (result.has_value() && *result > 0)
        return *result;
    else
        return std::nullopt;
390
391
}

392
393
constexpr static std::optional<double>
assign_01(std::string_view value)
394
{
395
    auto result = ::to_double(value);
396

397
398
399
400
    if (result.has_value() && *result >= 0 && *result <= 1)
        return *result;
    else
        return std::nullopt;
401
402
}

403
404
constexpr static std::optional<int>
assign(std::string_view value, int mindef, int maxdef)
405
{
406
    auto result = ::to_int(value);
407

408
409
410
411
    if (result.has_value() && *result >= mindef && *result <= maxdef)
        return result;
    else
        return std::nullopt;
412
413
}

414
415
416
417
418
419
420
421
422
423
424
constexpr static std::optional<long int>
assign(std::string_view value, long int mindef, long int maxdef)
{
    auto result = ::to_long(value);

    if (result.has_value() && *result >= mindef && *result <= maxdef)
        return result;
    else
        return std::nullopt;
}

425
426
constexpr static std::optional<double>
assign_d(std::string_view value, double mindef, double maxdef)
427
{
428
    auto result = ::to_double(value);
429

430
431
432
433
    if (result.has_value() && *result >= mindef && *result <= maxdef)
        return *result;
    else
        return std::nullopt;
434
435
}

436
437
438
439
enum class command_line_status
{
    success,
    unknown,
440
    parameter_missing,
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
    verbose_error,
    limit_error,
    time_limit_error,
    floating_point_type_error,
    observer_type_error,
    print_level_error,
    preprocessing_error,
    constraint_order_error,
    storage_type_error,
    theta_error,
    delta_error,
    kappa_min_error,
    kappa_step_error,
    kappa_max_error,
    alpha_error,
    w_error,
    norm_error,
    pushes_limit_error,
    pushing_objective_amplifier_error,
    pushing_iteration_limit_error,
    pushing_k_factor_error,
462
    init_population_size_error,
463
    init_policy_error,
464
    init_policy_random_error,
465
466
467
468
469
470
471
    init_crossover_bastert_insertion_error,
    init_crossover_solution_selection_mean_error,
    init_crossover_solution_selection_stddev_error,
    init_mutation_variable_mean_error,
    init_mutation_variable_stddev_error,
    init_mutation_value_mean_error,
    init_mutation_value_stddev_error,
472
473
474
    init_kappa_improve_start_error,
    init_kappa_improve_increase_error,
    init_kappa_improve_stop_error,
475
476
477
478
479
480
481
    thread_error,
    seed_error
};

constexpr const std::string_view command_line_status_string[] = {
    "success",
    "unknown",
482
    "parameter_missing",
483
    "verbose"
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
    "limit",
    "time_limit",
    "floating_point_type",
    "observer_type",
    "print_level",
    "preprocessing",
    "constraint_order",
    "storage_type",
    "theta",
    "delta",
    "kappa_min",
    "kappa_step",
    "kappa_max",
    "alpha",
    "w",
    "norm",
    "pushes_limit",
    "pushing_objective_amplifier",
    "pushing_iteration_limit",
    "pushing_k_factor",
504
    "init_population_size",
505
    "init_policy",
506
    "init_policy_random",
507
508
509
510
511
512
513
    "init_crossover_bastert_insertion",
    "init_crossover_solution_selection_mean",
    "init_crossover_solution_selection_stddev",
    "init_mutation_variable_mean",
    "init_mutation_variable_stddev",
    "init_mutation_value_mean",
    "init_mutation_value_stddev",
514
515
516
    "init_kappa_improve_start",
    "init_kappa_improve_increase",
    "init_kappa_improve_stop",
517
518
519
520
    "thread",
    "seed"
};

521
522
523
524
template<typename Integer>
constexpr typename std::make_unsigned<Integer>::type
to_unsigned(Integer value)
{
Gauthier Quesnel's avatar
Gauthier Quesnel committed
525
    assert(value >= 0 && "Signed to unsigned error: negative value");
526
527
528
529
530
531
532
533

    return static_cast<typename std::make_unsigned<Integer>::type>(value);
}

template<typename Integer>
constexpr typename std::make_signed<Integer>::type
to_signed(Integer value)
{
534
535
536
537
538
    assert(static_cast<std::uintmax_t>(value) <
             static_cast<std::uintmax_t>(
               std::numeric_limits<
                 typename std::make_signed<Integer>::type>::max()) &&
           "Unsigned to signed error: too big unsigned");
539
540
541
542

    return static_cast<typename std::make_signed<Integer>::type>(value);
}

543
544
545
546
547
constexpr const std::string_view
to_string(command_line_status s) noexcept
{
    auto x = static_cast<std::underlying_type<command_line_status>::type>(s);

548
    assert(x < to_signed(std::size(command_line_status_string)));
549
550
551
552

    return command_line_status_string[x];
}

553
constexpr static command_line_status
554
assign_parameter(baryonyx::solver_parameters& params,
555
556
                 std::string_view name,
                 std::string_view value)
557
558
{
    if (is_equal(name, "limit", 'l')) {
559
560
        if (auto v = assign(value, -1L, std::numeric_limits<long int>::max());
            !v)
561
            return command_line_status::limit_error;
562
563
        else
            params.limit = *v;
564

565
    } else if (is_equal(name, "time-limit")) {
566
        if (auto v = to_double(value); !v)
567
            return command_line_status::time_limit_error;
568
569
        else
            params.time_limit = *v <= 0.0 ? -1.0 : *v;
570

571
572
573
574
575
576
577
578
    } else if (is_equal(name, "floating-point-type")) {
        if (value == "float")
            params.float_type =
              baryonyx::solver_parameters::floating_point_type::float_type;
        else if (value == "double")
            params.float_type =
              baryonyx::solver_parameters::floating_point_type::double_type;
        else if (value == "longdouble")
579
580
581
            params.float_type = baryonyx::solver_parameters::
              floating_point_type::longdouble_type;
        else
582
583
            return command_line_status::floating_point_type_error;

584
585
586
587
588
589
590
    } else if (is_equal(name, "observer-type")) {
        if (value == "none")
            params.observer = baryonyx::solver_parameters::observer_type::none;
        else if (value == "pnm")
            params.observer = baryonyx::solver_parameters::observer_type::pnm;
        else if (value == "file")
            params.observer = baryonyx::solver_parameters::observer_type::file;
591
        else
592
593
            return command_line_status::observer_type_error;

594
    } else if (is_equal(name, "print-level")) {
595
        if (auto v = assign(value, 0, 2); !v)
596
            return command_line_status::print_level_error;
597
598
        else
            params.print_level = *v;
599

600
601
602
603
    } else if (is_equal(name, "preprocessing")) {
        if (value == "none")
            params.pre_order =
              baryonyx::solver_parameters::pre_constraint_order::none;
604
605
606
607
608
609
610
611
612
613
614
615
616
        else if (value == "memory")
            params.pre_order =
              baryonyx::solver_parameters::pre_constraint_order::memory;
        else if (value == "p1")
            params.pre_order =
              baryonyx::solver_parameters::pre_constraint_order::p1;
        else if (value == "p2")
            params.pre_order =
              baryonyx::solver_parameters::pre_constraint_order::p2;
        else if (value == "p3")
            params.pre_order =
              baryonyx::solver_parameters::pre_constraint_order::p3;
        else if (value == "p4")
617
            params.pre_order =
618
              baryonyx::solver_parameters::pre_constraint_order::p4;
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
        else if (value == "less-greater-equal")
            params.pre_order = baryonyx::solver_parameters::
              pre_constraint_order::less_greater_equal;
        else if (value == "less-equal-greater")
            params.pre_order = baryonyx::solver_parameters::
              pre_constraint_order::less_equal_greater;
        else if (value == "greater-less-equal")
            params.pre_order = baryonyx::solver_parameters::
              pre_constraint_order::greater_less_equal;
        else if (value == "greater-equal-less")
            params.pre_order = baryonyx::solver_parameters::
              pre_constraint_order::greater_equal_less;
        else if (value == "equal-less-greater")
            params.pre_order = baryonyx::solver_parameters::
              pre_constraint_order::equal_less_greater;
        else if (value == "equal-greater-less")
            params.pre_order = baryonyx::solver_parameters::
              pre_constraint_order::equal_greater_less;
637
        else
638
639
            return command_line_status::preprocessing_error;

640
641
642
643
644
645
    } else if (is_equal(name, "constraint-order")) {
        if (value == "none")
            params.order = baryonyx::solver_parameters::constraint_order::none;
        else if (value == "reversing")
            params.order =
              baryonyx::solver_parameters::constraint_order::reversing;
646
        else if (value == "random-sorting")
647
648
            params.order =
              baryonyx::solver_parameters::constraint_order::random_sorting;
649
        else if (value == "infeasibility-decr")
650
651
            params.order = baryonyx::solver_parameters::constraint_order::
              infeasibility_decr;
652
        else if (value == "infeasibility-incr")
653
654
            params.order = baryonyx::solver_parameters::constraint_order::
              infeasibility_incr;
655
656
657
658
659
660
        else if (value == "lagrangian-decr")
            params.order =
              baryonyx::solver_parameters::constraint_order::lagrangian_decr;
        else if (value == "lagrangian-incr")
            params.order =
              baryonyx::solver_parameters::constraint_order::lagrangian_incr;
661
662
663
        else if (value == "pi-sign-change")
            params.order =
              baryonyx::solver_parameters::constraint_order::pi_sign_change;
664
665
666
        else if (value == "cycle")
            params.order =
              baryonyx::solver_parameters::constraint_order::cycle;
667
        else
668
669
            return command_line_status::constraint_order_error;

Gauthier Quesnel's avatar
Gauthier Quesnel committed
670
671
672
673
674
    } else if (is_equal(name, "storage-type")) {
        if (value == "five")
            params.storage = baryonyx::solver_parameters::storage_type::five;
        else if (value == "bound")
            params.storage = baryonyx::solver_parameters::storage_type::bound;
675
        else if (value == "one")
Gauthier Quesnel's avatar
Gauthier Quesnel committed
676
            params.storage = baryonyx::solver_parameters::storage_type::one;
677
678
679
        else
            return command_line_status::storage_type_error;

680
    } else if (is_equal(name, "theta")) {
681
        if (auto v = assign_01(value); !v)
682
            return command_line_status::theta_error;
683
684
        else
            params.theta = *v;
685

686
    } else if (is_equal(name, "delta")) {
687
        if (auto v = assign_0oo(value); !v)
688
            return command_line_status::delta_error;
689
690
        else
            params.delta = *v;
691

692
    } else if (is_equal(name, "kappa-min")) {
693
        if (auto v = assign_01(value); !v)
694
            return command_line_status::kappa_min_error;
695
696
        else
            params.kappa_min = *v;
697

698
    } else if (is_equal(name, "kappa-step")) {
699
        if (auto v = assign_01(value); !v)
700
            return command_line_status::kappa_step_error;
701
702
        else
            params.kappa_step = *v;
703

704
    } else if (is_equal(name, "kappa-max")) {
705
        if (auto v = assign_01(value); !v)
706
            return command_line_status::kappa_max_error;
707
708
        else
            params.kappa_max = *v;
709

710
    } else if (is_equal(name, "alpha")) {
711
        if (auto v = assign_d(value, 0, 2); !v)
712
            return command_line_status::alpha_error;
713
714
        else
            params.alpha = *v;
715

716
    } else if (is_equal(name, "w")) {
717
718
        if (auto v = assign_d(value, 0.0, std::numeric_limits<double>::max());
            !v)
719
            return command_line_status::w_error;
720
721
        else
            params.w = *v;
722

723
724
725
726
727
728
729
730
731
732
733
734
    } else if (is_equal(name, "norm")) {
        if (value == "none")
            params.cost_norm =
              baryonyx::solver_parameters::cost_norm_type::none;
        else if (value == "random")
            params.cost_norm =
              baryonyx::solver_parameters::cost_norm_type::random;
        else if (value == "l1")
            params.cost_norm = baryonyx::solver_parameters::cost_norm_type::l1;
        else if (value == "l2")
            params.cost_norm = baryonyx::solver_parameters::cost_norm_type::l2;
        else if (value == "loo")
735
736
737
            params.cost_norm =
              baryonyx::solver_parameters::cost_norm_type::loo;
        else
738
739
            return command_line_status::norm_error;

740
    } else if (is_equal(name, "pushes-limit")) {
741
        if (auto v = assign(value, 0, std::numeric_limits<int>::max()); !v)
742
            return command_line_status::pushes_limit_error;
743
744
        else
            params.pushes_limit = *v;
745

746
    } else if (is_equal(name, "pushing-objective-amplifier")) {
747
        if (auto v = assign_0oo(value); !v)
748
            return command_line_status::pushing_objective_amplifier_error;
749
750
        else
            params.pushing_objective_amplifier = *v;
751

752
    } else if (is_equal(name, "pushing-iteration-limit")) {
753
        if (auto v = assign(value, 0, std::numeric_limits<int>::max()); !v)
754
            return command_line_status::pushing_iteration_limit_error;
755
756
        else
            params.pushing_iteration_limit = *v;
757

758
    } else if (is_equal(name, "pushing-k-factor")) {
759
        if (auto v = assign_0oo(value); !v)
760
            return command_line_status::pushing_k_factor_error;
761
762
        else
            params.pushing_k_factor = *v;
763

764
765
766
767
768
769
    } else if (is_equal(name, "init-population-size")) {
        if (auto v = assign(value, 5, std::numeric_limits<int>::max()); !v)
            return command_line_status::init_population_size_error;
        else
            params.init_population_size = *v;

770
771
772
773
774
775
776
777
    } else if (is_equal(name, "init-crossover-bastert-insertion")) {
        if (auto v = assign_01(value); !v)
            return command_line_status::init_crossover_bastert_insertion_error;
        else
            params.init_crossover_bastert_insertion = *v;

    } else if (is_equal(name, "init-crossover-solution-selection-mean")) {
        if (auto v = assign_01(value); !v)
778
779
            return command_line_status::
              init_crossover_solution_selection_mean_error;
780
781
782
783
784
        else
            params.init_crossover_solution_selection_mean = *v;

    } else if (is_equal(name, "init-crossover-solution-selection-stddev")) {
        if (auto v = assign_01(value); !v)
785
786
            return command_line_status::
              init_crossover_solution_selection_stddev_error;
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
        else
            params.init_crossover_solution_selection_stddev = *v;

    } else if (is_equal(name, "init-mutation-variable-mean")) {
        if (auto v = assign_01(value); !v)
            return command_line_status::init_mutation_variable_mean_error;
        else
            params.init_mutation_variable_mean = *v;

    } else if (is_equal(name, "init-mutation-variable-stddev")) {
        if (auto v = assign_01(value); !v)
            return command_line_status::init_mutation_variable_stddev_error;
        else
            params.init_mutation_variable_stddev = *v;

    } else if (is_equal(name, "init-mutation-value-mean")) {
        if (auto v = assign_01(value); !v)
            return command_line_status::init_mutation_value_mean_error;
        else
            params.init_mutation_value_mean = *v;

    } else if (is_equal(name, "init-mutation-value-stddev")) {
        if (auto v = assign_01(value); !v)
            return command_line_status::init_mutation_value_stddev_error;
        else
            params.init_mutation_value_stddev = *v;

814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
    } else if (is_equal(name, "init-kappa-improve-start")) {
        if (auto v = assign_01(value); !v)
            return command_line_status::init_kappa_improve_start_error;
        else
            params.init_kappa_improve_start = *v;

    } else if (is_equal(name, "init-kappa-improve-increase")) {
        if (auto v = assign_01(value); !v)
            return command_line_status::init_kappa_improve_increase_error;
        else
            params.init_kappa_improve_increase = *v;

    } else if (is_equal(name, "init-kappa-improve-stop")) {
        if (auto v = assign_01(value); !v)
            return command_line_status::init_kappa_improve_stop_error;
        else
            params.init_kappa_improve_stop = *v;

832
833
834
835
    } else if (is_equal(name, "init-policy")) {
        if (value == "bastert")
            params.init_policy =
              baryonyx::solver_parameters::init_policy_type::bastert;
836
        else if (value == "pessimistic-solve")
Gauthier Quesnel's avatar
Gauthier Quesnel committed
837
            params.init_policy =
838
839
              baryonyx::solver_parameters::init_policy_type::pessimistic_solve;
        else if (value == "optimistic-solve")
Gauthier Quesnel's avatar
Gauthier Quesnel committed
840
            params.init_policy =
841
              baryonyx::solver_parameters::init_policy_type::optimistic_solve;
842
        else
843
844
            return command_line_status::init_policy_error;

845
846
847
848
849
850
    } else if (is_equal(name, "init-policy-random")) {
        if (auto v = assign_01(value); !v)
            return command_line_status::init_policy_random_error;
        else
            params.init_policy_random = *v;

851
    } else if (is_equal(name, "thread")) {
852
        if (auto v = assign(value, 0, std::numeric_limits<int>::max()); !v)
853
            return command_line_status::thread_error;
854
855
        else
            params.thread = *v;
856

857
    } else if (is_equal(name, "seed")) {
858
        if (auto v = assign(value, 0, std::numeric_limits<int>::max()); !v)
859
            return command_line_status::seed_error;
860
861
        else
            params.seed = *v;
862

863
    } else
864
865
866
        return command_line_status::unknown;

    return command_line_status::success;
867
868
}

869
struct main_parameters
870
{
871
    baryonyx::solver_parameters parameters;
872
873
    std::vector<std::string> filenames;
    std::string check_filename;
874
    std::string bench_name;
875
    int verbose = 6;
876
    int parse_arg = 0;
877
878
879
    bool check = false;
    bool optimize = false;
    bool quiet = false;
880
    bool bench = false;
881
    command_line_status parse_status = command_line_status::success;
882
883
};

884
static main_parameters
885
parse(int argc, const char* argv[])
886
887
{
    main_parameters ret;
888
    get_param get(argc, argv);
889
890

    for (int i = 1; i < argc; ++i) {
891
892
        std::string_view arg(argv[i]);

893
        ret.parse_arg = i;
894

895
        if (arg == "--help" || arg == "-h") {
896
897
898
899
            ::help();
            continue;
        }

900
        if (arg == "--quiet" || arg == "-q") {
901
            ret.quiet = true;
902
903
904
            continue;
        }

905
        if (arg == "--optimize" || arg == "-O") {
906
            ret.optimize = true;
907
908
909
            continue;
        }

910
        if (auto opt = get(i, "--bench", "-b"); opt) {
911
            ret.bench = true;
912
            ret.bench_name = *opt;
913
914
915
916
            i = get.i;
            continue;
        }

917
        if (arg == "--disable-preprocessing" || arg == "-np") {
918
919
            ret.parameters.preprocessor =
              baryonyx::solver_parameters::preprocessor_options::none;
920
921
922
            continue;
        }

923
924
        if (auto opt = get(i, "--auto", "-a"); opt) {
            if (*opt == "manual")
925
926
                ret.parameters.mode =
                  baryonyx::solver_parameters::mode_type::manual;
927
            else if (*opt == "nlopt")
928
929
                ret.parameters.mode =
                  baryonyx::solver_parameters::mode_type::nlopt;
930
            else if (*opt == "branch")
931
932
                ret.parameters.mode =
                  baryonyx::solver_parameters::mode_type::branch;
933
            else if (*opt == "branch-manual")
934
935
936
                ret.parameters.mode =
                  baryonyx::solver_parameters::mode_type::manual |
                  baryonyx::solver_parameters::mode_type::branch;
937
            else if (*opt == "branch-nlopt")
938
939
940
941
942
943
                ret.parameters.mode =
                  baryonyx::solver_parameters::mode_type::nlopt |
                  baryonyx::solver_parameters::mode_type::branch;
            else
                ret.parameters.mode =
                  baryonyx::solver_parameters::mode_type::none;
944

945
            i = get.i;
946
947
948
            continue;
        }

949
950
        if (auto opt = get(i, "--verbose", "-v"); opt) {
            if (auto v = ::assign(*opt, 0, 6); v) {
951
                ret.verbose = *v;
952
            } else {
953
954
955
                ret.parse_status = command_line_status::verbose_error;
                return ret;
            }
956
957
        }

958
959
        if (auto opt = get(i, "--check", "-C"); opt) {
            ret.check_filename = *opt;
960
            i = get.i;
961
962
963
            continue;
        }

964
965
966
967
968
969
970
971
        if (auto opt = get(i, "--param", "-p"); opt) {
            auto [name, value] = split_argument(*opt);

            if (name.empty() || value.empty()) {
                ret.parse_status = command_line_status::parameter_missing;
                return ret;
            }

972
973
974
975
976
977
            if (auto v = assign_parameter(ret.parameters, name, value);
                v != command_line_status::success) {
                ret.parse_status = v;
                return ret;
            }

978
            i = get.i;
979
980
981
            continue;
        }

982
983
984
985
986
987
        if (arg == "--random") {
            ret.parameters.solver =
              baryonyx::solver_parameters::solver_type::random;
            continue;
        }

Gauthier Quesnel's avatar
Gauthier Quesnel committed
988
989
990
991
992
        if (arg == "--debug") {
            ret.parameters.debug = true;
            continue;
        }

993
        ret.filenames.emplace_back(argv[i]);
994
995
    }

996
    return ret;
997
998
}

999
1000
static void
resume(const baryonyx::raw_problem& pb) noexcept
For faster browsing, not all history is shown. View entire blame