All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/12] kconfig: add support for conflict resolution
@ 2021-10-20  9:32 Thorsten Berger
  2021-10-20  9:35 ` [RFC 01/12] Add picosat.h Thorsten Berger
                   ` (11 more replies)
  0 siblings, 12 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:32 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Hi,

(resending everything with smaller patches)

Configuring a kernel requires a forward enabling approach where one
enables each option one needs at a time. If one enables an option
that selects other options, these options are no longer de-selectable
by design. Likewise, if one has enabled an option which creates a
conflict with a secondary option one wishes to enable, one cannot
easily enable that secondary option, unless one is willing to spend
time analyzing the dependencies that led to this conflict. Sometimes,
these conflicts are not easy to understand [0,1].

This patch series (for linux-next) provides support to enable users to
express their desired target configuration and display possible resolutions
to their conflicts. This support is provided within xconfig.

Conflict resolution is provided by translating kconfig's configuration
option tree to a propositional formula, and then allowing our resolution
algorithm, which uses a SAT solver (picosat, implemented in C) calculate
the possible fixes for an expressed target kernel configuration.

New UI extensions are made to xconfig with panes and buttons to allow users
to express new desired target options, calculate fixes, and apply any of
found solutions.

We created a separate test infrastructure that we used to validate the
correctness of the suggestions made. It shows that our resolution
algorithm resolves around 95% of the conflicts. We plan to incorporate
this with a later patch series.

We envision that our translation of the kconfig option tree into into a
propositional formula could potentially also later be repurposed to
address other problems. An example is checking the consistency
between the use of ifdefs and logic expressed in kconfig files.
We suspect that this could, for example, help avoid invalid kconfig
configurations and help with ifdef maintenance.

You can see a YouTube video demonstrating this work [2]. This effort is
part of the kernelnewbies Kconfig-SAT project [3], the approach and effort is
also explained in detail in our paper [4]. It is also our attempt at contributing
back to the kernel community, whose configurator researchers studied a lot.

Patches applicable to linux-next.

[0] https://gsd.uwaterloo.ca/sites/default/files/vamos12-survey.pdf
[1] https://www.linux-magazine.com/Issues/2021/244/Kconfig-Deep-Dive
[2] https://youtu.be/vyX7zCRiLKU
[3] https://kernelnewbies.org/KernelProjects/kconfig-sat
[4] http://www.cse.chalmers.se/~bergert/paper/2021-icseseip-configfix.pdf

Thanks from the team! (and thanks to Luis Chamberlain for guiding us here)

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>


Patrick Franz (12):
  Add picosat.h
  Add picosat.c (1/3)
  Add picosat.c (2/3)
  Add picosat.c (3/3)
  Add definitions
  Add files for building constraints
  Add files for handling expressions
  Add files for RangeFix
  Add files with utility functions
  Add tools
  Add xconfig-modifications
  Simplify dependencies for MODULE_SIG_KEY_TYPE_RSA &
    MODULE_SIG_KEY_TYPE_ECDSA

 certs/Kconfig                    |    3 +-
 scripts/kconfig/Makefile         |   19 +-
 scripts/kconfig/cf_constraints.c | 1219 +++++
 scripts/kconfig/cf_constraints.h |   23 +
 scripts/kconfig/cf_defs.h        |  233 +
 scripts/kconfig/cf_expr.c        | 2146 ++++++++
 scripts/kconfig/cf_expr.h        |  237 +
 scripts/kconfig/cf_rangefix.c    | 1017 ++++
 scripts/kconfig/cf_rangefix.h    |   18 +
 scripts/kconfig/cf_satutils.c    |  536 ++
 scripts/kconfig/cf_satutils.h    |   30 +
 scripts/kconfig/cf_utils.c       |  510 ++
 scripts/kconfig/cf_utils.h       |   90 +
 scripts/kconfig/cfconfig.c       |  176 +
 scripts/kconfig/cfoutconfig.c    |  128 +
 scripts/kconfig/configfix.c      |  420 ++
 scripts/kconfig/configfix.h      |   41 +
 scripts/kconfig/expr.h           |   13 +
 scripts/kconfig/picosat.c        | 8502 ++++++++++++++++++++++++++++++
 scripts/kconfig/picosat.h        |  658 +++
 scripts/kconfig/qconf.cc         | 1003 +++-
 scripts/kconfig/qconf.h          |  179 +-
 22 files changed, 16943 insertions(+), 258 deletions(-)
 create mode 100644 scripts/kconfig/cf_constraints.c
 create mode 100644 scripts/kconfig/cf_constraints.h
 create mode 100644 scripts/kconfig/cf_defs.h
 create mode 100644 scripts/kconfig/cf_expr.c
 create mode 100644 scripts/kconfig/cf_expr.h
 create mode 100644 scripts/kconfig/cf_rangefix.c
 create mode 100644 scripts/kconfig/cf_rangefix.h
 create mode 100644 scripts/kconfig/cf_satutils.c
 create mode 100644 scripts/kconfig/cf_satutils.h
 create mode 100644 scripts/kconfig/cf_utils.c
 create mode 100644 scripts/kconfig/cf_utils.h
 create mode 100644 scripts/kconfig/cfconfig.c
 create mode 100644 scripts/kconfig/cfoutconfig.c
 create mode 100644 scripts/kconfig/configfix.c
 create mode 100644 scripts/kconfig/configfix.h
 create mode 100644 scripts/kconfig/picosat.c
 create mode 100644 scripts/kconfig/picosat.h

-- 
2.33.0

-- 
Prof. Dr. Thorsten Berger
Chair of Software Engineering
Faculty of Computer Science
Ruhr University Bochum, Germany

http://www.thorsten-berger.net
Tel.: +49 (0) 234 32 25975
Mob.: +49 (0) 160 926 878 10
Skype: tberger.work


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC 01/12] Add picosat.h
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
@ 2021-10-20  9:35 ` Thorsten Berger
  2021-10-20 15:54   ` Luis Chamberlain
  2021-10-20  9:36 ` [RFC 02/12] Add picosat.c (1/3) Thorsten Berger
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:35 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/picosat.h | 658 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 658 insertions(+)
 create mode 100644 scripts/kconfig/picosat.h

diff --git a/scripts/kconfig/picosat.h b/scripts/kconfig/picosat.h
new file mode 100644
index 000000000000..668bc00bcbc0
--- /dev/null
+++ b/scripts/kconfig/picosat.h
@@ -0,0 +1,658 @@
+/****************************************************************************
+Copyright (c) 2006 - 2015, Armin Biere, Johannes Kepler University.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+****************************************************************************/
+
+#ifndef picosat_h_INCLUDED
+#define picosat_h_INCLUDED
+
+/*------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+/*------------------------------------------------------------------------*/
+/* The following macros allows for users to distiguish between different
+ * versions of the API.  The first 'PICOSAT_REENTRANT_API' is defined for
+ * the new reentrant API which allows to generate multiple instances of
+ * PicoSAT in one process.  The second 'PICOSAT_API_VERSION' defines the
+ * (smallest) version of PicoSAT to which this API conforms.
+ */
+#define PICOSAT_REENTRANT_API
+#define PICOSAT_API_VERSION 953        /* API version */
+
+/*------------------------------------------------------------------------*/
+/* These are the return values for 'picosat_sat' as for instance
+ * standardized by the output format of the SAT competition.
+ */
+#define PICOSAT_UNKNOWN         0
+#define PICOSAT_SATISFIABLE     10
+#define PICOSAT_UNSATISFIABLE   20
+
+/*------------------------------------------------------------------------*/
+
+typedef struct PicoSAT PicoSAT;
+
+/*------------------------------------------------------------------------*/
+
+const char *picosat_version (void);
+const char *picosat_config (void);
+const char *picosat_copyright (void);
+
+/*------------------------------------------------------------------------*/
+/* You can make PicoSAT use an external memory manager instead of the one
+ * provided by LIBC. But then you need to call these three function before
+ * 'picosat_init'.  The memory manager functions here all have an additional
+ * first argument which is a pointer to the memory manager, but otherwise
+ * are supposed to work as their LIBC counter parts 'malloc', 'realloc' and
+ * 'free'.  As exception the 'resize' and 'delete' function have as third
+ * argument the number of bytes of the block given as second argument.
+ */
+
+typedef void * (*picosat_malloc)(void *, size_t);
+typedef void * (*picosat_realloc)(void*, void *, size_t, size_t);
+typedef void (*picosat_free)(void*, void*, size_t);
+
+/*------------------------------------------------------------------------*/
+
+PicoSAT * picosat_init (void);          /* constructor */
+
+PicoSAT * picosat_minit (void * state,
+             picosat_malloc,
+             picosat_realloc,
+             picosat_free);
+
+void picosat_reset (PicoSAT *);         /* destructor */
+
+/*------------------------------------------------------------------------*/
+/* The following five functions are essentially parameters to 'init', and
+ * thus should be called right after 'picosat_init' before doing anything
+ * else.  You should not call any of them after adding a literal.
+ */
+
+/* Set output file, default is 'stdout'.
+ */
+void picosat_set_output (PicoSAT *, FILE *);
+
+/* Measure all time spent in all calls in the solver.  By default only the
+ * time spent in 'picosat_sat' is measured.  Enabling this function might
+ * for instance triple the time needed to add large CNFs, since every call
+ * to 'picosat_add' will trigger a call to 'getrusage'.
+ */
+void picosat_measure_all_calls (PicoSAT *);
+
+/* Set the prefix used for printing verbose messages and statistics.
+ * Default is "c ".
+ */
+void picosat_set_prefix (PicoSAT *, const char *);
+
+/* Set verbosity level.  A verbosity level of 1 and above prints more and
+ * more detailed progress reports on the output file, set by
+ * 'picosat_set_output'.  Verbose messages are prefixed with the string set
+ * by 'picosat_set_prefix'.
+ */
+void picosat_set_verbosity (PicoSAT *, int new_verbosity_level);
+
+/* Disable/Enable all pre-processing, currently only failed literal probing.
+ *
+ *  new_plain_value != 0    only 'plain' solving, so no preprocessing
+ *  new_plain_value == 0    allow preprocessing
+ */
+void picosat_set_plain (PicoSAT *, int new_plain_value);
+
+/* Set default initial phase:
+ *
+ *   0 = false
+ *   1 = true
+ *   2 = Jeroslow-Wang (default)
+ *   3 = random initial phase
+ *
+ * After a variable has been assigned the first time, it will always
+ * be assigned the previous value if it is picked as decision variable.
+ * The initial assignment can be chosen with this function.
+ */
+void picosat_set_global_default_phase (PicoSAT *, int);
+
+/* Set next/initial phase of a particular variable if picked as decision
+ * variable.  Second argument 'phase' has the following meaning:
+ *
+ *   negative = next value if picked as decision variable is false
+ *
+ *   positive = next value if picked as decision variable is true
+ *
+ *   0        = use global default phase as next value and
+ *              assume 'lit' was never assigned
+ *
+ * Again if 'lit' is assigned afterwards through a forced assignment,
+ * then this forced assignment is the next phase if this variable is
+ * used as decision variable.
+ */
+void picosat_set_default_phase_lit (PicoSAT *, int lit, int phase);
+
+/* You can reset all phases by the following function.
+ */
+void picosat_reset_phases (PicoSAT *);
+
+/* Scores can be erased as well.  Note, however, that even after erasing
+ * scores and phases, learned clauses are kept.  In addition head tail
+ * pointers for literals are not moved either.  So expect a difference
+ * between calling the solver in incremental mode or with a fresh copy of
+ * the CNF.
+ */
+void picosat_reset_scores (PicoSAT *);
+
+/* Reset assignment if in SAT state and then remove the given percentage of
+ * less active (large) learned clauses.  If you specify 100% all large
+ * learned clauses are removed.
+ */
+void picosat_remove_learned (PicoSAT *, unsigned percentage);
+
+/* Set some variables to be more important than others.  These variables are
+ * always used as decisions before other variables are used.  Dually there
+ * is a set of variables that is used last.  The default is
+ * to mark all variables as being indifferent only.
+ */
+void picosat_set_more_important_lit (PicoSAT *, int lit);
+void picosat_set_less_important_lit (PicoSAT *, int lit);
+
+/* Allows to print to internal 'out' file from client.
+ */
+void picosat_message (PicoSAT *, int verbosity_level, const char * fmt, ...);
+
+/* Set a seed for the random number generator.  The random number generator
+ * is currently just used for generating random decisions.  In our
+ * experiments having random decisions did not really help on industrial
+ * examples, but was rather helpful to randomize the solver in order to
+ * do proper benchmarking of different internal parameter sets.
+ */
+void picosat_set_seed (PicoSAT *, unsigned random_number_generator_seed);
+
+/* If you ever want to extract cores or proof traces with the current
+ * instance of PicoSAT initialized with 'picosat_init', then make sure to
+ * call 'picosat_enable_trace_generation' right after 'picosat_init'.   This
+ * is not necessary if you only use 'picosat_set_incremental_rup_file'.
+ *
+ * NOTE, trace generation code is not necessarily included, e.g. if you
+ * configure PicoSAT with full optimzation as './configure.sh -O' or with
+
+ * you do not get any results by trying to generate traces.
+ *
+ * The return value is non-zero if code for generating traces is included
+ * and it is zero if traces can not be generated.
+ */
+int picosat_enable_trace_generation (PicoSAT *);
+
+/* You can dump proof traces in RUP format incrementally even without
+ * keeping the proof trace in memory.  The advantage is a reduction of
+ * memory usage, but the dumped clauses do not necessarily belong to the
+ * clausal core.  Beside the file the additional parameters denotes the
+ * maximal number of variables and the number of original clauses.
+ */
+void picosat_set_incremental_rup_file (PicoSAT *, FILE * file, int m, int n);
+
+/* Save original clauses for 'picosat_deref_partial'.  See comments to that
+ * function further down.
+ */
+void picosat_save_original_clauses (PicoSAT *);
+
+/* Add a call back which is checked regularly to notify the SAT solver
+ * to terminate earlier.  This is useful for setting external time limits
+ * or terminate early in say a portfolio style parallel SAT solver.
+ */
+void picosat_set_interrupt (PicoSAT *,
+                            void * external_state,
+                int (*interrupted)(void * external_state));
+
+/*------------------------------------------------------------------------*/
+/* This function returns the next available unused variable index and
+ * allocates a variable for it even though this variable does not occur as
+ * assumption, nor in a clause or any other constraints.  In future calls to
+ * 'picosat_sat', 'picosat_deref' and particularly for 'picosat_changed',
+ * this variable is treated as if it had been used.
+ */
+int picosat_inc_max_var (PicoSAT *);
+
+/*------------------------------------------------------------------------*/
+/* Push and pop semantics for PicoSAT.   'picosat_push' opens up a new
+ * context.  All clauses added in this context are attached to it and
+ * discarded when the context is closed with 'picosat_pop'.  It is also
+ * possible to nest contexts.
+ *
+ * The current implementation uses a new internal variable for each context.
+ * However, the indices for these internal variables are shared with
+ * ordinary external variables.  This means that after any call to
+ * 'picosat_push', new variable indices should be obtained with
+ * 'picosat_inc_max_var' and not just by incrementing the largest variable
+ * index used so far.
+ *
+ * The return value is the index of the literal that assumes this context.
+ * This literal can only be used for 'picosat_failed_context' otherwise
+ * it will lead to an API usage error.
+ */
+int picosat_push (PicoSAT *);
+
+/* This is as 'picosat_failed_assumption', but only for internal variables
+ * generated by 'picosat_push'.
+ */
+int picosat_failed_context (PicoSAT *, int lit);
+
+/* Returns the literal that assumes the current context or zero if the
+ * outer context has been reached.
+ */
+int picosat_context (PicoSAT *);   
+
+/* Closes the current context and recycles the literal generated for
+ * assuming this context.  The return value is the literal for the new
+ * outer context or zero if the outer most context has been reached.
+ */
+int picosat_pop (PicoSAT *);
+
+/* Force immmediate removal of all satisfied clauses and clauses that are
+ * added or generated in closed contexts.  This function is called
+ * internally if enough units are learned or after a certain number of
+ * contexts have been closed.  This number is fixed at compile time
+ * and defined as MAXCILS in 'picosat.c'.
+ *
+ * Note that learned clauses which only involve outer contexts are kept.
+ */
+void picosat_simplify (PicoSAT *);
+
+/*------------------------------------------------------------------------*/
+/* If you know a good estimate on how many variables you are going to use
+ * then calling this function before adding literals will result in less
+ * resizing of the variable table.  But this is just a minor optimization.
+ * Beside exactly allocating enough variables it has the same effect as
+ * calling 'picosat_inc_max_var'.
+ */
+void picosat_adjust (PicoSAT *, int max_idx);
+
+/*------------------------------------------------------------------------*/
+/* Statistics.
+ */
+int picosat_variables (PicoSAT *);                      /* p cnf <m> n */
+int picosat_added_original_clauses (PicoSAT *);         /* p cnf m <n> */
+size_t picosat_max_bytes_allocated (PicoSAT *);
+double picosat_time_stamp (void);                       /* ... in process */
+void picosat_stats (PicoSAT *);                         /* > output file */
+unsigned long long picosat_propagations (PicoSAT *);    /* #propagations */
+unsigned long long picosat_decisions (PicoSAT *);    /* #decisions */
+unsigned long long picosat_visits (PicoSAT *);        /* #visits */
+
+/* The time spent in calls to the library or in 'picosat_sat' respectively.
+ * The former is returned if, right after initialization
+ * 'picosat_measure_all_calls' is called.
+ */
+double picosat_seconds (PicoSAT *);
+
+/*------------------------------------------------------------------------*/
+/* Add a literal of the next clause.  A zero terminates the clause.  The
+ * solver is incremental.  Adding a new literal will reset the previous
+ * assignment.   The return value is the original clause index to which
+ * this literal respectively the trailing zero belong starting at 0.
+ */
+int picosat_add (PicoSAT *, int lit);
+
+/* As the previous function, but allows to add a full clause at once with an
+ * at compiled time known size.  The list of argument literals has to be
+ * terminated with a zero literal.  Literals beyond the first zero literal
+ * are discarded.
+ */
+int picosat_add_arg (PicoSAT *, ...);
+
+/* As the previous function but with an at compile time unknown size.
+ */
+int picosat_add_lits (PicoSAT *, int * lits);
+
+/* Print the CNF to the given file in DIMACS format.
+ */
+void picosat_print (PicoSAT *, FILE *);
+
+/* You can add arbitrary many assumptions before the next 'picosat_sat'
+ * call.  This is similar to the using assumptions in MiniSAT, except that
+ * for PicoSAT you do not have to collect all your assumptions in a vector
+ * yourself.  In PicoSAT you can add one after the other, to be used in the
+ * next call to 'picosat_sat'.
+ *
+ * These assumptions can be interpreted as adding unit clauses with those
+ * assumptions as literals.  However these assumption clauses are only valid
+ * for exactly the next call to 'picosat_sat', and will be removed
+ * afterwards, e.g. in following future calls to 'picosat_sat' after the
+ * next 'picosat_sat' call, unless they are assumed again trough
+ * 'picosat_assume'.
+ *
+ * More precisely, assumptions actually remain valid even after the next
+ * call to 'picosat_sat' has returned.  Valid means they remain 'assumed'
+ * internally until a call to 'picosat_add', 'picosat_assume', or a second
+ * 'picosat_sat', following the first 'picosat_sat'.  The reason for keeping
+ * them valid is to allow 'picosat_failed_assumption' to return correct
+ * values.  
+ *
+ * Example:
+ *
+ *   picosat_assume (1);        // assume unit clause '1 0'
+ *   picosat_assume (-2);       // additionally assume clause '-2 0'
+ *   res = picosat_sat (1000);  // assumes 1 and -2 to hold
+ *                              // 1000 decisions max.
+ *
+ *   if (res == PICOSAT_UNSATISFIABLE)
+ *     {
+ *       if (picosat_failed_assumption (1))
+ *         // unit clause '1 0' was necessary to derive UNSAT
+ *
+ *       if (picosat_failed_assumption (-2))
+ *         // unit clause '-2 0' was necessary to derive UNSAT
+ *
+ *       // at least one but also both could be necessary
+ *
+ *       picosat_assume (17);  // previous assumptions are removed
+ *                             // now assume unit clause '17 0' for
+ *                             // the next call to 'picosat_sat'
+ *
+ *       // adding a new clause, actually the first literal of
+ *       // a clause would also make the assumptions used in the previous
+ *       // call to 'picosat_sat' invalid.
+ *
+ *       // The first two assumptions above are not assumed anymore.  Only
+ *       // the assumptions, since the last call to 'picosat_sat' returned
+ *       // are assumed, e.g. the unit clause '17 0'.
+ *
+ *       res = picosat_sat (-1);
+ *     }
+ *   else if (res == PICOSAT_SATISFIABLE)
+ *     {
+ *       // now the assignment is valid and we can call 'picosat_deref'
+ *
+ *       assert (picosat_deref (1) == 1));
+ *       assert (picosat_deref (-2) == 1));
+ *
+ *       val = picosat_deref (15);
+ *
+ *       // previous two assumptions are still valid
+ *
+ *       // would become invalid if 'picosat_add' or 'picosat_assume' is
+ *       // called here, but we immediately call 'picosat_sat'.  Now when
+ *       // entering 'picosat_sat' the solver knows that the previous call
+ *       // returned SAT and it can safely reset the previous assumptions
+ *
+ *       res = picosat_sat (-1);
+ *     }
+ *   else
+ *     {
+ *       assert (res == PICOSAT_UNKNOWN);
+ *
+ *       // assumptions valid, but assignment invalid
+ *       // except for top level assigned literals which
+ *       // necessarily need to have this value if the formula is SAT
+ *
+ *       // as above the solver nows that the previous call returned UNKWOWN
+ *       // and will before doing anything else reset assumptions
+ *
+ *       picosat_sat (-1);
+ *     }
+ */
+void picosat_assume (PicoSAT *, int lit);
+
+/*------------------------------------------------------------------------*/
+/* This is an experimental feature for handling 'all different constraints'
+ * (ADC).  Currently only one global ADC can be handled.  The bit-width of
+ * all the bit-vectors entered in this ADC (stored in 'all different
+ * objects' or ADOs) has to be identical.
+ *
+ * TODO: also handle top level assigned literals here.
+ */
+void picosat_add_ado_lit (PicoSAT *, int);
+
+/*------------------------------------------------------------------------*/
+/* Call the main SAT routine.  A negative decision limit sets no limit on
+ * the number of decisions.  The return values are as above, e.g.
+ * 'PICOSAT_UNSATISFIABLE', 'PICOSAT_SATISFIABLE', or 'PICOSAT_UNKNOWN'.
+ */
+int picosat_sat (PicoSAT *, int decision_limit);
+
+/* As alternative to a decision limit you can use the number of propagations
+ * as limit.  This is more linearly related to execution time. This has to
+ * be called after 'picosat_init' and before 'picosat_sat'.
+ */
+void picosat_set_propagation_limit (PicoSAT *, unsigned long long limit);
+
+/* Return last result of calling 'picosat_sat' or '0' if not called.
+ */
+int picosat_res (PicoSAT *);
+
+/* After 'picosat_sat' was called and returned 'PICOSAT_SATISFIABLE', then
+ * the satisfying assignment can be obtained by 'dereferencing' literals.
+ * The value of the literal is return as '1' for 'true',  '-1' for 'false'
+ * and '0' for an unknown value.
+ */
+int picosat_deref (PicoSAT *, int lit);
+
+/* Same as before but just returns true resp. false if the literals is
+ * forced to this assignment at the top level.  This function does not
+ * require that 'picosat_sat' was called and also does not internally reset
+ * incremental usage.
+ */
+int picosat_deref_toplevel (PicoSAT *, int lit);
+
+/* After 'picosat_sat' was called and returned 'PICOSAT_SATISFIABLE' a
+ * partial satisfying assignment can be obtained as well.  It satisfies all
+ * original clauses.  The value of the literal is return as '1' for 'true',
+ * '-1' for 'false' and '0' for an unknown value.  In order to make this
+ * work all original clauses have to be saved internally, which has to be
+ * enabled by 'picosat_save_original_clauses' right after initialization.
+ */
+int picosat_deref_partial (PicoSAT *, int lit);
+
+/* Returns non zero if the CNF is unsatisfiable because an empty clause was
+ * added or derived.
+ */
+int picosat_inconsistent  (PicoSAT *);
+
+/* Returns non zero if the literal is a failed assumption, which is defined
+ * as an assumption used to derive unsatisfiability.  This is as accurate as
+ * generating core literals, but still of course is an overapproximation of
+ * the set of assumptions really necessary.  The technique does not need
+ * clausal core generation nor tracing to be enabled and thus can be much
+ * more effective.  The function can only be called as long the current
+ * assumptions are valid.  See 'picosat_assume' for more details.
+ */
+int picosat_failed_assumption (PicoSAT *, int lit);
+
+/* Returns a zero terminated list of failed assumption in the last call to
+ * 'picosat_sat'.  The pointer is valid until the next call to
+ * 'picosat_sat' or 'picosat_failed_assumptions'.  It only makes sense if the
+ * last call to 'picosat_sat' returned 'PICOSAT_UNSATISFIABLE'.
+ */
+const int * picosat_failed_assumptions (PicoSAT *);
+
+/* Returns a zero terminated minimized list of failed assumption for the last
+ * call to 'picosat_sat'.  The pointer is valid until the next call to this
+ * function or 'picosat_sat' or 'picosat_mus_assumptions'.  It only makes sense
+ * if the last call to 'picosat_sat' returned 'PICOSAT_UNSATISFIABLE'.
+ *
+ * The call back function is called for all successful simplification
+ * attempts.  The first argument of the call back function is the state
+ * given as first argument to 'picosat_mus_assumptions'.  The second
+ * argument to the call back function is the new reduced list of failed
+ * assumptions.
+ *
+ * This function will call 'picosat_assume' and 'picosat_sat' internally but
+ * before returning reestablish a proper UNSAT state, e.g.
+ * 'picosat_failed_assumption' will work afterwards as expected.
+ *
+ * The last argument if non zero fixes assumptions.  In particular, if an
+ * assumption can not be removed it is permanently assigned true, otherwise
+ * if it turns out to be redundant it is permanently assumed to be false.
+ */
+const int * picosat_mus_assumptions (PicoSAT *, void *,
+                                     void(*)(void*,const int*),int);
+
+/* Compute one maximal subset of satisfiable assumptions.  You need to set
+ * the assumptions, call 'picosat_sat' and check for 'picosat_inconsistent',
+ * before calling this function.  The result is a zero terminated array of
+ * assumptions that consistently can be asserted at the same time.  Before
+ * returing the library 'reassumes' all assumptions.
+ *
+ * It could be beneficial to set the default phase of assumptions
+ * to true (positive).  This can speed up the computation.
+ */
+const int * picosat_maximal_satisfiable_subset_of_assumptions (PicoSAT *);
+
+/* This function assumes that you have set up all assumptions with
+ * 'picosat_assume'.  Then it calls 'picosat_sat' internally unless the
+ * formula is already inconsistent without assumptions, i.e.  it contains
+ * the empty clause.  After that it extracts a maximal satisfiable subset of
+ * assumptions.
+ *
+ * The result is a zero terminated maximal subset of consistent assumptions
+ * or a zero pointer if the formula contains the empty clause and thus no
+ * more maximal consistent subsets of assumptions can be extracted.  In the
+ * first case, before returning, a blocking clause is added, that rules out
+ * the result for the next call.
+ *
+ * NOTE: adding the blocking clause changes the CNF.
+ *
+ * So the following idiom
+ *
+ * const int * mss;
+ * picosat_assume (a1);
+ * picosat_assume (a2);
+ * picosat_assume (a3);
+ * picosat_assume (a4);
+ * while ((mss = picosat_next_maximal_satisfiable_subset_of_assumptions ()))
+ *   process_mss (mss);
+ *
+ * can be used to iterate over all maximal consistent subsets of
+ * the set of assumptions {a1,a2,a3,a4}.
+ *
+ * It could be beneficial to set the default phase of assumptions
+ * to true (positive).  This might speed up the computation.
+ */
+const int *
+picosat_next_maximal_satisfiable_subset_of_assumptions (PicoSAT *);
+
+/* Similarly we can iterate over all minimal correcting assumption sets.
+ * See the CAMUS literature [M. Liffiton, K. Sakallah JAR 2008].
+ *
+ * The result contains each assumed literal only once, even if it
+ * was assumed multiple times (in contrast to the maximal consistent
+ * subset functions above).
+ *
+ * It could be beneficial to set the default phase of assumptions
+ * to true (positive).  This might speed up the computation.
+ */
+const int *
+picosat_next_minimal_correcting_subset_of_assumptions (PicoSAT *);
+
+/* Compute the union of all minmal correcting sets, which is called
+ * the 'high level union of all minimal unsatisfiable subset sets'
+ * or 'HUMUS' in our papers.
+ *
+ * It uses 'picosat_next_minimal_correcting_subset_of_assumptions' and
+ * the same notes and advices apply.  In particular, this implies that
+ * after calling the function once, the current CNF becomes inconsistent,
+ * and PicoSAT has to be reset.  So even this function internally uses
+ * PicoSAT incrementally, it can not be used incrementally itself at this
+ * point.
+ *
+ * The 'callback' can be used for progress logging and is called after
+ * each extracted minimal correcting set if non zero.  The 'nhumus'
+ * parameter of 'callback' denotes the number of assumptions found to be
+ * part of the HUMUS sofar.
+ */
+const int *
+picosat_humus (PicoSAT *,
+               void (*callback)(void * state, int nmcs, int nhumus),
+           void * state);
+
+/*------------------------------------------------------------------------*/
+/* Assume that a previous call to 'picosat_sat' in incremental usage,
+ * returned 'SATISFIABLE'.  Then a couple of clauses and optionally new
+ * variables were added (a new variable is a variable that has an index
+ * larger then the maximum variable added so far).  The next call to
+ * 'picosat_sat' also returns 'SATISFIABLE'. If this function
+ * 'picosat_changed' returns '0', then the assignment to the old variables
+ * is guaranteed to not have changed.  Otherwise it might have changed.
+ *
+ * The return value to this function is only valid until new clauses are
+ * added through 'picosat_add', an assumption is made through
+ * 'picosat_assume', or again 'picosat_sat' is called.  This is the same
+ * assumption as for 'picosat_deref'.
+ *
+ * TODO currently this function might also return a non zero value even if
+ * the old assignment did not change, because it only checks whether the
+ * assignment of at least one old variable was flipped at least once during
+ * the search.  In principle it should be possible to be exact in the other
+ * direction as well by using a counter of variables that have an odd number
+ * of flips.  But this is not implemented yet.
+ */
+int picosat_changed (PicoSAT *);
+
+/*------------------------------------------------------------------------*/
+/* The following six functions internally extract the variable and clausal
+ * core and thus require trace generation to be enabled with
+ * 'picosat_enable_trace_generation' right after calling 'picosat_init'.
+ *
+ * TODO: using these functions in incremental mode with failed assumptions
+ * has only been tested for 'picosat_corelit' thoroughly.  The others
+ * probably only work in non-incremental mode or without using
+ * 'picosat_assume'.
+ */
+
+/* This function determines whether the i'th added original clause is in the
+ * core.  The 'i' is the return value of 'picosat_add', which starts at zero
+ * and is incremented by one after a original clause is added (that is after
+ * 'picosat_add (0)').  For the index 'i' the following has to hold:
+ *
+ *   0 <= i < picosat_added_original_clauses ()
+ */
+int picosat_coreclause (PicoSAT *, int i);
+
+/* This function gives access to the variable core, which is made up of the
+ * variables that were resolved in deriving the empty clause.
+ */
+int picosat_corelit (PicoSAT *, int lit);
+
+/* Write the clauses that were used in deriving the empty clause to a file
+ * in DIMACS format.
+ */
+void picosat_write_clausal_core (PicoSAT *, FILE * core_file);
+
+/* Write a proof trace in TraceCheck format to a file.
+ */
+void picosat_write_compact_trace (PicoSAT *, FILE * trace_file);
+void picosat_write_extended_trace (PicoSAT *, FILE * trace_file);
+
+/* Write a RUP trace to a file.  This trace file contains only the learned
+ * core clauses while this is not necessarily the case for the RUP file
+ * obtained with 'picosat_set_incremental_rup_file'.
+ */
+void picosat_write_rup_trace (PicoSAT *, FILE * trace_file);
+
+/*------------------------------------------------------------------------*/
+/* Keeping the proof trace around is not necessary if an over-approximation
+ * of the core is enough.  A literal is 'used' if it was involved in a
+ * resolution to derive a learned clause.  The core literals are necessarily
+ * a subset of the 'used' literals.
+ */
+
+int picosat_usedlit (PicoSAT *, int lit);
+/*------------------------------------------------------------------------*/
+#endif
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 02/12] Add picosat.c (1/3)
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
  2021-10-20  9:35 ` [RFC 01/12] Add picosat.h Thorsten Berger
@ 2021-10-20  9:36 ` Thorsten Berger
  2021-10-20  9:37 ` [RFC 03/12] Add picosat.c (2/3) Thorsten Berger
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:36 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/picosat.c | 3000 +++++++++++++++++++++++++++++++++++++
 1 file changed, 3000 insertions(+)
 create mode 100644 scripts/kconfig/picosat.c

diff --git a/scripts/kconfig/picosat.c b/scripts/kconfig/picosat.c
new file mode 100644
index 000000000000..653bf0f0b99f
--- /dev/null
+++ b/scripts/kconfig/picosat.c
@@ -0,0 +1,3000 @@
+/****************************************************************************
+Copyright (c) 2006 - 2015, Armin Biere, Johannes Kepler University.
+
+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.
+****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <limits.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "picosat.h"
+
+/* By default code for 'all different constraints' is disabled, since 'NADC'
+ * is defined.
+ */
+#define NADC
+
+/* By default we enable failed literals, since 'NFL' is undefined.
+ *
+#define NFL
+ */
+
+/* By default we 'detach satisfied (large) clauses', e.g. NDSC undefined.
+ *
+#define NDSC
+ */
+
+/* Do not use luby restart schedule instead of inner/outer.
+ *
+#define NLUBY
+ */
+
+/* Enabling this define, will use gnuplot to visualize how the scores evolve.
+ *
+#define VISCORES
+ */
+#ifdef VISCORES
+// #define WRITEGIF        /* ... to generate a video */
+#endif
+
+#ifdef VISCORES
+#ifndef WRITEGIF
+#include <unistd.h>        /* for 'usleep' */
+#endif
+#endif
+
+#ifdef RCODE
+#include <R.h>
+#endif
+
+#define MINRESTART    100    /* minimum restart interval */
+#define MAXRESTART    1000000 /* maximum restart interval */
+#define RDECIDE        1000    /* interval of random decisions */
+#define FRESTART    110    /* restart increase factor in percent */
+#define FREDUCE        110    /* reduce increase factor in percent  */
+#define FREDADJ        121    /* reduce increase adjustment factor */
+#define MAXCILS        10    /* maximal number of unrecycled internals */
+#define FFLIPPED    10000    /* flipped reduce factor */
+#define FFLIPPEDPREC    10000000/* flipped reduce factor precision */
+#define INTERRUPTLIM    1024    /* check interrupt after that many decisions */
+
+#ifndef TRACE
+#define NO_BINARY_CLAUSES    /* store binary clauses more compactly */
+#endif
+
+/* For debugging purposes you may want to define 'LOGGING', which actually
+ * can be enforced by using './configure.sh --log'.
+ */
+#ifdef LOGGING
+#define LOG(code) do { code; } while (0)
+#else
+#define LOG(code) do { } while (0)
+#endif
+#define NOLOG(code) do { } while (0)        /* log exception */
+#define ONLYLOG(code) do { code; } while (0)    /* force logging */
+
+#define FALSE ((Val)-1)
+#define UNDEF ((Val)0)
+#define TRUE ((Val)1)
+
+#define COMPACT_TRACECHECK_TRACE_FMT 0
+#define EXTENDED_TRACECHECK_TRACE_FMT 1
+#define RUP_TRACE_FMT 2
+
+#define NEWN(p,n) do { (p) = new (ps, sizeof (*(p)) * (n)); } while (0)
+#define CLRN(p,n) do { memset ((p), 0, sizeof (*(p)) * (n)); } while (0)
+#define CLR(p) CLRN(p,1)
+#define DELETEN(p,n) \
+  do { delete (ps, p, sizeof (*(p)) * (n)); (p) = 0; } while (0)
+
+#define RESIZEN(p,old_num,new_num) \
+  do { \
+    size_t old_size = sizeof (*(p)) * (old_num); \
+    size_t new_size = sizeof (*(p)) * (new_num); \
+    (p) = resize (ps, (p), old_size, new_size) ; \
+  } while (0)
+
+#define ENLARGE(start,head,end) \
+  do { \
+    unsigned old_num = (ptrdiff_t)((end) - (start)); \
+    size_t new_num = old_num ? (2 * old_num) : 1; \
+    unsigned count = (head) - (start); \
+    assert ((start) <= (end)); \
+    RESIZEN((start),old_num,new_num); \
+    (head) = (start) + count; \
+    (end) = (start) + new_num; \
+  } while (0)
+
+#define NOTLIT(l) (ps->lits + (1 ^ ((l) - ps->lits)))
+
+#define LIT2IDX(l) ((ptrdiff_t)((l) - ps->lits) / 2)
+#define LIT2IMPLS(l) (ps->impls + (ptrdiff_t)((l) - ps->lits))
+#define LIT2INT(l) ((int)(LIT2SGN(l) * LIT2IDX(l)))
+#define LIT2SGN(l) (((ptrdiff_t)((l) - ps->lits) & 1) ? -1 : 1)
+#define LIT2VAR(l) (ps->vars + LIT2IDX(l))
+#define LIT2HTPS(l) (ps->htps + (ptrdiff_t)((l) - ps->lits))
+#define LIT2JWH(l) (ps->jwh + ((l) - ps->lits))
+
+#ifndef NDSC
+#define LIT2DHTPS(l) (ps->dhtps + (ptrdiff_t)((l) - ps->lits))
+#endif
+
+#ifdef NO_BINARY_CLAUSES
+typedef uintptr_t Wrd;
+#define ISLITREASON(C) (1&(Wrd)C)
+#define LIT2REASON(L) \
+  (assert (L->val==TRUE), ((Cls*)(1 + (2*(L - ps->lits)))))
+#define REASON2LIT(C) ((Lit*)(ps->lits + ((Wrd)C)/2))
+#endif
+
+#define ENDOFCLS(c) ((void*)((Lit**)(c)->lits + (c)->size))
+
+#define SOC ((ps->oclauses == ps->ohead) ? ps->lclauses : ps->oclauses)
+#define EOC (ps->lhead)
+#define NXC(p) (((p) + 1 == ps->ohead) ? ps->lclauses : (p) + 1)
+
+#define OIDX2IDX(idx) (2 * ((idx) + 1))
+#define LIDX2IDX(idx) (2 * (idx) + 1)
+
+#define ISLIDX(idx) ((idx)&1)
+
+#define IDX2OIDX(idx) (assert(!ISLIDX(idx)), (idx)/2 - 1)
+#define IDX2LIDX(idx) (assert(ISLIDX(idx)), (idx)/2)
+
+#define EXPORTIDX(idx) \
+  ((ISLIDX(idx) ? (IDX2LIDX (idx) + (ps->ohead - ps->oclauses)) : IDX2OIDX(idx)) + 1)
+
+#define IDX2CLS(i) \
+  (assert(i), (ISLIDX(i) ? ps->lclauses : ps->oclauses)[(i)/2 - !ISLIDX(i)])
+
+#define IDX2ZHN(i) (assert(i), (ISLIDX(i) ? ps->zhains[(i)/2] : 0))
+
+#define CLS2TRD(c) (((Trd*)(c)) - 1)
+#define CLS2IDX(c) ((((Trd*)(c)) - 1)->idx)
+
+#define CLS2ACT(c) \
+  ((Act*)((assert((c)->learned)),assert((c)->size>2),ENDOFCLS(c)))
+
+#define VAR2LIT(v) (ps->lits + 2 * ((v) - ps->vars))
+#define VAR2RNK(v) (ps->rnks + ((v) - ps->vars))
+
+#define RNK2LIT(r) (ps->lits + 2 * ((r) - ps->rnks))
+#define RNK2VAR(r) (ps->vars + ((r) - ps->rnks))
+
+#define BLK_FILL_BYTES 8
+#define SIZE_OF_BLK (sizeof (Blk) - BLK_FILL_BYTES)
+
+#define PTR2BLK(void_ptr) \
+  ((void_ptr) ? (Blk*)(((char*)(void_ptr)) - SIZE_OF_BLK) : 0)
+
+#define AVERAGE(a,b) ((b) ? (((double)a) / (double)(b)) : 0.0)
+#define PERCENT(a,b) (100.0 * AVERAGE(a,b))
+
+#ifndef RCODE
+#define ABORT(msg) \
+  do { \
+    fputs ("*** picosat: " msg "\n", stderr); \
+    abort (); \
+  } while (0)
+#else
+#define ABORT(msg) \
+  do { \
+    Rf_error (msg); \
+  } while (0)
+#endif
+
+#define ABORTIF(cond,msg) \
+  do { \
+    if (!(cond)) break; \
+    ABORT (msg); \
+  } while (0)
+
+#define ZEROFLT        (0x00000000u)
+#define EPSFLT        (0x00000001u)
+#define INFFLT        (0xffffffffu)
+
+#define FLTCARRY    (1u << 25)
+#define FLTMSB        (1u << 24)
+#define FLTMAXMANTISSA    (FLTMSB - 1)
+
+#define FLTMANTISSA(d)    ((d) & FLTMAXMANTISSA)
+#define FLTEXPONENT(d)    ((int)((d) >> 24) - 128)
+
+#define FLTMINEXPONENT    (-128)
+#define FLTMAXEXPONENT    (127)
+
+#define CMPSWAPFLT(a,b) \
+  do { \
+    Flt tmp; \
+    if (((a) < (b))) \
+      { \
+    tmp = (a); \
+    (a) = (b); \
+    (b) = tmp; \
+      } \
+  } while (0)
+
+#define UNPACKFLT(u,m,e) \
+  do { \
+    (m) = FLTMANTISSA(u); \
+    (e) = FLTEXPONENT(u); \
+    (m) |= FLTMSB; \
+  } while (0)
+
+#define INSERTION_SORT_LIMIT 10
+
+#define SORTING_SWAP(T,p,q) \
+do { \
+  T tmp = *(q); \
+  *(q) = *(p); \
+  *(p) = tmp; \
+} while (0)
+
+#define SORTING_CMP_SWAP(T,cmp,p,q) \
+do { \
+  if ((cmp) (ps, *(p), *(q)) > 0) \
+    SORTING_SWAP (T, p, q); \
+} while(0)
+
+#define QUICKSORT_PARTITION(T,cmp,a,l,r) \
+do { \
+  T pivot; \
+  int j; \
+  i = (l) - 1;             /* result in 'i' */ \
+  j = (r); \
+  pivot = (a)[j]; \
+  for (;;) \
+    { \
+      while ((cmp) (ps, (a)[++i], pivot) < 0) \
+    ; \
+      while ((cmp) (ps, pivot, (a)[--j]) < 0) \
+        if (j == (l)) \
+      break; \
+      if (i >= j) \
+    break; \
+      SORTING_SWAP (T, (a) + i, (a) + j); \
+    } \
+  SORTING_SWAP (T, (a) + i, (a) + (r)); \
+} while(0)
+
+#define QUICKSORT(T,cmp,a,n) \
+do { \
+  int l = 0, r = (n) - 1, m, ll, rr, i; \
+  assert (ps->ihead == ps->indices); \
+  if (r - l <= INSERTION_SORT_LIMIT) \
+    break; \
+  for (;;) \
+    { \
+      m = (l + r) / 2; \
+      SORTING_SWAP (T, (a) + m, (a) + r - 1); \
+      SORTING_CMP_SWAP (T, cmp, (a) + l, (a) + r - 1); \
+      SORTING_CMP_SWAP (T, cmp, (a) + l, (a) + r); \
+      SORTING_CMP_SWAP (T, cmp, (a) + r - 1, (a) + r); \
+      QUICKSORT_PARTITION (T, cmp, (a), l + 1, r - 1); \
+      if (i - l < r - i) \
+    { \
+      ll = i + 1; \
+      rr = r; \
+      r = i - 1; \
+    } \
+      else \
+    { \
+      ll = l; \
+      rr = i - 1; \
+      l = i + 1; \
+    } \
+      if (r - l > INSERTION_SORT_LIMIT) \
+    { \
+      assert (rr - ll > INSERTION_SORT_LIMIT); \
+      if (ps->ihead == ps->eoi) \
+        ENLARGE (ps->indices, ps->ihead, ps->eoi); \
+      *ps->ihead++ = ll; \
+      if (ps->ihead == ps->eoi) \
+        ENLARGE (ps->indices, ps->ihead, ps->eoi); \
+      *ps->ihead++ = rr; \
+    } \
+      else if (rr - ll > INSERTION_SORT_LIMIT) \
+        { \
+      l = ll; \
+      r = rr; \
+    } \
+      else if (ps->ihead > ps->indices) \
+    { \
+      r = *--ps->ihead; \
+      l = *--ps->ihead; \
+    } \
+      else \
+    break; \
+    } \
+} while (0)
+
+#define INSERTION_SORT(T,cmp,a,n) \
+do { \
+  T pivot; \
+  int l = 0, r = (n) - 1, i, j; \
+  for (i = r; i > l; i--) \
+    SORTING_CMP_SWAP (T, cmp, (a) + i - 1, (a) + i); \
+  for (i = l + 2; i <= r; i++)  \
+    { \
+      j = i; \
+      pivot = (a)[i]; \
+      while ((cmp) (ps, pivot, (a)[j - 1]) < 0) \
+        { \
+      (a)[j] = (a)[j - 1]; \
+      j--; \
+    } \
+      (a)[j] = pivot; \
+    } \
+} while (0)
+
+#ifdef NDEBUG
+#define CHECK_SORTED(cmp,a,n) do { } while(0)
+#else
+#define CHECK_SORTED(cmp,a,n) \
+do { \
+  int i; \
+  for (i = 0; i < (n) - 1; i++) \
+    assert ((cmp) (ps, (a)[i], (a)[i + 1]) <= 0); \
+} while(0)
+#endif
+
+#define SORT(T,cmp,a,n) \
+do { \
+  T * aa = (a); \
+  int nn = (n); \
+  QUICKSORT (T, cmp, aa, nn); \
+  INSERTION_SORT (T, cmp, aa, nn); \
+  assert (ps->ihead == ps->indices); \
+  CHECK_SORTED (cmp, aa, nn); \
+} while (0)
+
+#define WRDSZ (sizeof (long) * 8)
+
+#ifdef RCODE
+#define fprintf(...) do { } while (0)
+#define vfprintf(...) do { } while (0)
+#define fputs(...) do { } while (0)
+#define fputc(...) do { } while (0)
+#endif
+
+typedef unsigned Flt;        /* 32 bit deterministic soft float */
+typedef Flt Act;        /* clause and variable activity */
+typedef struct Blk Blk;        /* allocated memory block */
+typedef struct Cls Cls;        /* clause */
+typedef struct Lit Lit;        /* literal */
+typedef struct Rnk Rnk;        /* variable to score mapping */
+typedef signed char Val;    /* TRUE, UNDEF, FALSE */
+typedef struct Var Var;        /* variable */
+#ifdef TRACE
+typedef struct Trd Trd;        /* trace data for clauses */
+typedef struct Zhn Zhn;        /* compressed chain (=zain) data */
+typedef unsigned char Znt;    /* compressed antecedent data */
+#endif
+
+#ifdef NO_BINARY_CLAUSES
+typedef struct Ltk Ltk;
+
+struct Ltk
+{
+  Lit ** start;
+  unsigned count : WRDSZ == 32 ? 27 : 32;
+  unsigned ldsize : WRDSZ == 32 ? 5 : 32;
+};
+#endif
+
+struct Lit
+{
+  Val val;
+};
+
+struct Var
+{
+  unsigned mark        : 1;    /*bit 1*/
+  unsigned resolved    : 1;    /*bit 2*/
+  unsigned phase    : 1;    /*bit 3*/
+  unsigned assigned    : 1;    /*bit 4*/
+  unsigned used        : 1;    /*bit 5*/
+  unsigned failed    : 1;    /*bit 6*/
+  unsigned internal    : 1;    /*bit 7*/
+  unsigned usedefphase  : 1;    /*bit 8*/
+  unsigned defphase     : 1;    /*bit 9*/
+  unsigned msspos       : 1;    /*bit 10*/
+  unsigned mssneg       : 1;    /*bit 11*/
+  unsigned humuspos     : 1;    /*bit 12*/
+  unsigned humusneg     : 1;    /*bit 13*/
+  unsigned partial      : 1;    /*bit 14*/
+#ifdef TRACE
+  unsigned core        : 1;    /*bit 15*/
+#endif
+  unsigned level;
+  Cls *reason;
+#ifndef NADC
+  Lit ** inado;
+  Lit ** ado;
+  Lit *** adotabpos;
+#endif
+};
+
+struct Rnk
+{
+  Act score;
+  unsigned pos : 30;            /* 0 iff not on heap */
+  unsigned moreimportant : 1;
+  unsigned lessimportant : 1;
+};
+
+struct Cls
+{
+  unsigned size;
+
+  unsigned collect:1;    /* bit 1 */
+  unsigned learned:1;    /* bit 2 */
+  unsigned locked:1;    /* bit 3 */
+  unsigned used:1;    /* bit 4 */
+#ifndef NDEBUG
+  unsigned connected:1;    /* bit 5 */
+#endif
+#ifdef TRACE
+  unsigned collected:1;    /* bit 6 */
+  unsigned core:1;    /* bit 7 */
+#endif
+
+#define LDMAXGLUE 25    /* 32 - 7 */
+#define MAXGLUE     ((1<<LDMAXGLUE)-1)
+
+  unsigned glue:LDMAXGLUE;
+
+  Cls *next[2];
+  Lit *lits[2];
+};
+
+#ifdef TRACE
+struct Zhn
+{
+  unsigned ref:31;
+  unsigned core:1;
+  Znt * liz;
+  Znt znt[0];
+};
+
+struct Trd
+{
+  unsigned idx;
+  Cls cls[0];
+};
+#endif
+
+struct Blk
+{
+#ifndef NDEBUG
+  union
+  {
+    size_t size;        /* this is what we really use */
+    void *as_two_ptrs[2];    /* 2 * sizeof (void*) alignment of data */
+  }
+  header;
+#endif
+  char data[BLK_FILL_BYTES];
+};
+
+enum State
+{
+  RESET = 0,
+  READY = 1,
+  SAT = 2,
+  UNSAT = 3,
+  UNKNOWN = 4,
+};
+
+enum Phase
+{
+  POSPHASE,
+  NEGPHASE,
+  JWLPHASE,
+  RNDPHASE,
+};
+
+struct PicoSAT
+{
+  enum State state;
+  enum Phase defaultphase;
+  int last_sat_call_result;
+
+  FILE *out;
+  char * prefix;
+  int verbosity;
+  int plain;
+  unsigned LEVEL;
+  unsigned max_var;
+  unsigned size_vars;
+
+  Lit *lits;
+  Var *vars;
+  Rnk *rnks;
+  Flt *jwh;
+  Cls **htps;
+#ifndef NDSC
+  Cls **dhtps;
+#endif
+#ifdef NO_BINARY_CLAUSES
+  Ltk *impls;
+  Cls impl, cimpl;
+  int implvalid, cimplvalid;
+#else
+  Cls **impls;
+#endif
+  Lit **trail, **thead, **eot, **ttail, ** ttail2;
+#ifndef NADC
+  Lit **ttailado;
+#endif
+  unsigned adecidelevel;
+  Lit **als, **alshead, **alstail, **eoals;
+  Lit **CLS, **clshead, **eocls;
+  int *rils, *rilshead, *eorils;
+  int *cils, *cilshead, *eocils;
+  int *fals, *falshead, *eofals;
+  int *mass, szmass;
+  int *mssass, szmssass;
+  int *mcsass, nmcsass, szmcsass;
+  int *humus, szhumus;
+  Lit *failed_assumption;
+  int extracted_all_failed_assumptions;
+  Rnk **heap, **hhead, **eoh;
+  Cls **oclauses, **ohead, **eoo;    /* original clauses */
+  Cls **lclauses, **lhead, ** EOL;    /* learned clauses */
+  int * soclauses, * sohead, * eoso; /* saved original clauses */
+  int saveorig;
+  int partial;
+#ifdef TRACE
+  int trace;
+  Zhn **zhains, **zhead, **eoz;
+  int ocore;
+#endif
+  FILE * rup;
+  int rupstarted;
+  int rupvariables;
+  int rupclauses;
+  Cls *mtcls;
+  Cls *conflict;
+  Lit **added, **ahead, **eoa;
+  Var **marked, **mhead, **eom;
+  Var **dfs, **dhead, **eod;
+  Cls **resolved, **rhead, **eor;
+  unsigned char *levels, *levelshead, *eolevels;
+  unsigned *dused, *dusedhead, *eodused;
+  unsigned char *buffer, *bhead, *eob;
+  Act vinc, lscore, ilvinc, ifvinc;
+#ifdef VISCORES
+  Act fvinc, nvinc;
+#endif
+  Act cinc, lcinc, ilcinc, fcinc;
+  unsigned srng;
+  size_t current_bytes;
+  size_t max_bytes;
+  size_t recycled;
+  double seconds, flseconds;
+  double entered;
+  unsigned nentered;
+  int measurealltimeinlib;
+  char *rline[2];
+  int szrline, RCOUNT;
+  double levelsum;
+  unsigned iterations;
+  int reports;
+  int lastrheader;
+  unsigned calls;
+  unsigned decisions;
+  unsigned restarts;
+  unsigned simps;
+  unsigned fsimplify;
+  unsigned isimplify;
+  unsigned reductions;
+  unsigned lreduce;
+  unsigned lreduceadjustcnt;
+  unsigned lreduceadjustinc;
+  unsigned lastreduceconflicts;
+  unsigned llocked;    /* locked large learned clauses */
+  unsigned lrestart;
+#ifdef NLUBY
+  unsigned drestart;
+  unsigned ddrestart;
+#else
+  unsigned lubycnt;
+  unsigned lubymaxdelta;
+  int waslubymaxdelta;
+#endif
+  unsigned long long lsimplify;
+  unsigned long long propagations;
+  unsigned long long lpropagations;
+  unsigned fixed;        /* top level assignments */
+#ifndef NFL
+  unsigned failedlits;
+  unsigned ifailedlits;
+  unsigned efailedlits;
+  unsigned flcalls;
+#ifdef STATS
+  unsigned flrounds;
+  unsigned long long flprops;
+  unsigned long long floopsed, fltried, flskipped;
+#endif
+  unsigned long long fllimit;
+  int simplifying;
+  Lit ** saved;
+  unsigned saved_size;
+#endif
+  unsigned conflicts;
+  unsigned contexts;
+  unsigned internals;
+  unsigned noclauses;    /* current number large original clauses */
+  unsigned nlclauses;    /* current number large learned clauses */
+  unsigned olits;        /* current literals in large original clauses */
+  unsigned llits;        /* current literals in large learned clauses */
+  unsigned oadded;        /* added original clauses */
+  unsigned ladded;        /* added learned clauses */
+  unsigned loadded;    /* added original large clauses */
+  unsigned lladded;    /* added learned large clauses */
+  unsigned addedclauses;    /* oadded + ladded */
+  unsigned vused;        /* used variables */
+  unsigned llitsadded;    /* added learned literals */
+  unsigned long long visits;
+#ifdef STATS
+  unsigned loused;        /* used large original clauses */
+  unsigned llused;        /* used large learned clauses */
+  unsigned long long bvisits;
+  unsigned long long tvisits;
+  unsigned long long lvisits;
+  unsigned long long othertrue;
+  unsigned long long othertrue2;
+  unsigned long long othertruel;
+  unsigned long long othertrue2u;
+  unsigned long long othertruelu;
+  unsigned long long ltraversals;
+  unsigned long long traversals;
+#ifdef TRACE
+  unsigned long long antecedents;
+#endif
+  unsigned uips;
+  unsigned znts;
+  unsigned assumptions;
+  unsigned rdecisions;
+  unsigned sdecisions;
+  size_t srecycled;
+  size_t rrecycled;
+  unsigned long long derefs;
+#endif
+  unsigned minimizedllits;
+  unsigned nonminimizedllits;
+#ifndef NADC
+  Lit *** ados, *** hados, *** eados;
+  Lit *** adotab;
+  unsigned nadotab;
+  unsigned szadotab;
+  Cls * adoconflict;
+  unsigned adoconflicts;
+  unsigned adoconflictlimit;
+  int addingtoado;
+  int adodisabled;
+#endif
+  unsigned long long flips;
+#ifdef STATS
+  unsigned long long FORCED;
+  unsigned long long assignments;
+  unsigned inclreduces;
+  unsigned staticphasedecisions;
+  unsigned skippedrestarts;
+#endif
+  int * indices, * ihead, *eoi;
+  unsigned sdflips;
+
+  unsigned long long saved_flips;
+  unsigned saved_max_var;
+  unsigned min_flipped;
+
+  void * emgr;
+  picosat_malloc enew;
+  picosat_realloc eresize;
+  picosat_free edelete;
+
+  struct {
+    void * state;
+    int (*function) (void *);
+  } interrupt;
+
+#ifdef VISCORES
+  FILE * fviscores;
+#endif
+};
+
+typedef PicoSAT PS;
+
+static Flt
+packflt (unsigned m, int e)
+{
+  Flt res;
+  assert (m < FLTMSB);
+  assert (FLTMINEXPONENT <= e);
+  assert (e <= FLTMAXEXPONENT);
+  res = m | ((unsigned)(e + 128) << 24);
+  return res;
+}
+
+static Flt
+base2flt (unsigned m, int e)
+{
+  if (!m)
+    return ZEROFLT;
+
+  if (m < FLTMSB)
+    {
+      do
+    {
+      if (e <= FLTMINEXPONENT)
+        return EPSFLT;
+
+      e--;
+      m <<= 1;
+
+    }
+      while (m < FLTMSB);
+    }
+  else
+    {
+      while (m >= FLTCARRY)
+    {
+      if (e >= FLTMAXEXPONENT)
+        return INFFLT;
+
+      e++;
+      m >>= 1;
+    }
+    }
+
+  m &= ~FLTMSB;
+  return packflt (m, e);
+}
+
+static Flt
+addflt (Flt a, Flt b)
+{
+  unsigned ma, mb, delta;
+  int ea, eb;
+
+  CMPSWAPFLT (a, b);
+  if (!b)
+    return a;
+
+  UNPACKFLT (a, ma, ea);
+  UNPACKFLT (b, mb, eb);
+
+  assert (ea >= eb);
+  delta = ea - eb;
+  if (delta < 32) mb >>= delta; else mb = 0;
+  if (!mb)
+    return a;
+
+  ma += mb;
+  if (ma & FLTCARRY)
+    {
+      if (ea == FLTMAXEXPONENT)
+    return INFFLT;
+
+      ea++;
+      ma >>= 1;
+    }
+
+  assert (ma < FLTCARRY);
+  ma &= FLTMAXMANTISSA;
+
+  return packflt (ma, ea);
+}
+
+static Flt
+mulflt (Flt a, Flt b)
+{
+  unsigned ma, mb;
+  unsigned long long accu;
+  int ea, eb;
+
+  CMPSWAPFLT (a, b);
+  if (!b)
+    return ZEROFLT;
+
+  UNPACKFLT (a, ma, ea);
+  UNPACKFLT (b, mb, eb);
+
+  ea += eb;
+  ea += 24;
+  if (ea > FLTMAXEXPONENT)
+    return INFFLT;
+
+  if (ea < FLTMINEXPONENT)
+    return EPSFLT;
+
+  accu = ma;
+  accu *= mb;
+  accu >>= 24;
+
+  if (accu >= FLTCARRY)
+    {
+      if (ea == FLTMAXEXPONENT)
+    return INFFLT;
+
+      ea++;
+      accu >>= 1;
+
+      if (accu >= FLTCARRY)
+    return INFFLT;
+    }
+
+  assert (accu < FLTCARRY);
+  assert (accu & FLTMSB);
+
+  ma = accu;
+  ma &= ~FLTMSB;
+
+  return packflt (ma, ea);
+}
+
+static Flt
+ascii2flt (const char *str)
+{
+  Flt ten = base2flt (10, 0);
+  Flt onetenth = base2flt (26843546, -28);
+  Flt res = ZEROFLT, tmp, base;
+  const char *p = str;
+  int ch;
+
+  ch = *p++;
+
+  if (ch != '.')
+    {
+      if (!isdigit (ch))
+    return INFFLT;    /* better abort ? */
+
+      res = base2flt (ch - '0', 0);
+
+      while ((ch = *p++))
+    {
+      if (ch == '.')
+        break;
+
+      if (!isdigit (ch))
+        return INFFLT;    /* better abort? */
+
+      res = mulflt (res, ten);
+      tmp = base2flt (ch - '0', 0);
+      res = addflt (res, tmp);
+    }
+    }
+
+  if (ch == '.')
+    {
+      ch = *p++;
+      if (!isdigit (ch))
+    return INFFLT;    /* better abort ? */
+
+      base = onetenth;
+      tmp = mulflt (base2flt (ch - '0', 0), base);
+      res = addflt (res, tmp);
+
+      while ((ch = *p++))
+    {
+      if (!isdigit (ch))
+        return INFFLT;    /* better abort? */
+
+      base = mulflt (base, onetenth);
+      tmp = mulflt (base2flt (ch - '0', 0), base);
+      res = addflt (res, tmp);
+    }
+    }
+
+  return res;
+}
+
+#if defined(VISCORES)
+
+static double
+flt2double (Flt f)
+{
+  double res;
+  unsigned m;
+  int e, i;
+
+  UNPACKFLT (f, m, e);
+  res = m;
+
+  if (e < 0)
+    {
+      for (i = e; i < 0; i++)
+    res *= 0.5;
+    }
+  else
+    {
+      for (i = 0; i < e; i++)
+    res *= 2.0;
+    }
+
+  return res;
+}
+
+#endif
+
+static int
+log2flt (Flt a)
+{
+  return FLTEXPONENT (a) + 24;
+}
+
+static int
+cmpflt (Flt a, Flt b)
+{
+  if (a < b)
+    return -1;
+
+  if (a > b)
+    return 1;
+
+  return 0;
+}
+
+static void *
+new (PS * ps, size_t size)
+{
+  size_t bytes;
+  Blk *b;
+  
+  if (!size)
+    return 0;
+
+  bytes = size + SIZE_OF_BLK;
+
+  if (ps->enew)
+    b = ps->enew (ps->emgr, bytes);
+  else
+    b = malloc (bytes);
+
+  ABORTIF (!b, "out of memory in 'new'");
+#ifndef NDEBUG
+  b->header.size = size;
+#endif
+  ps->current_bytes += size;
+  if (ps->current_bytes > ps->max_bytes)
+    ps->max_bytes = ps->current_bytes;
+  return b->data;
+}
+
+static void
+delete (PS * ps, void *void_ptr, size_t size)
+{
+  size_t bytes;
+  Blk *b;
+
+  if (!void_ptr)
+    {
+      assert (!size);
+      return;
+    }
+
+  assert (size);
+  b = PTR2BLK (void_ptr);
+
+  assert (size <= ps->current_bytes);
+  ps->current_bytes -= size;
+
+  assert (b->header.size == size);
+
+  bytes = size + SIZE_OF_BLK;
+  if (ps->edelete)
+    ps->edelete (ps->emgr, b, bytes);
+  else
+    free (b);
+}
+
+static void *
+resize (PS * ps, void *void_ptr, size_t old_size, size_t new_size)
+{
+  size_t old_bytes, new_bytes;
+  Blk *b;
+
+  b = PTR2BLK (void_ptr);
+
+  assert (old_size <= ps->current_bytes);
+  ps->current_bytes -= old_size;
+
+  if ((old_bytes = old_size))
+    {
+      assert (old_size && b && b->header.size == old_size);
+      old_bytes += SIZE_OF_BLK;
+    }
+  else
+    assert (!b);
+
+  if ((new_bytes = new_size))
+    new_bytes += SIZE_OF_BLK;
+
+  if (ps->eresize)
+    b = ps->eresize (ps->emgr, b, old_bytes, new_bytes);
+  else
+    b = realloc (b, new_bytes);
+
+  if (!new_size)
+    {
+      assert (!b);
+      return 0;
+    }
+
+  ABORTIF (!b, "out of memory in 'resize'");
+#ifndef NDEBUG
+  b->header.size = new_size;
+#endif
+
+  ps->current_bytes += new_size;
+  if (ps->current_bytes > ps->max_bytes)
+    ps->max_bytes = ps->current_bytes;
+
+  return b->data;
+}
+
+static unsigned
+int2unsigned (int l)
+{
+  return (l < 0) ? 1 + 2 * -l : 2 * l;
+}
+
+static Lit *
+int2lit (PS * ps, int l)
+{
+  return ps->lits + int2unsigned (l);
+}
+
+static Lit **
+end_of_lits (Cls * c)
+{
+  return (Lit**)c->lits + c->size;
+}
+
+#if !defined(NDEBUG) || defined(LOGGING)
+
+static void
+dumplits (PS * ps, Lit ** l, Lit ** end)
+{
+  int first;
+  Lit ** p;
+
+  if (l == end)
+    {
+      /* empty clause */
+    }
+  else if (l + 1 == end)
+    {
+      fprintf (ps->out, "%d ", LIT2INT (l[0]));
+    }
+  else
+    {
+      assert (l + 2 <= end);
+      first = (abs (LIT2INT (l[0])) > abs (LIT2INT (l[1])));
+      fprintf (ps->out, "%d ", LIT2INT (l[first]));
+      fprintf (ps->out, "%d ", LIT2INT (l[!first]));
+      for (p = l + 2; p < end; p++)
+     fprintf (ps->out, "%d ", LIT2INT (*p));
+    }
+
+  fputc ('0', ps->out);
+}
+
+static void
+dumpcls (PS * ps, Cls * c)
+{
+  Lit **end;
+
+  if (c)
+    {
+      end = end_of_lits (c);
+      dumplits (ps, c->lits, end);
+#ifdef TRACE
+      if (ps->trace)
+     fprintf (ps->out, " clause(%u)", CLS2IDX (c));
+#endif
+    }
+  else
+    fputs ("DECISION", ps->out);
+}
+
+static void
+dumpclsnl (PS * ps, Cls * c)
+{
+  dumpcls (ps, c);
+  fputc ('\n', ps->out);
+}
+
+void
+dumpcnf (PS * ps)
+{
+  Cls **p, *c;
+
+  for (p = SOC; p != EOC; p = NXC (p))
+    {
+      c = *p;
+
+      if (!c)
+    continue;
+
+#ifdef TRACE
+      if (c->collected)
+    continue;
+#endif
+
+      dumpclsnl (ps, *p);
+    }
+}
+
+#endif
+
+static void
+delete_prefix (PS * ps)
+{
+  if (!ps->prefix)
+    return;
+    
+  delete (ps, ps->prefix, strlen (ps->prefix) + 1);
+  ps->prefix = 0;
+}
+
+static void
+new_prefix (PS * ps, const char * str)
+{
+  delete_prefix (ps);
+  assert (str);
+  ps->prefix = new (ps, strlen (str) + 1);
+  strcpy (ps->prefix, str);
+}
+
+static PS *
+init (void * pmgr,
+      picosat_malloc pnew, picosat_realloc presize, picosat_free pdelete)
+{
+  PS * ps;
+
+#if 0
+  int count = 3 - !pnew - !presize - !pdelete;
+
+  ABORTIF (count && !pnew, "API usage: missing 'picosat_set_new'");
+  ABORTIF (count && !presize, "API usage: missing 'picosat_set_resize'");
+  ABORTIF (count && !pdelete, "API usage: missing 'picosat_set_delete'");
+#endif
+
+  ps = pnew ? pnew (pmgr, sizeof *ps) : malloc (sizeof *ps);
+  ABORTIF (!ps, "failed to allocate memory for PicoSAT manager");
+  memset (ps, 0, sizeof *ps);
+
+  ps->emgr = pmgr;
+  ps->enew = pnew;
+  ps->eresize = presize;
+  ps->edelete = pdelete;
+
+  ps->size_vars = 1;
+  ps->state = RESET;
+  ps->defaultphase = JWLPHASE;
+#ifdef TRACE
+  ps->ocore = -1;
+#endif
+  ps->lastrheader = -2;
+#ifndef NADC
+  ps->adoconflictlimit = UINT_MAX;
+#endif
+  ps->min_flipped = UINT_MAX;
+
+  NEWN (ps->lits, 2 * ps->size_vars);
+  NEWN (ps->jwh, 2 * ps->size_vars);
+  NEWN (ps->htps, 2 * ps->size_vars);
+#ifndef NDSC
+  NEWN (ps->dhtps, 2 * ps->size_vars);
+#endif
+  NEWN (ps->impls, 2 * ps->size_vars);
+  NEWN (ps->vars, ps->size_vars);
+  NEWN (ps->rnks, ps->size_vars);
+
+  /* because '0' pos denotes not on heap
+   */
+  ENLARGE (ps->heap, ps->hhead, ps->eoh);
+  ps->hhead = ps->heap + 1;
+
+  ps->vinc = base2flt (1, 0);        /* initial var activity */
+  ps->ifvinc = ascii2flt ("1.05");    /* var score rescore factor */
+#ifdef VISCORES
+  ps->fvinc = ascii2flt ("0.9523809");    /*     1/f =     1/1.05 */
+  ps->nvinc = ascii2flt ("0.0476191");    /* 1 - 1/f = 1 - 1/1.05 */
+#endif
+  ps->lscore = base2flt (1, 90);    /* var activity rescore limit */
+  ps->ilvinc = base2flt (1, -90);    /* inverse of 'lscore' */
+
+  ps->cinc = base2flt (1, 0);        /* initial clause activity */
+  ps->fcinc = ascii2flt ("1.001");    /* cls activity rescore factor */
+  ps->lcinc = base2flt (1, 90);        /* cls activity rescore limit */
+  ps->ilcinc = base2flt (1, -90);    /* inverse of 'ilcinc' */
+
+  ps->lreduceadjustcnt = ps->lreduceadjustinc = 100;
+  ps->lpropagations = ~0ull;
+
+#ifndef RCODE
+  ps->out = stdout;
+#else
+  ps->out = 0;
+#endif
+  new_prefix (ps, "c ");
+  ps->verbosity = 0;
+  ps->plain = 0;
+
+#ifdef NO_BINARY_CLAUSES
+  memset (&ps->impl, 0, sizeof (ps->impl));
+  ps->impl.size = 2;
+
+  memset (&ps->cimpl, 0, sizeof (ps->impl));
+  ps->cimpl.size = 2;
+#endif
+
+#ifdef VISCORES
+  ps->fviscores = popen (
+    "/usr/bin/gnuplot -background black"
+    " -xrm 'gnuplot*textColor:white'"
+    " -xrm 'gnuplot*borderColor:white'"
+    " -xrm 'gnuplot*axisColor:white'"
+    , "w");
+  fprintf (ps->fviscores, "unset key\n");
+  // fprintf (ps->fviscores, "set log y\n");
+  fflush (ps->fviscores);
+  system ("rm -rf /tmp/picosat-viscores");
+  system ("mkdir /tmp/picosat-viscores");
+  system ("mkdir /tmp/picosat-viscores/data");
+#ifdef WRITEGIF
+  system ("mkdir /tmp/picosat-viscores/gif");
+  fprintf (ps->fviscores,
+           "set terminal gif giant animate opt size 1024,768 x000000 xffffff"
+       "\n");
+
+  fprintf (ps->fviscores,
+           "set output \"/tmp/picosat-viscores/gif/animated.gif\"\n");
+#endif
+#endif
+  ps->defaultphase = JWLPHASE;
+  ps->state = READY;
+  ps->last_sat_call_result = 0;
+
+  return ps;
+}
+
+static size_t
+bytes_clause (PS * ps, unsigned size, unsigned learned)
+{
+  size_t res;
+
+  res = sizeof (Cls);
+  res += size * sizeof (Lit *);
+  res -= 2 * sizeof (Lit *);
+
+  if (learned && size > 2)
+    res += sizeof (Act);    /* add activity */
+
+#ifdef TRACE
+  if (ps->trace)
+    res += sizeof (Trd);    /* add trace data */
+#else
+  (void) ps;
+#endif
+
+  return res;
+}
+
+static Cls *
+new_clause (PS * ps, unsigned size, unsigned learned)
+{
+  size_t bytes;
+  void * tmp;
+#ifdef TRACE
+  Trd *trd;
+#endif
+  Cls *res;
+
+  bytes = bytes_clause (ps, size, learned);
+  tmp = new (ps, bytes);
+
+#ifdef TRACE
+  if (ps->trace)
+    {
+      trd = tmp;
+
+      if (learned)
+    trd->idx = LIDX2IDX (ps->lhead - ps->lclauses);
+      else
+    trd->idx = OIDX2IDX (ps->ohead - ps->oclauses);
+
+      res = trd->cls;
+    }
+  else
+#endif
+    res = tmp;
+
+  res->size = size;
+  res->learned = learned;
+
+  res->collect = 0;
+#ifndef NDEBUG
+  res->connected = 0;
+#endif
+  res->locked = 0;
+  res->used = 0;
+#ifdef TRACE
+  res->core = 0;
+  res->collected = 0;
+#endif
+
+  if (learned && size > 2)
+    {
+      Act * p = CLS2ACT (res);
+      *p = ps->cinc;
+    }
+
+  return res;
+}
+
+static void
+delete_clause (PS * ps, Cls * c)
+{
+  size_t bytes;
+#ifdef TRACE
+  Trd *trd;
+#endif
+
+  bytes = bytes_clause (ps, c->size, c->learned);
+
+#ifdef TRACE
+  if (ps->trace)
+    {
+      trd = CLS2TRD (c);
+      delete (ps, trd, bytes);
+    }
+  else
+#endif
+    delete (ps, c, bytes);
+}
+
+static void
+delete_clauses (PS * ps)
+{
+  Cls **p;
+  for (p = SOC; p != EOC; p = NXC (p))
+    if (*p)
+      delete_clause (ps, *p);
+
+  DELETEN (ps->oclauses, ps->eoo - ps->oclauses);
+  DELETEN (ps->lclauses, ps->EOL - ps->lclauses);
+
+  ps->ohead = ps->eoo = ps->lhead = ps->EOL = 0;
+}
+
+#ifdef TRACE
+
+static void
+delete_zhain (PS * ps, Zhn * zhain)
+{
+  const Znt *p, *znt;
+
+  assert (zhain);
+
+  znt = zhain->znt;
+  for (p = znt; *p; p++)
+    ;
+
+  delete (ps, zhain, sizeof (Zhn) + (p - znt) + 1);
+}
+
+static void
+delete_zhains (PS * ps)
+{
+  Zhn **p, *z;
+  for (p = ps->zhains; p < ps->zhead; p++)
+    if ((z = *p))
+      delete_zhain (ps, z);
+
+  DELETEN (ps->zhains, ps->eoz - ps->zhains);
+  ps->eoz = ps->zhead = 0;
+}
+
+#endif
+
+#ifdef NO_BINARY_CLAUSES
+static void
+lrelease (PS * ps, Ltk * stk)
+{
+  if (stk->start)
+    DELETEN (stk->start, (1 << (stk->ldsize)));
+  memset (stk, 0, sizeof (*stk));
+}
+#endif
+
+#ifndef NADC
+
+static unsigned
+llength (Lit ** a)
+{
+  Lit ** p;
+  for (p = a; *p; p++)
+    ;
+  return p - a;
+}
+
+static void
+resetadoconflict (PS * ps)
+{
+  assert (ps->adoconflict);
+  delete_clause (ps, ps->adoconflict);
+  ps->adoconflict = 0;
+}
+
+static void
+reset_ados (PS * ps)
+{
+  Lit *** p;
+
+  for (p = ps->ados; p < ps->hados; p++)
+    DELETEN (*p, llength (*p) + 1);
+
+  DELETEN (ps->ados, ps->eados - ps->ados);
+  ps->hados = ps->eados = 0;
+
+  DELETEN (ps->adotab, ps->szadotab);
+  ps->szadotab = ps->nadotab = 0;
+
+  if (ps->adoconflict)
+    resetadoconflict (ps);
+
+  ps->adoconflicts = 0;
+  ps->adoconflictlimit = UINT_MAX;
+  ps->adodisabled = 0;
+}
+
+#endif
+
+static void
+reset (PS * ps)
+{
+  ABORTIF (!ps ||
+           ps->state == RESET, "API usage: reset without initialization");
+
+  delete_clauses (ps);
+#ifdef TRACE
+  delete_zhains (ps);
+#endif
+#ifdef NO_BINARY_CLAUSES
+  {
+    unsigned i;
+    for (i = 2; i <= 2 * ps->max_var + 1; i++)
+      lrelease (ps, ps->impls + i);
+  }
+#endif
+#ifndef NADC
+  reset_ados (ps);
+#endif
+#ifndef NFL
+  DELETEN (ps->saved, ps->saved_size);
+#endif
+  DELETEN (ps->htps, 2 * ps->size_vars);
+#ifndef NDSC
+  DELETEN (ps->dhtps, 2 * ps->size_vars);
+#endif
+  DELETEN (ps->impls, 2 * ps->size_vars);
+  DELETEN (ps->lits, 2 * ps->size_vars);
+  DELETEN (ps->jwh, 2 * ps->size_vars);
+  DELETEN (ps->vars, ps->size_vars);
+  DELETEN (ps->rnks, ps->size_vars);
+  DELETEN (ps->trail, ps->eot - ps->trail);
+  DELETEN (ps->heap, ps->eoh - ps->heap);
+  DELETEN (ps->als, ps->eoals - ps->als);
+  DELETEN (ps->CLS, ps->eocls - ps->CLS);
+  DELETEN (ps->rils, ps->eorils - ps->rils);
+  DELETEN (ps->cils, ps->eocils - ps->cils);
+  DELETEN (ps->fals, ps->eofals - ps->fals);
+  DELETEN (ps->mass, ps->szmass);
+  DELETEN (ps->mssass, ps->szmssass);
+  DELETEN (ps->mcsass, ps->szmcsass);
+  DELETEN (ps->humus, ps->szhumus);
+  DELETEN (ps->added, ps->eoa - ps->added);
+  DELETEN (ps->marked, ps->eom - ps->marked);
+  DELETEN (ps->dfs, ps->eod - ps->dfs);
+  DELETEN (ps->resolved, ps->eor - ps->resolved);
+  DELETEN (ps->levels, ps->eolevels - ps->levels);
+  DELETEN (ps->dused, ps->eodused - ps->dused);
+  DELETEN (ps->buffer, ps->eob - ps->buffer);
+  DELETEN (ps->indices, ps->eoi - ps->indices);
+  DELETEN (ps->soclauses, ps->eoso - ps->soclauses);
+  delete_prefix (ps);
+  delete (ps, ps->rline[0], ps->szrline);
+  delete (ps, ps->rline[1], ps->szrline);
+  assert (getenv ("LEAK") || !ps->current_bytes);    /* found leak if failing */
+#ifdef VISCORES
+  pclose (ps->fviscores);
+#endif
+  if (ps->edelete)
+    ps->edelete (ps->emgr, ps, sizeof *ps);
+  else
+    free (ps);
+}
+
+inline static void
+tpush (PS * ps, Lit * lit)
+{
+  assert (ps->lits < lit && lit <= ps->lits + 2* ps->max_var + 1);
+  if (ps->thead == ps->eot)
+    {
+      unsigned ttail2count = ps->ttail2 - ps->trail;
+      unsigned ttailcount = ps->ttail - ps->trail;
+#ifndef NADC
+      unsigned ttailadocount = ps->ttailado - ps->trail;
+#endif
+      ENLARGE (ps->trail, ps->thead, ps->eot);
+      ps->ttail = ps->trail + ttailcount;
+      ps->ttail2 = ps->trail + ttail2count;
+#ifndef NADC
+      ps->ttailado = ps->trail + ttailadocount;
+#endif
+    }
+
+  *ps->thead++ = lit;
+}
+
+static void
+assign_reason (PS * ps, Var * v, Cls * reason)
+{
+#if defined(NO_BINARY_CLAUSES) && !defined(NDEBUG)
+  assert (reason != &ps->impl);
+#else
+  (void) ps;
+#endif
+  v->reason = reason;
+}
+
+static void
+assign_phase (PS * ps, Lit * lit)
+{
+  unsigned new_phase, idx;
+  Var * v = LIT2VAR (lit);
+
+#ifndef NFL
+  /* In 'simplifying' mode we only need to keep 'min_flipped' up to date if
+   * we force assignments on the top level.   The other assignments will be
+   * undone and thus we can keep the old saved value of the phase.
+   */
+  if (!ps->LEVEL || !ps->simplifying)
+#endif
+    {
+      new_phase = (LIT2SGN (lit) > 0);
+
+      if (v->assigned)
+    {
+      ps->sdflips -= ps->sdflips/FFLIPPED;
+
+      if (new_phase != v->phase)
+        {
+          assert (FFLIPPEDPREC >= FFLIPPED);
+          ps->sdflips += FFLIPPEDPREC / FFLIPPED;
+          ps->flips++;
+
+          idx = LIT2IDX (lit);
+          if (idx < ps->min_flipped)
+        ps->min_flipped = idx;
+
+              NOLOG (fprintf (ps->out,
+                          "%sflipped %d\n",
+                   ps->prefix, LIT2INT (lit)));
+        }
+    }
+
+      v->phase = new_phase;
+      v->assigned = 1;
+    }
+
+  lit->val = TRUE;
+  NOTLIT (lit)->val = FALSE;
+}
+
+inline static void
+assign (PS * ps, Lit * lit, Cls * reason)
+{
+  Var * v = LIT2VAR (lit);
+  assert (lit->val == UNDEF);
+#ifdef STATS
+  ps->assignments++;
+#endif
+  v->level = ps->LEVEL;
+  assign_phase (ps, lit);
+  assign_reason (ps, v, reason);
+  tpush (ps, lit);
+}
+
+inline static int
+cmp_added (PS * ps, Lit * k, Lit * l)
+{
+  Val a = k->val, b = l->val;
+  Var *u, *v;
+  int res;
+
+  if (a == UNDEF && b != UNDEF)
+    return -1;
+
+  if (a != UNDEF && b == UNDEF)
+    return 1;
+
+  u = LIT2VAR (k);
+  v = LIT2VAR (l);
+
+  if (a != UNDEF)
+    {
+      assert (b != UNDEF);
+      res = v->level - u->level;
+      if (res)
+    return res;        /* larger level first */
+    }
+
+  res = cmpflt (VAR2RNK (u)->score, VAR2RNK (v)->score);
+  if (res)
+    return res;            /* smaller activity first */
+
+  return u - v;            /* smaller index first */
+}
+
+static void
+sorttwolits (Lit ** v)
+{
+  Lit * a = v[0], * b = v[1];
+
+  assert (a != b);
+
+  if (a < b)
+    return;
+
+  v[0] = b;
+  v[1] = a;
+}
+
+inline static void
+sortlits (PS * ps, Lit ** v, unsigned size)
+{
+  if (size == 2)
+    sorttwolits (v);    /* same order with and with out 'NO_BINARY_CLAUSES' */
+  else
+    SORT (Lit *, cmp_added, v, size);
+}
+
+#ifdef NO_BINARY_CLAUSES
+static Cls *
+setimpl (PS * ps, Lit * a, Lit * b)
+{
+  assert (!ps->implvalid);
+  assert (ps->impl.size == 2);
+
+  ps->impl.lits[0] = a;
+  ps->impl.lits[1] = b;
+
+  sorttwolits (ps->impl.lits);
+  ps->implvalid = 1;
+
+  return &ps->impl;
+}
+
+static void
+resetimpl (PS * ps)
+{
+  ps->implvalid = 0;
+}
+
+static Cls *
+setcimpl (PS * ps, Lit * a, Lit * b)
+{
+  assert (!ps->cimplvalid);
+  assert (ps->cimpl.size == 2);
+
+  ps->cimpl.lits[0] = a;
+  ps->cimpl.lits[1] = b;
+
+  sorttwolits (ps->cimpl.lits);
+  ps->cimplvalid = 1;
+
+  return &ps->cimpl;
+}
+
+static void
+resetcimpl (PS * ps)
+{
+  assert (ps->cimplvalid);
+  ps->cimplvalid = 0;
+}
+
+#endif
+
+static int
+cmp_ptr (PS * ps, void *l, void *k)
+{
+  (void) ps;
+  return ((char*)l) - (char*)k;        /* arbitrarily already reverse */
+}
+
+static int
+cmp_rnk (Rnk * r, Rnk * s)
+{
+  if (!r->moreimportant && s->moreimportant)
+    return -1;
+
+  if (r->moreimportant && !s->moreimportant)
+    return 1;
+
+  if (!r->lessimportant && s->lessimportant)
+    return 1;
+
+  if (r->lessimportant && !s->lessimportant)
+    return -1;
+
+  if (r->score < s->score)
+    return -1;
+
+  if (r->score > s->score)
+    return 1;
+
+  return -cmp_ptr (0, r, s);
+}
+
+static void
+hup (PS * ps, Rnk * v)
+{
+  int upos, vpos;
+  Rnk *u;
+
+#ifndef NFL
+  assert (!ps->simplifying);
+#endif
+
+  vpos = v->pos;
+
+  assert (0 < vpos);
+  assert (vpos < ps->hhead - ps->heap);
+  assert (ps->heap[vpos] == v);
+
+  while (vpos > 1)
+    {
+      upos = vpos / 2;
+
+      u = ps->heap[upos];
+
+      if (cmp_rnk (u, v) > 0)
+    break;
+
+      ps->heap[vpos] = u;
+      u->pos = vpos;
+
+      vpos = upos;
+    }
+
+  ps->heap[vpos] = v;
+  v->pos = vpos;
+}
+
+static Cls *add_simplified_clause (PS *, int);
+
+inline static void
+add_antecedent (PS * ps, Cls * c)
+{
+  assert (c);
+
+#ifdef NO_BINARY_CLAUSES
+  if (ISLITREASON (c))
+    return;
+
+  if (c == &ps->impl)
+    return;
+#elif defined(STATS) && defined(TRACE)
+  ps->antecedents++;
+#endif
+  if (ps->rhead == ps->eor)
+    ENLARGE (ps->resolved, ps->rhead, ps->eor);
+
+  assert (ps->rhead < ps->eor);
+  *ps->rhead++ = c;
+}
+
+#ifdef TRACE
+
+#ifdef NO_BINARY_CLAUSES
+#error "can not combine TRACE and NO_BINARY_CLAUSES"
+#endif
+
+#endif /* TRACE */
+
+static void
+add_lit (PS * ps, Lit * lit)
+{
+  assert (lit);
+
+  if (ps->ahead == ps->eoa)
+    ENLARGE (ps->added, ps->ahead, ps->eoa);
+
+  *ps->ahead++ = lit;
+}
+
+static void
+push_var_as_marked (PS * ps, Var * v)
+{
+  if (ps->mhead == ps->eom)
+    ENLARGE (ps->marked, ps->mhead, ps->eom);
+
+  *ps->mhead++ = v;
+}
+
+static void
+mark_var (PS * ps, Var * v)
+{
+  assert (!v->mark);
+  v->mark = 1;
+  push_var_as_marked (ps, v);
+}
+
+#ifdef NO_BINARY_CLAUSES
+
+static Cls *
+impl2reason (PS * ps, Lit * lit)
+{
+  Lit * other;
+  Cls * res;
+  other = ps->impl.lits[0];
+  if (lit == other)
+    other = ps->impl.lits[1];
+  assert (other->val == FALSE);
+  res = LIT2REASON (NOTLIT (other));
+  resetimpl (ps);
+  return res;
+}
+
+#endif
+
+/* Whenever we have a top level derived unit we really should derive a unit
+ * clause otherwise the resolutions in 'add_simplified_clause' become
+ * incorrect.
+ */
+static Cls *
+resolve_top_level_unit (PS * ps, Lit * lit, Cls * reason)
+{
+  unsigned count_resolved;
+  Lit **p, **eol, *other;
+  Var *u, *v;
+
+  assert (ps->rhead == ps->resolved);
+  assert (ps->ahead == ps->added);
+
+  add_lit (ps, lit);
+  add_antecedent (ps, reason);
+  count_resolved = 1;
+  v = LIT2VAR (lit);
+
+  eol = end_of_lits (reason);
+  for (p = reason->lits; p < eol; p++)
+    {
+      other = *p;
+      u = LIT2VAR (other);
+      if (u == v)
+    continue;
+
+      add_antecedent (ps, u->reason);
+      count_resolved++;
+    }
+
+  /* Some of the literals could be assumptions.  If at least one
+   * variable is not an assumption, we should resolve.
+   */
+  if (count_resolved >= 2)
+    {
+#ifdef NO_BINARY_CLAUSES
+      if (reason == &ps->impl)
+    resetimpl (ps);
+#endif
+      reason = add_simplified_clause (ps, 1);
+#ifdef NO_BINARY_CLAUSES
+      if (reason->size == 2)
+    {
+      assert (reason == &ps->impl);
+      reason = impl2reason (ps, lit);
+    }
+#endif
+      assign_reason (ps, v, reason);
+    }
+  else
+    {
+      ps->ahead = ps->added;
+      ps->rhead = ps->resolved;
+    }
+
+  return reason;
+}
+
+static void
+fixvar (PS * ps, Var * v)
+{
+  Rnk * r;
+
+  assert (VAR2LIT (v) != UNDEF);
+  assert (!v->level);
+
+  ps->fixed++;
+
+  r = VAR2RNK (v);
+  r->score = INFFLT;
+
+#ifndef NFL
+  if (ps->simplifying)
+    return;
+#endif
+
+  if (!r->pos)
+    return;
+
+  hup (ps, r);
+}
+
+static void
+use_var (PS * ps, Var * v)
+{
+  if (v->used)
+    return;
+
+  v->used = 1;
+  ps->vused++;
+}
+
+static void
+assign_forced (PS * ps, Lit * lit, Cls * reason)
+{
+  Var *v;
+
+  assert (reason);
+  assert (lit->val == UNDEF);
+
+#ifdef STATS
+  ps->FORCED++;
+#endif
+  assign (ps, lit, reason);
+
+#ifdef NO_BINARY_CLAUSES
+  assert (reason != &ps->impl);
+  if (ISLITREASON (reason))
+    {
+      reason = setimpl (ps, lit, NOTLIT (REASON2LIT (reason)));
+      assert (reason);
+    }
+#endif
+  LOG ( fprintf (ps->out,
+                "%sassign %d at level %d by ",
+                ps->prefix, LIT2INT (lit), ps->LEVEL);
+       dumpclsnl (ps, reason));
+
+  v = LIT2VAR (lit);
+  if (!ps->LEVEL)
+    use_var (ps, v);
+
+  if (!ps->LEVEL && reason->size > 1)
+    {
+      reason = resolve_top_level_unit (ps, lit, reason);
+      assert (reason);
+    }
+
+#ifdef NO_BINARY_CLAUSES
+  if (ISLITREASON (reason) || reason == &ps->impl)
+    {
+      /* DO NOTHING */
+    }
+  else
+#endif
+    {
+      assert (!reason->locked);
+      reason->locked = 1;
+      if (reason->learned && reason->size > 2)
+    ps->llocked++;
+    }
+
+#ifdef NO_BINARY_CLAUSES
+  if (reason == &ps->impl)
+    resetimpl (ps);
+#endif
+
+  if (!ps->LEVEL)
+    fixvar (ps, v);
+}
+
+#ifdef NO_BINARY_CLAUSES
+
+static void
+lpush (PS * ps, Lit * lit, Cls * c)
+{
+  int pos = (c->lits[0] == lit);
+  Ltk * s = LIT2IMPLS (lit);
+  unsigned oldsize, newsize;
+
+  assert (c->size == 2);
+
+  if (!s->start)
+    {
+      assert (!s->count);
+      assert (!s->ldsize);
+      NEWN (s->start, 1);
+    }
+  else
+    {
+      oldsize = (1 << (s->ldsize));
+      assert (s->count <= oldsize);
+      if (s->count == oldsize)
+    {
+      newsize = 2 * oldsize;
+      RESIZEN (s->start, oldsize, newsize);
+      s->ldsize++;
+    }
+    }
+
+  s->start[s->count++] = c->lits[pos];
+}
+
+#endif
+
+static void
+connect_head_tail (PS * ps, Lit * lit, Cls * c)
+{
+  Cls ** s;
+  assert (c->size >= 1);
+  if (c->size == 2)
+    {
+#ifdef NO_BINARY_CLAUSES
+      lpush (ps, lit, c);
+      return;
+#else
+      s = LIT2IMPLS (lit);
+#endif
+    }
+  else
+    s = LIT2HTPS (lit);
+
+  if (c->lits[0] != lit)
+    {
+      assert (c->size >= 2);
+      assert (c->lits[1] == lit);
+      c->next[1] = *s;
+    }
+  else
+    c->next[0] = *s;
+
+  *s = c;
+}
+
+#ifdef TRACE
+static void
+zpush (PS * ps, Zhn * zhain)
+{
+  assert (ps->trace);
+
+  if (ps->zhead == ps->eoz)
+    ENLARGE (ps->zhains, ps->zhead, ps->eoz);
+
+  *ps->zhead++ = zhain;
+}
+
+static int
+cmp_resolved (PS * ps, Cls * c, Cls * d)
+{
+#ifndef NDEBUG
+  assert (ps->trace);
+#else
+  (void) ps;
+#endif
+  return CLS2IDX (c) - CLS2IDX (d);
+}
+
+static void
+bpushc (PS * ps, unsigned char ch)
+{
+  if (ps->bhead == ps->eob)
+    ENLARGE (ps->buffer, ps->bhead, ps->eob);
+
+  *ps->bhead++ = ch;
+}
+
+static void
+bpushu (PS * ps, unsigned u)
+{
+  while (u & ~0x7f)
+    {
+      bpushc (ps, u | 0x80);
+      u >>= 7;
+    }
+
+  bpushc (ps, u);
+}
+
+static void
+bpushd (PS * ps, unsigned prev, unsigned this)
+{
+  unsigned delta;
+  assert (prev < this);
+  delta = this - prev;
+  bpushu (ps, delta);
+}
+
+static void
+add_zhain (PS * ps)
+{
+  unsigned prev, this, count, rcount;
+  Cls **p, *c;
+  Zhn *res;
+
+  assert (ps->trace);
+  assert (ps->bhead == ps->buffer);
+  assert (ps->rhead > ps->resolved);
+
+  rcount = ps->rhead - ps->resolved;
+  SORT (Cls *, cmp_resolved, ps->resolved, rcount);
+
+  prev = 0;
+  for (p = ps->resolved; p < ps->rhead; p++)
+    {
+      c = *p;
+      this = CLS2TRD (c)->idx;
+      bpushd (ps, prev, this);
+      prev = this;
+    }
+  bpushc (ps, 0);
+
+  count = ps->bhead - ps->buffer;
+
+  res = new (ps, sizeof (Zhn) + count);
+  res->core = 0;
+  res->ref = 0;
+  memcpy (res->znt, ps->buffer, count);
+
+  ps->bhead = ps->buffer;
+#ifdef STATS
+  ps->znts += count - 1;
+#endif
+  zpush (ps, res);
+}
+
+#endif
+
+static void
+add_resolved (PS * ps, int learned)
+{
+#if defined(STATS) || defined(TRACE)
+  Cls **p, *c;
+
+  for (p = ps->resolved; p < ps->rhead; p++)
+    {
+      c = *p;
+      if (c->used)
+    continue;
+
+      c->used = 1;
+
+      if (c->size <= 2)
+    continue;
+
+#ifdef STATS
+      if (c->learned)
+    ps->llused++;
+      else
+    ps->loused++;
+#endif
+    }
+#endif
+
+#ifdef TRACE
+  if (learned && ps->trace)
+    add_zhain (ps);
+#else
+  (void) learned;
+#endif
+  ps->rhead = ps->resolved;
+}
+
+static void
+incjwh (PS * ps, Cls * c)
+{
+  Lit **p, *lit, ** eol;
+  Flt * f, inc, sum;
+  unsigned size = 0;
+  Var * v;
+  Val val;
+
+  eol = end_of_lits (c);
+
+  for (p = c->lits; p < eol; p++)
+    {
+      lit = *p;
+      val = lit->val;
+
+      if (val && ps->LEVEL > 0)
+    {
+      v = LIT2VAR (lit);
+      if (v->level > 0)
+        val = UNDEF;
+    }
+
+      if (val == TRUE)
+    return;
+
+      if (val != FALSE)
+    size++;
+    }
+
+  inc = base2flt (1, -size);
+
+  for (p = c->lits; p < eol; p++)
+    {
+      lit = *p;
+      f = LIT2JWH (lit);
+      sum = addflt (*f, inc);
+      *f = sum;
+    }
+}
+
+static void
+write_rup_header (PS * ps, FILE * file)
+{
+  char line[80];
+  int i;
+
+  sprintf (line, "%%RUPD32 %u %u", ps->rupvariables, ps->rupclauses);
+
+  fputs (line, file);
+  for (i = 255 - strlen (line); i >= 0; i--)
+    fputc (' ', file);
+
+  fputc ('\n', file);
+  fflush (file);
+}
+
+static Cls *
+add_simplified_clause (PS * ps, int learned)
+{
+  unsigned num_true, num_undef, num_false, size, count_resolved;
+  Lit **p, **q, *lit, ** end;
+  unsigned litlevel, glue;
+  Cls *res, * reason;
+  int reentered;
+  Val val;
+  Var *v;
+#if !defined(NDEBUG) && defined(TRACE)
+  unsigned idx;
+#endif
+
+  reentered = 0;
+
+REENTER:
+
+  size = ps->ahead - ps->added;
+
+  add_resolved (ps, learned);
+
+  if (learned)
+    {
+      ps->ladded++;
+      ps->llitsadded += size;
+      if (size > 2)
+    {
+      ps->lladded++;
+      ps->nlclauses++;
+      ps->llits += size;
+    }
+    }
+  else
+    {
+      ps->oadded++;
+      if (size > 2)
+    {
+      ps->loadded++;
+      ps->noclauses++;
+      ps->olits += size;
+    }
+    }
+
+  ps->addedclauses++;
+  assert (ps->addedclauses == ps->ladded + ps->oadded);
+
+#ifdef NO_BINARY_CLAUSES
+  if (size == 2)
+    res = setimpl (ps, ps->added[0], ps->added[1]);
+  else
+#endif
+    {
+      sortlits (ps, ps->added, size);
+
+      if (learned)
+    {
+      if (ps->lhead == ps->EOL)
+        {
+          ENLARGE (ps->lclauses, ps->lhead, ps->EOL);
+
+          /* A very difficult to find bug, which only occurs if the
+           * learned clauses stack is immediately allocated before the
+           * original clauses stack without padding.  In this case, we
+           * have 'SOC == EOC', which terminates all loops using the
+           * idiom 'for (p = SOC; p != EOC; p = NXC(p))' immediately.
+           * Unfortunately this occurred in 'fix_clause_lits' after
+           * using a recent version of the memory allocator of 'Google'
+           * perftools in the context of one large benchmark for
+           * our SMT solver 'Boolector'.
+           */
+          if (ps->EOL == ps->oclauses)
+        ENLARGE (ps->lclauses, ps->lhead, ps->EOL);
+        }
+
+#if !defined(NDEBUG) && defined(TRACE)
+      idx = LIDX2IDX (ps->lhead - ps->lclauses);
+#endif
+    }
+      else
+    {
+      if (ps->ohead == ps->eoo)
+        {
+          ENLARGE (ps->oclauses, ps->ohead, ps->eoo);
+          if (ps->EOL == ps->oclauses)
+        ENLARGE (ps->oclauses, ps->ohead, ps->eoo);    /* ditto */
+        }
+
+#if !defined(NDEBUG) && defined(TRACE)
+      idx = OIDX2IDX (ps->ohead - ps->oclauses);
+#endif
+    }
+
+      assert (ps->EOL != ps->oclauses);            /* ditto */
+
+      res = new_clause (ps, size, learned);
+
+      glue = 0;
+
+      if (learned)
+    {
+      assert (ps->dusedhead == ps->dused);
+
+      for (p = ps->added; p < ps->ahead; p++)
+        {
+          lit = *p;
+          if (lit->val)
+        {
+          litlevel = LIT2VAR (lit)->level;
+          assert (litlevel <= ps->LEVEL);
+          while (ps->levels + litlevel >= ps->levelshead)
+            {
+              if (ps->levelshead >= ps->eolevels)
+            ENLARGE (ps->levels, ps->levelshead, ps->eolevels);
+              assert (ps->levelshead < ps->eolevels);
+              *ps->levelshead++ = 0;
+            }
+          if (!ps->levels[litlevel])
+            {
+              if (ps->dusedhead >= ps->eodused)
+            ENLARGE (ps->dused, ps->dusedhead, ps->eodused);
+              assert (ps->dusedhead < ps->eodused);
+              *ps->dusedhead++ = litlevel;
+              ps->levels[litlevel] = 1;
+              glue++;
+            }
+        }
+          else
+        glue++;
+        }
+
+      while (ps->dusedhead > ps->dused)
+        {
+          litlevel = *--ps->dusedhead;
+          assert (ps->levels + litlevel < ps->levelshead);
+          assert (ps->levels[litlevel]);
+          ps->levels[litlevel] = 0;
+        }
+    }
+
+      assert (glue <= MAXGLUE);
+      res->glue = glue;
+
+#if !defined(NDEBUG) && defined(TRACE)
+      if (ps->trace)
+    assert (CLS2IDX (res) == idx);
+#endif
+      if (learned)
+    *ps->lhead++ = res;
+      else
+    *ps->ohead++ = res;
+
+#if !defined(NDEBUG) && defined(TRACE)
+      if (ps->trace && learned)
+    assert (ps->zhead - ps->zhains == ps->lhead - ps->lclauses);
+#endif
+      assert (ps->lhead != ps->oclauses);        /* ditto */
+    }
+
+  if (learned && ps->rup)
+    {
+      if (!ps->rupstarted)
+    {
+      write_rup_header (ps, ps->rup);
+      ps->rupstarted = 1;
+    }
+    }
+
+  num_true = num_undef = num_false = 0;
+
+  q = res->lits;
+  for (p = ps->added; p < ps->ahead; p++)
+    {
+      lit = *p;
+      *q++ = lit;
+
+      if (learned && ps->rup)
+    fprintf (ps->rup, "%d ", LIT2INT (lit));
+
+      val = lit->val;
+
+      num_true += (val == TRUE);
+      num_undef += (val == UNDEF);
+      num_false += (val == FALSE);
+    }
+  assert (num_false + num_true + num_undef == size);
+
+  if (learned && ps->rup)
+    fputs ("0\n", ps->rup);
+
+  ps->ahead = ps->added;        /* reset */
+
+  if (!reentered)                // TODO merge
+  if (size > 0)
+    {
+      assert (size <= 2 || !reentered);        // TODO remove
+      connect_head_tail (ps, res->lits[0], res);
+      if (size > 1)
+    connect_head_tail (ps, res->lits[1], res);
+    }
+
+  if (size == 0)
+    {
+      if (!ps->mtcls)
+    ps->mtcls = res;
+    }
+
+#ifdef NO_BINARY_CLAUSES
+  if (size != 2)
+#endif
+#ifndef NDEBUG
+    res->connected = 1;
+#endif
+
+  LOG ( fprintf (ps->out, "%s%s ", ps->prefix, learned ? "learned" : "original");
+        dumpclsnl (ps, res));
+
+  /* Shrink clause by resolving it against top level assignments.
+   */
+  if (!ps->LEVEL && num_false > 0)
+    {
+      assert (ps->ahead == ps->added);
+      assert (ps->rhead == ps->resolved);
+
+      count_resolved = 1;
+      add_antecedent (ps, res);
+
+      end = end_of_lits (res);
+      for (p = res->lits; p < end; p++)
+    {
+      lit = *p;
+      v = LIT2VAR (lit);
+      use_var (ps, v);
+
+      if (lit->val == FALSE)
+        {
+          add_antecedent (ps, v->reason);
+          count_resolved++;
+        }
+      else
+        add_lit (ps, lit);
+    }
+
+      assert (count_resolved >= 2);
+
+      learned = 1;
+#ifdef NO_BINARY_CLAUSES
+      if (res == &ps->impl)
+    resetimpl (ps);
+#endif
+      reentered = 1;
+      goto REENTER;        /* and return simplified clause */
+    }
+
+  if (!num_true && num_undef == 1)    /* unit clause */
+    {
+      lit = 0;
+      for (p = res->lits; p < res->lits + size; p++)
+    {
+      if ((*p)->val == UNDEF)
+        lit = *p;
+
+      v = LIT2VAR (*p);
+      use_var (ps, v);
+    }
+      assert (lit);
+
+      reason = res;
+#ifdef NO_BINARY_CLAUSES
+      if (size == 2)
+        {
+      Lit * other = res->lits[0];
+      if (other == lit)
+        other = res->lits[1];
+
+      assert (other->val == FALSE);
+      reason = LIT2REASON (NOTLIT (other));
+    }
+#endif
+      assign_forced (ps, lit, reason);
+      num_true++;
+    }
+
+  if (num_false == size && !ps->conflict)
+    {
+#ifdef NO_BINARY_CLAUSES
+      if (res == &ps->impl)
+    ps->conflict = setcimpl (ps, res->lits[0], res->lits[1]);
+      else
+#endif
+      ps->conflict = res;
+    }
+
+  if (!learned && !num_true && num_undef)
+    incjwh (ps, res);
+
+#ifdef NO_BINARY_CLAUSES
+  if (res == &ps->impl)
+    resetimpl (ps);
+#endif
+  return res;
+}
+
+static int
+trivial_clause (PS * ps)
+{
+  Lit **p, **q, *prev;
+  Var *v;
+
+  SORT (Lit *, cmp_ptr, ps->added,  ps->ahead - ps->added);
+
+  prev = 0;
+  q = ps->added;
+  for (p = q; p < ps->ahead; p++)
+    {
+      Lit *this = *p;
+
+      v = LIT2VAR (this);
+
+      if (prev == this)        /* skip repeated literals */
+    continue;
+
+      /* Top level satisfied ?
+       */
+      if (this->val == TRUE && !v->level)
+     return 1;
+
+      if (prev == NOTLIT (this))/* found pair of dual literals */
+    return 1;
+
+      *q++ = prev = this;
+    }
+
+  ps->ahead = q;            /* shrink */
+
+  return 0;
+}
+
+static void
+simplify_and_add_original_clause (PS * ps)
+{
+#ifdef NO_BINARY_CLAUSES
+  Cls * c;
+#endif
+  if (trivial_clause (ps))
+    {
+      ps->ahead = ps->added;
+
+      if (ps->ohead == ps->eoo)
+    ENLARGE (ps->oclauses, ps->ohead, ps->eoo);
+
+      *ps->ohead++ = 0;
+
+      ps->addedclauses++;
+      ps->oadded++;
+    }
+  else
+    {
+      if (ps->CLS != ps->clshead)
+    add_lit (ps, NOTLIT (ps->clshead[-1]));
+
+#ifdef NO_BINARY_CLAUSES
+      c =
+#endif
+      add_simplified_clause (ps, 0);
+#ifdef NO_BINARY_CLAUSES
+      if (c == &ps->impl) assert (!ps->implvalid);
+#endif
+    }
+}
+
+#ifndef NADC
+
+static void
+add_ado (PS * ps)
+{
+  unsigned len = ps->ahead - ps->added;
+  Lit ** ado, ** p, ** q, *lit;
+  Var * v, * u;
+
+#ifdef TRACE
+  assert (!ps->trace);
+#endif
+
+  ABORTIF (ps->ados < ps->hados && llength (ps->ados[0]) != len,
+           "internal: non matching all different constraint object lengths");
+
+  if (ps->hados == ps->eados)
+    ENLARGE (ps->ados, ps->hados, ps->eados);
+
+  NEWN (ado, len + 1);
+  *ps->hados++ = ado;
+
+  p = ps->added;
+  q = ado;
+  u = 0;
+  while (p < ps->ahead)
+    {
+      lit = *p++;
+      v = LIT2VAR (lit);
+      ABORTIF (v->inado,
+               "internal: variable in multiple all different objects");
+      v->inado = ado;
+      if (!u && !lit->val)
+    u = v;
+      *q++ = lit;
+    }
+
+  assert (q == ado + len);
+  *q++ = 0;
+
+  /* TODO simply do a conflict test as in propado */
+
+  ABORTIF (!u,
+    "internal: "
+    "adding fully instantiated all different object not implemented yet");
+
+  assert (u);
+  assert (u->inado == ado);
+  assert (!u->ado);
+  u->ado = ado;
+
+  ps->ahead = ps->added;
+}
+
+#endif
+
+static void
+hdown (PS * ps, Rnk * r)
+{
+  unsigned end, rpos, cpos, opos;
+  Rnk *child, *other;
+
+  assert (r->pos > 0);
+  assert (ps->heap[r->pos] == r);
+
+  end = ps->hhead - ps->heap;
+  rpos = r->pos;
+
+  for (;;)
+    {
+      cpos = 2 * rpos;
+      if (cpos >= end)
+    break;
+
+      opos = cpos + 1;
+      child = ps->heap[cpos];
+
+      if (cmp_rnk (r, child) < 0)
+    {
+      if (opos < end)
+        {
+          other = ps->heap[opos];
+
+          if (cmp_rnk (child, other) < 0)
+        {
+          child = other;
+          cpos = opos;
+        }
+        }
+    }
+      else if (opos < end)
+    {
+      child = ps->heap[opos];
+
+      if (cmp_rnk (r, child) >= 0)
+        break;
+
+      cpos = opos;
+    }
+      else
+    break;
+
+      ps->heap[rpos] = child;
+      child->pos = rpos;
+      rpos = cpos;
+    }
+
+  r->pos = rpos;
+  ps->heap[rpos] = r;
+}
+
+static Rnk *
+htop (PS * ps)
+{
+  assert (ps->hhead > ps->heap + 1);
+  return ps->heap[1];
+}
+
+static Rnk *
+hpop (PS * ps)
+{
+  Rnk *res, *last;
+  unsigned end;
+
+  assert (ps->hhead > ps->heap + 1);
+
+  res = ps->heap[1];
+  res->pos = 0;
+
+  end = --ps->hhead - ps->heap;
+  if (end == 1)
+    return res;
+
+  last = ps->heap[end];
+
+  ps->heap[last->pos = 1] = last;
+  hdown (ps, last);
+
+  return res;
+}
+
+inline static void
+hpush (PS * ps, Rnk * r)
+{
+  assert (!r->pos);
+
+  if (ps->hhead == ps->eoh)
+    ENLARGE (ps->heap, ps->hhead, ps->eoh);
+
+  r->pos = ps->hhead++ - ps->heap;
+  ps->heap[r->pos] = r;
+  hup (ps, r);
+}
+
+static void
+fix_trail_lits (PS * ps, long delta)
+{
+  Lit **p;
+  for (p = ps->trail; p < ps->thead; p++)
+    *p += delta;
+}
+
+#ifdef NO_BINARY_CLAUSES
+static void
+fix_impl_lits (PS * ps, long delta)
+{
+  Ltk * s;
+  Lit ** p;
+
+  for (s = ps->impls + 2; s <= ps->impls + 2 * ps->max_var + 1; s++)
+    for (p = s->start; p < s->start + s->count; p++)
+      *p += delta;
+}
+#endif
+
+static void
+fix_clause_lits (PS * ps, long delta)
+{
+  Cls **p, *clause;
+  Lit **q, *lit, **eol;
+
+  for (p = SOC; p != EOC; p = NXC (p))
+    {
+      clause = *p;
+      if (!clause)
+    continue;
+
+      q = clause->lits;
+      eol = end_of_lits (clause);
+      while (q < eol)
+    {
+      assert (q - clause->lits <= (int) clause->size);
+      lit = *q;
+      lit += delta;
+      *q++ = lit;
+    }
+    }
+}
+
+static void
+fix_added_lits (PS * ps, long delta)
+{
+  Lit **p;
+  for (p = ps->added; p < ps->ahead; p++)
+    *p += delta;
+}
+
+static void
+fix_assumed_lits (PS * ps, long delta)
+{
+  Lit **p;
+  for (p = ps->als; p < ps->alshead; p++)
+    *p += delta;
+}
+
+static void
+fix_cls_lits (PS * ps, long delta)
+{
+  Lit **p;
+  for (p = ps->CLS; p < ps->clshead; p++)
+    *p += delta;
+}
+
+static void
+fix_heap_rnks (PS * ps, long delta)
+{
+  Rnk **p;
+
+  for (p = ps->heap + 1; p < ps->hhead; p++)
+    *p += delta;
+}
+
+#ifndef NADC
+
+static void
+fix_ado (long delta, Lit ** ado)
+{
+  Lit ** p;
+  for (p = ado; *p; p++)
+    *p += delta;
+}
+
+static void
+fix_ados (PS * ps, long delta)
+{
+  Lit *** p;
+
+  for (p = ps->ados; p < ps->hados; p++)
+    fix_ado (delta, *p);
+}
+
+#endif
+
+static void
+enlarge (PS * ps, unsigned new_size_vars)
+{
+  long rnks_delta, lits_delta;
+  Lit *old_lits = ps->lits;
+  Rnk *old_rnks = ps->rnks;
+
+  RESIZEN (ps->lits, 2 * ps->size_vars, 2 * new_size_vars);
+  RESIZEN (ps->jwh, 2 * ps->size_vars, 2 * new_size_vars);
+  RESIZEN (ps->htps, 2 * ps->size_vars, 2 * new_size_vars);
+#ifndef NDSC
+  RESIZEN (ps->dhtps, 2 * ps->size_vars, 2 * new_size_vars);
+#endif
+  RESIZEN (ps->impls, 2 * ps->size_vars, 2 * new_size_vars);
+  RESIZEN (ps->vars, ps->size_vars, new_size_vars);
+  RESIZEN (ps->rnks, ps->size_vars, new_size_vars);
+
+  if ((lits_delta = ps->lits - old_lits))
+    {
+      fix_trail_lits (ps, lits_delta);
+      fix_clause_lits (ps, lits_delta);
+      fix_added_lits (ps, lits_delta);
+      fix_assumed_lits (ps, lits_delta);
+      fix_cls_lits (ps, lits_delta);
+#ifdef NO_BINARY_CLAUSES
+      fix_impl_lits (ps, lits_delta);
+#endif
+#ifndef NADC
+      fix_ados (ps, lits_delta);
+#endif
+    }
+
+  if ((rnks_delta = ps->rnks - old_rnks))
+    {
+      fix_heap_rnks (ps, rnks_delta);
+    }
+
+  assert (ps->mhead == ps->marked);
+
+  ps->size_vars = new_size_vars;
+}
+
+static void
+unassign (PS * ps, Lit * lit)
+{
+  Cls *reason;
+  Var *v;
+  Rnk *r;
+
+  assert (lit->val == TRUE);
+
+  LOG ( fprintf (ps->out, "%sunassign %d\n", ps->prefix, LIT2INT (lit)));
+
+  v = LIT2VAR (lit);
+  reason = v->reason;
+
+#ifdef NO_BINARY_CLAUSES
+  assert (reason != &ps->impl);
+  if (ISLITREASON (reason))
+    {
+      /* DO NOTHING */
+    }
+  else
+#endif
+  if (reason)
+    {
+      assert (reason->locked);
+      reason->locked = 0;
+      if (reason->learned && reason->size > 2)
+    {
+      assert (ps->llocked > 0);
+      ps->llocked--;
+    }
+    }
+
+  lit->val = UNDEF;
+  NOTLIT (lit)->val = UNDEF;
+
+  r = VAR2RNK (v);
+  if (!r->pos)
+    hpush (ps, r);
+
+#ifndef NDSC
+  {
+    Cls * p, * next, ** q;
+
+    q = LIT2DHTPS (lit);
+    p = *q;
+    *q = 0;
+
+    while (p)
+      {
+    Lit * other = p->lits[0];
+
+    if (other == lit)
+      {
+        other = p->lits[1];
+        q = p->next + 1;
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 03/12] Add picosat.c (2/3)
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
  2021-10-20  9:35 ` [RFC 01/12] Add picosat.h Thorsten Berger
  2021-10-20  9:36 ` [RFC 02/12] Add picosat.c (1/3) Thorsten Berger
@ 2021-10-20  9:37 ` Thorsten Berger
  2021-10-20  9:38 ` [RFC 04/12] Add picosat.c (3/3) Thorsten Berger
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:37 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/picosat.c | 3000 +++++++++++++++++++++++++++++++++++++
 1 file changed, 3000 insertions(+)

diff --git a/scripts/kconfig/picosat.c b/scripts/kconfig/picosat.c
index 653bf0f0b99f..0a6eb3d5a45d 100644
--- a/scripts/kconfig/picosat.c
+++ b/scripts/kconfig/picosat.c
@@ -2998,3 +2998,3003 @@ unassign (PS * ps, Lit * lit)
       {
         other = p->lits[1];
         q = p->next + 1;
+      }
+    else
+      {
+        assert (p->lits[1] == lit);
+        q = p->next;
+      }
+
+    next = *q;
+    *q = *LIT2HTPS (other);
+    *LIT2HTPS (other) = p;
+    p = next;
+      }
+  }
+#endif
+
+#ifndef NADC
+  if (v->adotabpos)
+    {
+      assert (ps->nadotab);
+      assert (*v->adotabpos == v->ado);
+
+      *v->adotabpos = 0;
+      v->adotabpos = 0;
+
+      ps->nadotab--;
+    }
+#endif
+}
+
+static Cls *
+var2reason (PS * ps, Var * var)
+{
+  Cls * res = var->reason;
+#ifdef NO_BINARY_CLAUSES
+  Lit * this, * other;
+  if (ISLITREASON (res))
+    {
+      this = VAR2LIT (var);
+      if (this->val == FALSE)
+    this = NOTLIT (this);
+
+      other = REASON2LIT (res);
+      assert (other->val == TRUE);
+      assert (this->val == TRUE);
+      res = setimpl (ps, NOTLIT (other), this);
+    }
+#else
+  (void) ps;
+#endif
+  return res;
+}
+
+static void
+mark_clause_to_be_collected (Cls * c)
+{
+  assert (!c->collect);
+  c->collect = 1;
+}
+
+static void
+undo (PS * ps, unsigned new_level)
+{
+  Lit *lit;
+  Var *v;
+
+  while (ps->thead > ps->trail)
+    {
+      lit = *--ps->thead;
+      v = LIT2VAR (lit);
+      if (v->level == new_level)
+    {
+      ps->thead++;        /* fix pre decrement */
+      break;
+    }
+
+      unassign (ps, lit);
+    }
+
+  ps->LEVEL = new_level;
+  ps->ttail = ps->thead;
+  ps->ttail2 = ps->thead;
+#ifndef NADC
+  ps->ttailado = ps->thead;
+#endif
+
+#ifdef NO_BINARY_CLAUSES
+  if (ps->conflict == &ps->cimpl)
+    resetcimpl (ps);
+#endif
+#ifndef NADC
+  if (ps->conflict && ps->conflict == ps->adoconflict)
+    resetadoconflict (ps);
+#endif
+  ps->conflict = ps->mtcls;
+  if (ps->LEVEL < ps->adecidelevel)
+    {
+      assert (ps->als < ps->alshead);
+      ps->adecidelevel = 0;
+      ps->alstail = ps->als;
+    }
+  LOG ( fprintf (ps->out, "%sback to level %u\n", ps->prefix, ps->LEVEL));
+}
+
+#ifndef NDEBUG
+
+static int
+clause_satisfied (Cls * c)
+{
+  Lit **p, **eol, *lit;
+
+  eol = end_of_lits (c);
+  for (p = c->lits; p < eol; p++)
+    {
+      lit = *p;
+      if (lit->val == TRUE)
+    return 1;
+    }
+
+  return 0;
+}
+
+static void
+original_clauses_satisfied (PS * ps)
+{
+  Cls **p, *c;
+
+  for (p = ps->oclauses; p < ps->ohead; p++)
+    {
+      c = *p;
+
+      if (!c)
+    continue;
+
+      if (c->learned)
+    continue;
+
+      assert (clause_satisfied (c));
+    }
+}
+
+static void
+assumptions_satisfied (PS * ps)
+{
+  Lit *lit, ** p;
+
+  for (p = ps->als; p < ps->alshead; p++)
+    {
+      lit = *p;
+      assert (lit->val == TRUE);
+    }
+}
+
+#endif
+
+static void
+sflush (PS * ps)
+{
+  double now = picosat_time_stamp ();
+  double delta = now - ps->entered;
+  delta = (delta < 0) ? 0 : delta;
+  ps->seconds += delta;
+  ps->entered = now;
+}
+
+static double
+mb (PS * ps)
+{
+  return ps->current_bytes / (double) (1 << 20);
+}
+
+static double
+avglevel (PS * ps)
+{
+  return ps->decisions ? ps->levelsum / ps->decisions : 0.0;
+}
+
+static void
+rheader (PS * ps)
+{
+  assert (ps->lastrheader <= ps->reports);
+
+  if (ps->lastrheader == ps->reports)
+    return;
+
+  ps->lastrheader = ps->reports;
+
+   fprintf (ps->out, "%s\n", ps->prefix);
+   fprintf (ps->out, "%s %s\n", ps->prefix, ps->rline[0]);
+   fprintf (ps->out, "%s %s\n", ps->prefix, ps->rline[1]);
+   fprintf (ps->out, "%s\n", ps->prefix);
+}
+
+static unsigned
+dynamic_flips_per_assignment_per_mille (PS * ps)
+{
+  assert (FFLIPPEDPREC >= 1000);
+  return ps->sdflips / (FFLIPPEDPREC / 1000);
+}
+
+#ifdef NLUBY
+
+static int
+high_agility (PS * ps)
+{
+  return dynamic_flips_per_assignment_per_mille (ps) >= 200;
+}
+
+static int
+very_high_agility (PS * ps)
+{
+  return dynamic_flips_per_assignment_per_mille (ps) >= 250;
+}
+
+#else
+
+static int
+medium_agility (PS * ps)
+{
+  return dynamic_flips_per_assignment_per_mille (ps) >= 230;
+}
+
+#endif
+
+static void
+relemdata (PS * ps)
+{
+  char *p;
+  int x;
+
+  if (ps->reports < 0)
+    {
+      /* strip trailing white space
+       */
+      for (x = 0; x <= 1; x++)
+    {
+      p = ps->rline[x] + strlen (ps->rline[x]);
+      while (p-- > ps->rline[x])
+        {
+          if (*p != ' ')
+        break;
+
+          *p = 0;
+        }
+    }
+
+      rheader (ps);
+    }
+  else
+    fputc ('\n', ps->out);
+
+  ps->RCOUNT = 0;
+}
+
+static void
+relemhead (PS * ps, const char * name, int fp, double val)
+{
+  int x, y, len, size;
+  const char *fmt;
+  unsigned tmp, e;
+
+  if (ps->reports < 0)
+    {
+      x = ps->RCOUNT & 1;
+      y = (ps->RCOUNT / 2) * 12 + x * 6;
+
+      if (ps->RCOUNT == 1)
+    sprintf (ps->rline[1], "%6s", "");
+
+      len = strlen (name);
+      while (ps->szrline <= len + y + 1)
+    {
+      size = ps->szrline ? 2 * ps->szrline : 128;
+      ps->rline[0] = resize (ps, ps->rline[0], ps->szrline, size);
+      ps->rline[1] = resize (ps, ps->rline[1], ps->szrline, size);
+      ps->szrline = size;
+    }
+
+      fmt = (len <= 6) ? "%6s%10s" : "%-10s%4s";
+      sprintf (ps->rline[x] + y, fmt, name, "");
+    }
+  else if (val < 0)
+    {
+      assert (fp);
+
+      if (val > -100 && (tmp = val * 10.0 - 0.5) > -1000.0)
+    {
+       fprintf (ps->out, "-%4.1f ", -tmp / 10.0);
+    }
+      else
+    {
+      tmp = -val / 10.0 + 0.5;
+      e = 1;
+      while (tmp >= 100)
+        {
+          tmp /= 10;
+          e++;
+        }
+
+       fprintf (ps->out, "-%2ue%u ", tmp, e);
+    }
+    }
+  else
+    {
+      if (fp && val < 1000 && (tmp = val * 10.0 + 0.5) < 10000)
+    {
+       fprintf (ps->out, "%5.1f ", tmp / 10.0);
+    }
+      else if (!fp && (tmp = val) < 100000)
+    {
+       fprintf (ps->out, "%5u ", tmp);
+    }
+      else
+    {
+      tmp = val / 10.0 + 0.5;
+      e = 1;
+
+      while (tmp >= 1000)
+        {
+          tmp /= 10;
+          e++;
+        }
+
+       fprintf (ps->out, "%3ue%u ", tmp, e);
+    }
+    }
+
+  ps->RCOUNT++;
+}
+
+inline static void
+relem (PS * ps, const char *name, int fp, double val)
+{
+  if (name)
+    relemhead (ps, name, fp, val);
+  else
+    relemdata (ps);
+}
+
+static unsigned
+reduce_limit_on_lclauses (PS * ps)
+{
+  unsigned res = ps->lreduce;
+  res += ps->llocked;
+  return res;
+}
+
+static void
+report (PS * ps, int replevel, char type)
+{
+  int rounds;
+
+#ifdef RCODE
+  (void) type;
+#endif
+
+  if (ps->verbosity < replevel)
+    return;
+
+  sflush (ps);
+
+  if (!ps->reports)
+    ps->reports = -1;
+
+  for (rounds = (ps->reports < 0) ? 2 : 1; rounds; rounds--)
+    {
+      if (ps->reports >= 0)
+     fprintf (ps->out, "%s%c ", ps->prefix, type);
+
+      relem (ps, "seconds", 1, ps->seconds);
+      relem (ps, "level", 1, avglevel (ps));
+      assert (ps->fixed <=  ps->max_var);
+      relem (ps, "variables", 0, ps->max_var - ps->fixed);
+      relem (ps, "used", 1, PERCENT (ps->vused, ps->max_var));
+      relem (ps, "original", 0, ps->noclauses);
+      relem (ps, "conflicts", 0, ps->conflicts);
+      // relem (ps, "decisions", 0, ps->decisions);
+      // relem (ps, "conf/dec", 1, PERCENT(ps->conflicts,ps->decisions));
+      // relem (ps, "limit", 0, reduce_limit_on_lclauses (ps));
+      relem (ps, "learned", 0, ps->nlclauses);
+      // relem (ps, "limit", 1, PERCENT (ps->nlclauses, reduce_limit_on_lclauses (ps)));
+      relem (ps, "limit", 0, ps->lreduce);
+#ifdef STATS
+      relem (ps, "learning", 1, PERCENT (ps->llused, ps->lladded));
+#endif
+      relem (ps, "agility", 1, dynamic_flips_per_assignment_per_mille (ps) / 10.0);
+      // relem (ps, "original", 0, ps->noclauses);
+      relem (ps, "MB", 1, mb (ps));
+      // relem (ps, "lladded", 0, ps->lladded);
+      // relem (ps, "llused", 0, ps->llused);
+
+      relem (ps, 0, 0, 0);
+
+      ps->reports++;
+    }
+
+  /* Adapt this to the number of rows in your terminal.
+   */
+  #define ROWS 25
+
+  if (ps->reports % (ROWS - 3) == (ROWS - 4))
+    rheader (ps);
+
+  fflush (ps->out);
+}
+
+static int
+bcp_queue_is_empty (PS * ps)
+{
+  if (ps->ttail != ps->thead)
+    return 0;
+
+  if (ps->ttail2 != ps->thead)
+    return 0;
+
+#ifndef NADC
+  if (ps->ttailado != ps->thead)
+    return 0;
+#endif
+
+  return 1;
+}
+
+static int
+satisfied (PS * ps)
+{
+  assert (!ps->mtcls);
+  assert (!ps->failed_assumption);
+  if (ps->alstail < ps->alshead)
+    return 0;
+  assert (!ps->conflict);
+  assert (bcp_queue_is_empty (ps));
+  return ps->thead == ps->trail + ps->max_var;    /* all assigned */
+}
+
+static void
+vrescore (PS * ps)
+{
+  Rnk *p, *eor = ps->rnks + ps->max_var;
+  for (p = ps->rnks + 1; p <= eor; p++)
+    if (p->score != INFFLT)
+      p->score = mulflt (p->score, ps->ilvinc);
+  ps->vinc = mulflt (ps->vinc, ps->ilvinc);;
+#ifdef VISCORES
+  ps->nvinc = mulflt (ps->nvinc, ps->lscore);;
+#endif
+}
+
+static void
+inc_score (PS * ps, Var * v)
+{
+  Flt score;
+  Rnk *r;
+
+#ifndef NFL
+  if (ps->simplifying)
+    return;
+#endif
+
+  if (!v->level)
+    return;
+
+  if (v->internal)
+    return;
+
+  r = VAR2RNK (v);
+  score = r->score;
+
+  assert (score != INFFLT);
+
+  score = addflt (score, ps->vinc);
+  assert (score < INFFLT);
+  r->score = score;
+  if (r->pos > 0)
+    hup (ps, r);
+
+  if (score > ps->lscore)
+    vrescore (ps);
+}
+
+static void
+inc_activity (PS * ps, Cls * c)
+{
+  Act *p;
+
+  if (!c->learned)
+    return;
+
+  if (c->size <= 2)
+    return;
+
+  p = CLS2ACT (c);
+  *p = addflt (*p, ps->cinc);
+}
+
+static unsigned
+hashlevel (unsigned l)
+{
+  return 1u << (l & 31);
+}
+
+static void
+push (PS * ps, Var * v)
+{
+  if (ps->dhead == ps->eod)
+    ENLARGE (ps->dfs, ps->dhead, ps->eod);
+
+  *ps->dhead++ = v;
+}
+
+static Var *
+pop (PS * ps)
+{
+  assert (ps->dfs < ps->dhead);
+  return *--ps->dhead;
+}
+
+static void
+analyze (PS * ps)
+{
+  unsigned open, minlevel, siglevels, l, old, i, orig;
+  Lit *this, *other, **p, **q, **eol;
+  Var *v, *u, **m, *start, *uip;
+  Cls *c;
+
+  assert (ps->conflict);
+
+  assert (ps->ahead == ps->added);
+  assert (ps->mhead == ps->marked);
+  assert (ps->rhead == ps->resolved);
+
+  /* First, search for First UIP variable and mark all resolved variables.
+   * At the same time determine the minimum decision level involved.
+   * Increase activities of resolved variables.
+   */
+  q = ps->thead;
+  open = 0;
+  minlevel = ps->LEVEL;
+  siglevels = 0;
+  uip = 0;
+
+  c = ps->conflict;
+
+  for (;;)
+    {
+      add_antecedent (ps, c);
+      inc_activity (ps, c);
+      eol = end_of_lits (c);
+      for (p = c->lits; p < eol; p++)
+    {
+      other = *p;
+
+      if (other->val == TRUE)
+        continue;
+
+      assert (other->val == FALSE);
+
+      u = LIT2VAR (other);
+      if (u->mark)
+        continue;
+     
+      u->mark = 1;
+      inc_score (ps, u);
+      use_var (ps, u);
+
+      if (u->level == ps->LEVEL)
+        {
+          open++;
+        }
+      else
+        {
+          push_var_as_marked (ps, u);
+
+          if (u->level)
+        {
+          /* The statistics counter 'nonminimizedllits' sums up the
+           * number of literals that would be added if only the
+           * 'first UIP' scheme for learned clauses would be used
+           * and no clause minimization.
+           */
+          ps->nonminimizedllits++;
+
+          if (u->level < minlevel)
+            minlevel = u->level;
+
+          siglevels |= hashlevel (u->level);
+        }
+          else
+        {
+          assert (!u->level);
+          assert (u->reason);
+        }
+        }
+    }
+
+      do
+    {
+      if (q == ps->trail)
+        {
+          uip = 0;
+          goto DONE_FIRST_UIP;
+        }
+
+      this = *--q;
+      uip = LIT2VAR (this);
+    }
+      while (!uip->mark);
+
+      uip->mark = 0;
+
+      c = var2reason (ps, uip);
+#ifdef NO_BINARY_CLAUSES
+      if (c == &ps->impl)
+    resetimpl (ps);
+#endif
+     open--;
+     if ((!open && ps->LEVEL) || !c)
+    break;
+
+     assert (c);
+    }
+
+DONE_FIRST_UIP:
+
+  if (uip)
+    {
+      assert (ps->LEVEL);
+      this = VAR2LIT (uip);
+      this += (this->val == TRUE);
+      ps->nonminimizedllits++;
+      ps->minimizedllits++;
+      add_lit (ps, this);
+#ifdef STATS
+      if (uip->reason)
+    ps->uips++;
+#endif
+    }
+  else
+    assert (!ps->LEVEL);
+
+  /* Second, try to mark more intermediate variables, with the goal to
+   * minimize the conflict clause.  This is a DFS from already marked
+   * variables backward through the implication graph.  It tries to reach
+   * other marked variables.  If the search reaches an unmarked decision
+   * variable or a variable assigned below the minimum level of variables in
+   * the first uip learned clause or a level on which no variable has been
+   * marked, then the variable from which the DFS is started is not
+   * redundant.  Otherwise the start variable is redundant and will
+   * eventually be removed from the learned clause in step 4.  We initially
+   * implemented BFS, but then profiling revelead that this step is a bottle
+   * neck for certain incremental applications.  After switching to DFS this
+   * hot spot went away.
+   */
+  orig = ps->mhead - ps->marked;
+  for (i = 0; i < orig; i++)
+    {
+      start = ps->marked[i];
+
+      assert (start->mark);
+      assert (start != uip);
+      assert (start->level < ps->LEVEL);
+
+      if (!start->reason)
+    continue;
+
+      old = ps->mhead - ps->marked;
+      assert (ps->dhead == ps->dfs);
+      push (ps, start);
+
+      while (ps->dhead > ps->dfs)
+    {
+      u = pop (ps);
+      assert (u->mark);
+
+      c = var2reason (ps, u);
+#ifdef NO_BINARY_CLAUSES
+      if (c == &ps->impl)
+        resetimpl (ps);
+#endif
+      if (!c ||
+          ((l = u->level) &&
+           (l < minlevel || ((hashlevel (l) & ~siglevels)))))
+        {
+          while (ps->mhead > ps->marked + old)    /* reset all marked */
+        (*--ps->mhead)->mark = 0;
+
+          ps->dhead = ps->dfs;        /* and DFS stack */
+          break;
+        }
+
+      eol = end_of_lits (c);
+      for (p = c->lits; p < eol; p++)
+        {
+          v = LIT2VAR (*p);
+          if (v->mark)
+        continue;
+
+          mark_var (ps, v);
+          push (ps, v);
+        }
+    }
+    }
+
+  for (m = ps->marked; m < ps->mhead; m++)
+    {
+      v = *m;
+
+      assert (v->mark);
+      assert (!v->resolved);
+
+      use_var (ps, v);
+
+      c = var2reason (ps, v);
+      if (!c)
+    continue;
+
+#ifdef NO_BINARY_CLAUSES
+      if (c == &ps->impl)
+    resetimpl (ps);
+#endif
+      eol = end_of_lits (c);
+      for (p = c->lits; p < eol; p++)
+    {
+      other = *p;
+
+      u = LIT2VAR (other);
+      if (!u->level)
+        continue;
+
+      if (!u->mark)        /* 'MARKTEST' */
+        break;
+    }
+
+      if (p != eol)
+    continue;
+
+      add_antecedent (ps, c);
+      v->resolved = 1;
+    }
+
+  for (m = ps->marked; m < ps->mhead; m++)
+    {
+      v = *m;
+
+      assert (v->mark);
+      v->mark = 0;
+
+      if (v->resolved)
+    {
+      v->resolved = 0;
+      continue;
+    }
+
+      this = VAR2LIT (v);
+      if (this->val == TRUE)
+    this++;            /* actually NOTLIT */
+
+      add_lit (ps, this);
+      ps->minimizedllits++;
+    }
+
+  assert (ps->ahead <= ps->eoa);
+  assert (ps->rhead <= ps->eor);
+
+  ps->mhead = ps->marked;
+}
+
+static void
+fanalyze (PS * ps)
+{
+  Lit ** eol, ** p, * lit;
+  Cls * c, * reason;
+  Var * v, * u;
+  int next;
+
+#ifndef RCODE
+  double start = picosat_time_stamp ();
+#endif
+
+  assert (ps->failed_assumption);
+  assert (ps->failed_assumption->val == FALSE);
+
+  v = LIT2VAR (ps->failed_assumption);
+  reason = var2reason (ps, v);
+  if (!reason) return;
+#ifdef NO_BINARY_CLAUSES
+  if (reason == &ps->impl)
+    resetimpl (ps);
+#endif
+
+  eol = end_of_lits (reason);
+  for (p = reason->lits; p != eol; p++)
+    {
+      lit = *p;
+      u = LIT2VAR (lit);
+      if (u == v) continue;
+      if (u->reason) break;
+    }
+  if (p == eol) return;
+
+  assert (ps->ahead == ps->added);
+  assert (ps->mhead == ps->marked);
+  assert (ps->rhead == ps->resolved);
+
+  next = 0;
+  mark_var (ps, v);
+  add_lit (ps, NOTLIT (ps->failed_assumption));
+
+  do
+    {
+      v = ps->marked[next++];
+      use_var (ps, v);
+      if (v->reason)
+    {
+      reason = var2reason (ps, v);
+#ifdef NO_BINARY_CLAUSES
+      if (reason == &ps->impl)
+        resetimpl (ps);
+#endif
+      add_antecedent (ps, reason);
+      eol = end_of_lits (reason);
+      for (p = reason->lits; p != eol; p++)
+        {
+          lit = *p;
+          u = LIT2VAR (lit);
+          if (u == v) continue;
+          if (u->mark) continue;
+          mark_var (ps, u);
+        }
+    }
+      else
+    {
+      lit = VAR2LIT (v);
+      if (lit->val == TRUE) lit = NOTLIT (lit);
+      add_lit (ps, lit);
+    }
+    }
+  while (ps->marked + next < ps->mhead);
+
+  c = add_simplified_clause (ps, 1);
+  v = LIT2VAR (ps->failed_assumption);
+  reason = v->reason;
+#ifdef NO_BINARY_CLAUSES
+  if (!ISLITREASON (reason))
+#endif
+    {
+      assert (reason->locked);
+      reason->locked = 0;
+      if (reason->learned && reason->size > 2)
+    {
+      assert (ps->llocked > 0);
+      ps->llocked--;
+    }
+    }
+
+#ifdef NO_BINARY_CLAUSES
+  if (c == &ps->impl)
+    {
+      c = impl2reason (ps, NOTLIT (ps->failed_assumption));
+    }
+  else
+#endif
+    {
+      assert (c->learned);
+      assert (!c->locked);
+      c->locked = 1;
+      if (c->size > 2)
+    {
+      ps->llocked++;
+      assert (ps->llocked > 0);
+    }
+    }
+
+  v->reason = c;
+
+  while (ps->mhead > ps->marked)
+    (*--ps->mhead)->mark = 0;
+
+  if (ps->verbosity)
+     fprintf (ps->out, "%sfanalyze took %.1f seconds\n",
+         ps->prefix, picosat_time_stamp () - start);
+}
+
+/* Propagate assignment of 'this' to 'FALSE' by visiting all binary clauses in
+ * which 'this' occurs.
+ */
+inline static void
+prop2 (PS * ps, Lit * this)
+{
+#ifdef NO_BINARY_CLAUSES
+  Lit ** l, ** start;
+  Ltk * lstk;
+#else
+  Cls * c, ** p;
+  Cls * next;
+#endif
+  Lit * other;
+  Val tmp;
+
+  assert (this->val == FALSE);
+
+#ifdef NO_BINARY_CLAUSES
+  lstk = LIT2IMPLS (this);
+  start = lstk->start;
+  l = start + lstk->count;
+  while (l != start)
+    {
+      /* The counter 'visits' is the number of clauses that are
+       * visited during propagations of assignments.
+       */
+      ps->visits++;
+#ifdef STATS
+      ps->bvisits++;
+#endif
+      other = *--l;
+      tmp = other->val;
+
+      if (tmp == TRUE)
+    {
+#ifdef STATS
+      ps->othertrue++;
+      ps->othertrue2++;
+      if (LIT2VAR (other)->level < ps->LEVEL)
+        ps->othertrue2u++;
+#endif
+      continue;
+    }
+
+      if (tmp != FALSE)
+    {
+      assign_forced (ps, other, LIT2REASON (NOTLIT(this)));
+      continue;
+    }
+
+      if (ps->conflict == &ps->cimpl)
+    resetcimpl (ps);
+      ps->conflict = setcimpl (ps, this, other);
+    }
+#else
+  /* Traverse all binary clauses with 'this'.  Head/Tail pointers for binary
+   * clauses do not have to be modified here.
+   */
+  p = LIT2IMPLS (this);
+  for (c = *p; c; c = next)
+    {
+      ps->visits++;
+#ifdef STATS
+      ps->bvisits++;
+#endif
+      assert (!c->collect);
+#ifdef TRACE
+      assert (!c->collected);
+#endif
+      assert (c->size == 2);
+      
+      other = c->lits[0];
+      if (other == this)
+    {
+      next = c->next[0];
+      other = c->lits[1];
+    }
+      else
+    next = c->next[1];
+
+      tmp = other->val;
+
+      if (tmp == TRUE)
+    {
+#ifdef STATS
+      ps->othertrue++;
+      ps->othertrue2++;
+      if (LIT2VAR (other)->level < ps->LEVEL)
+        ps->othertrue2u++;
+#endif
+      continue;
+    }
+
+      if (tmp == FALSE)
+    ps->conflict = c;
+      else
+    assign_forced (ps, other, c);    /* unit clause */
+    }
+#endif /* !defined(NO_BINARY_CLAUSES) */
+}
+
+#ifndef NDSC
+static int
+should_disconnect_head_tail (PS * ps, Lit * lit)
+{
+  unsigned litlevel;
+  Var * v;
+
+  assert (lit->val == TRUE);
+
+  v = LIT2VAR (lit);
+  litlevel = v->level;
+
+  if (!litlevel)
+    return 1;
+
+#ifndef NFL
+  if (ps->simplifying)
+    return 0;
+#endif
+
+  return litlevel < ps->LEVEL;
+}
+#endif
+
+inline static void
+propl (PS * ps, Lit * this)
+{
+  Lit **l, *other, *prev, *new_lit, **eol;
+  Cls *next, **htp_ptr, **new_htp_ptr;
+  Cls *c;
+#ifdef STATS
+  unsigned size;
+#endif
+
+  htp_ptr = LIT2HTPS (this);
+  assert (this->val == FALSE);
+
+  /* Traverse all non binary clauses with 'this'.  Head/Tail pointers are
+   * updated as well.
+   */
+  for (c = *htp_ptr; c; c = next)
+    {
+      ps->visits++;
+#ifdef STATS
+      size = c->size;
+      assert (size >= 3);
+      ps->traversals++;    /* other is dereferenced at least */
+
+      if (size == 3)
+    ps->tvisits++;
+      else if (size >= 4)
+    {
+      ps->lvisits++;
+      ps->ltraversals++;
+    }
+#endif
+#ifdef TRACE
+      assert (!c->collected);
+#endif
+      assert (c->size > 0);
+
+      other = c->lits[0];
+      if (other != this)
+    {
+      assert (c->size != 1);
+      c->lits[0] = this;
+      c->lits[1] = other;
+      next = c->next[1];
+      c->next[1] = c->next[0];
+      c->next[0] = next;
+    }
+      else if (c->size == 1)    /* With assumptions we need to
+                             * traverse unit clauses as well.
+                     */
+    {
+      assert (!ps->conflict);
+      ps->conflict = c;
+      break;
+    }
+      else
+    {
+      assert (other == this && c->size > 1);
+      other = c->lits[1];
+      next = c->next[0];
+    }
+      assert (other == c->lits[1]);
+      assert (this == c->lits[0]);
+      assert (next == c->next[0]);
+      assert (!c->collect);
+
+      if (other->val == TRUE)
+    {
+#ifdef STATS
+      ps->othertrue++;
+      ps->othertruel++;
+#endif
+#ifndef NDSC
+      if (should_disconnect_head_tail (ps, other))
+        {
+          new_htp_ptr = LIT2DHTPS (other);
+          c->next[0] = *new_htp_ptr;
+          *new_htp_ptr = c;
+#ifdef STATS
+          ps->othertruelu++;
+#endif
+          *htp_ptr = next;
+          continue;
+        }
+#endif
+      htp_ptr = c->next;
+      continue;
+    }
+
+      l = c->lits + 1;
+      eol = (Lit**) c->lits + c->size;
+      prev = this;
+
+      while (++l != eol)
+    {
+#ifdef STATS
+      if (size >= 3)
+        {
+          ps->traversals++;
+          if (size > 3)
+        ps->ltraversals++;
+        }
+#endif
+      new_lit = *l;
+      *l = prev;
+      prev = new_lit;
+      if (new_lit->val != FALSE) break;
+    }
+
+      if (l == eol)
+    {
+      while (l > c->lits + 2)
+        {
+          new_lit = *--l;
+          *l = prev;
+          prev = new_lit;
+        }
+      assert (c->lits[0] == this);
+
+      assert (other == c->lits[1]);
+      if (other->val == FALSE)    /* found conflict */
+        {
+          assert (!ps->conflict);
+          ps->conflict = c;
+          return;
+        }
+
+      assign_forced (ps, other, c);        /* unit clause */
+      htp_ptr = c->next;
+    }
+      else
+    {
+      assert (new_lit->val == TRUE || new_lit->val == UNDEF);
+      c->lits[0] = new_lit;
+      // *l = this;
+      new_htp_ptr = LIT2HTPS (new_lit);
+      c->next[0] = *new_htp_ptr;
+      *new_htp_ptr = c;
+      *htp_ptr = next;
+    }
+    }
+}
+
+#ifndef NADC
+
+static unsigned primes[] = { 996293, 330643, 753947, 500873 };
+
+#define PRIMES ((sizeof primes)/sizeof *primes)
+
+static unsigned
+hash_ado (PS * ps, Lit ** ado, unsigned salt)
+{
+  unsigned i, res, tmp;
+  Lit ** p, * lit;
+
+  assert (salt < PRIMES);
+
+  i = salt;
+  res = 0;
+
+  for (p = ado; (lit = *p); p++)
+    {
+      assert (lit->val);
+
+      tmp = res >> 31;
+      res <<= 1;
+
+      if (lit->val > 0)
+    res |= 1;
+
+      assert (i < PRIMES);
+      res *= primes[i++];
+      if (i == PRIMES)
+    i = 0;
+
+      res += tmp;
+    }
+
+  return res & (ps->szadotab - 1);
+}
+
+static unsigned
+cmp_ado (Lit ** a, Lit ** b)
+{
+  Lit ** p, ** q, * l, * k;
+  int res;
+
+  for (p = a, q = b; (l = *p); p++, q++)
+    {
+      k = *q;
+      assert (k);
+      if ((res = (l->val - k->val)))
+    return res;
+    }
+
+  assert (!*q);
+
+  return 0;
+}
+
+static Lit ***
+find_ado (PS * ps, Lit ** ado)
+{
+  Lit *** res, ** other;
+  unsigned pos, delta;
+
+  pos = hash_ado (ps, ado, 0);
+  assert (pos < ps->szadotab);
+  res = ps->adotab + pos;
+
+  other = *res;
+  if (!other || !cmp_ado (other, ado))
+    return res;
+
+  delta = hash_ado (ps, ado, 1);
+  if (!(delta & 1))
+    delta++;
+
+  assert (delta & 1);
+  assert (delta < ps->szadotab);
+
+  for (;;)
+    {
+      pos += delta;
+      if (pos >= ps->szadotab)
+    pos -= ps->szadotab;
+
+      assert (pos < ps->szadotab);
+      res = ps->adotab + pos;
+      other = *res;
+      if (!other || !cmp_ado (other, ado))
+    return res;
+    }
+}
+
+static void
+enlarge_adotab (PS * ps)
+{
+  /* TODO make this generic */
+
+  ABORTIF (ps->szadotab,
+           "internal: all different objects table needs larger initial size");
+  assert (!ps->nadotab);
+  ps->szadotab = 10000;
+  NEWN (ps->adotab, ps->szadotab);
+  CLRN (ps->adotab, ps->szadotab);
+}
+
+static int
+propado (PS * ps, Var * v)
+{
+  Lit ** p, ** q, *** adotabpos, **ado, * lit;
+  Var * u;
+
+  if (ps->LEVEL && ps->adodisabled)
+    return 1;
+
+  assert (!ps->conflict);
+  assert (!ps->adoconflict);
+  assert (VAR2LIT (v)->val != UNDEF);
+  assert (!v->adotabpos);
+
+  if (!v->ado)
+    return 1;
+
+  assert (v->inado);
+
+  for (p = v->ado; (lit = *p); p++)
+    if (lit->val == UNDEF)
+      {
+    u = LIT2VAR (lit);
+    assert (!u->ado);
+    u->ado = v->ado;
+    v->ado = 0;
+
+    return 1;
+      }
+
+  if (4 * ps->nadotab >= 3 * ps->szadotab)    /* at least 75% filled */
+    enlarge_adotab (ps);
+
+  adotabpos = find_ado (ps, v->ado);
+  ado = *adotabpos;
+
+  if (!ado)
+    {
+      ps->nadotab++;
+      v->adotabpos = adotabpos;
+      *adotabpos = v->ado;
+      return 1;
+    }
+
+  assert (ado != v->ado);
+
+  ps->adoconflict = new_clause (ps, 2 * llength (ado), 1);
+  q = ps->adoconflict->lits;
+
+  for (p = ado; (lit = *p); p++)
+    *q++ = lit->val == FALSE ? lit : NOTLIT (lit);
+
+  for (p = v->ado; (lit = *p); p++)
+    *q++ = lit->val == FALSE ? lit : NOTLIT (lit);
+
+  assert (q == ENDOFCLS (ps->adoconflict));
+  ps->conflict = ps->adoconflict;
+  ps->adoconflicts++;
+  return 0;
+}
+
+#endif
+
+static void
+bcp (PS * ps)
+{
+  int props = 0;
+  assert (!ps->conflict);
+
+  if (ps->mtcls)
+    return;
+
+  for (;;)
+    {
+      if (ps->ttail2 < ps->thead)    /* prioritize implications */
+    {
+      props++;
+      prop2 (ps, NOTLIT (*ps->ttail2++));
+    }
+      else if (ps->ttail < ps->thead)    /* unit clauses or clauses with length > 2 */
+    {
+      if (ps->conflict) break;
+      propl (ps, NOTLIT (*ps->ttail++));
+      if (ps->conflict) break;
+    }
+#ifndef NADC
+      else if (ps->ttailado < ps->thead)
+    {
+      if (ps->conflict) break;
+      propado (ps, LIT2VAR (*ps->ttailado++));
+      if (ps->conflict) break;
+    }
+#endif
+      else
+    break;        /* all assignments propagated, so break */
+    }
+
+  ps->propagations += props;
+}
+
+static unsigned
+drive (PS * ps)
+{
+  unsigned res, vlevel;
+  Lit **p;
+  Var *v;
+
+  res = 0;
+  for (p = ps->added; p < ps->ahead; p++)
+    {
+      v = LIT2VAR (*p);
+      vlevel = v->level;
+      assert (vlevel <= ps->LEVEL);
+      if (vlevel < ps->LEVEL && vlevel > res)
+    res = vlevel;
+    }
+
+  return res;
+}
+
+#ifdef VISCORES
+
+static void
+viscores (PS * ps)
+{
+  Rnk *p, *eor = ps->rnks + ps->max_var;
+  char name[100], cmd[200];
+  FILE * data;
+  Flt s;
+  int i;
+
+  for (p = ps->rnks + 1; p <= ps->eor; p++)
+    {
+      s = p->score;
+      if (s == INFFLT)
+    continue;
+      s = mulflt (s, ps->nvinc);
+      assert (flt2double (s) <= 1.0);
+    }
+
+  sprintf (name, "/tmp/picosat-viscores/data/%08u", ps->conflicts);
+  sprintf (cmd, "sort -n|nl>%s", name);
+
+  data = popen (cmd, "w");
+  for (p = ps->rnks + 1; p <= ps->eor; p++)
+    {
+      s = p->score;
+      if (s == INFFLT)
+    continue;
+      s = mulflt (s, ps->nvinc);
+      fprintf (data, "%lf %d\n", 100.0 * flt2double (s), (int)(p - ps->rnks));
+    }
+  fflush (data);
+  pclose (data);
+
+  for (i = 0; i < 8; i++)
+    {
+      sprintf (cmd, "awk '$3%%8==%d' %s>%s.%d", i, name, name, i);
+      system (cmd);
+    }
+
+  fprintf (ps->fviscores, "set title \"%u\"\n", ps->conflicts);
+  fprintf (ps->fviscores, "plot [0:%u] 0, 100 * (1 - 1/1.1), 100", ps->max_var);
+
+  for (i = 0; i < 8; i++)
+    fprintf (ps->fviscores,
+             ", \"%s.%d\" using 1:2:3 with labels tc lt %d",
+         name, i, i + 1);
+
+  fputc ('\n', ps->fviscores);
+  fflush (ps->fviscores);
+#ifndef WRITEGIF
+  usleep (50000);        /* refresh rate of 20 Hz */
+#endif
+}
+
+#endif
+
+static void
+crescore (PS * ps)
+{
+  Cls **p, *c;
+  Act *a;
+  Flt factor;
+  int l = log2flt (ps->cinc);
+  assert (l > 0);
+  factor = base2flt (1, -l);
+
+  for (p = ps->lclauses; p != ps->lhead; p++)
+    {
+      c = *p;
+
+      if (!c)
+    continue;
+
+#ifdef TRACE
+      if (c->collected)
+    continue;
+#endif
+      assert (c->learned);
+
+      if (c->size <= 2)
+    continue;
+
+      a = CLS2ACT (c);
+      *a = mulflt (*a, factor);
+    }
+
+  ps->cinc = mulflt (ps->cinc, factor);
+}
+
+static void
+inc_vinc (PS * ps)
+{
+#ifdef VISCORES
+  ps->nvinc = mulflt (ps->nvinc, ps->fvinc);
+#endif
+  ps->vinc = mulflt (ps->vinc, ps->ifvinc);
+}
+
+inline static void
+inc_max_var (PS * ps)
+{
+  Lit *lit;
+  Rnk *r;
+  Var *v;
+
+  assert (ps->max_var < ps->size_vars);
+
+  if (ps->max_var + 1 == ps->size_vars)
+    enlarge (ps, ps->size_vars + 2*(ps->size_vars + 3) / 4); /* +25% */
+
+  ps->max_var++;            /* new index of variable */
+  assert (ps->max_var);            /* no unsigned overflow */
+
+  assert (ps->max_var < ps->size_vars);
+
+  lit = ps->lits + 2 * ps->max_var;
+  lit[0].val = lit[1].val = UNDEF;
+
+  memset (ps->htps + 2 * ps->max_var, 0, 2 * sizeof *ps->htps);
+#ifndef NDSC
+  memset (ps->dhtps + 2 * ps->max_var, 0, 2 * sizeof *ps->dhtps);
+#endif
+  memset (ps->impls + 2 * ps->max_var, 0, 2 * sizeof *ps->impls);
+  memset (ps->jwh + 2 * ps->max_var, 0, 2 * sizeof *ps->jwh);
+
+  v = ps->vars + ps->max_var;        /* initialize variable components */
+  CLR (v);
+
+  r = ps->rnks + ps->max_var;        /* initialize rank */
+  CLR (r);
+
+  hpush (ps, r);
+}
+
+static void
+force (PS * ps, Cls * c)
+{
+  Lit ** p, ** eol, * lit, * forced;
+  Cls * reason;
+
+  forced = 0;
+  reason = c;
+
+  eol = end_of_lits (c);
+  for (p = c->lits; p < eol; p++)
+    {
+      lit = *p;
+      if (lit->val == UNDEF)
+    {
+      assert (!forced);
+      forced = lit;
+#ifdef NO_BINARY_CLAUSES
+      if (c == &ps->impl)
+        reason = LIT2REASON (NOTLIT (p[p == c->lits ? 1 : -1]));
+#endif
+    }
+      else
+    assert (lit->val == FALSE);
+    }
+
+#ifdef NO_BINARY_CLAUSES
+  if (c == &ps->impl)
+    resetimpl (ps);
+#endif
+  if (!forced)
+    return;
+
+  assign_forced (ps, forced, reason);
+}
+
+static void
+inc_lreduce (PS * ps)
+{
+#ifdef STATS
+  ps->inclreduces++;
+#endif
+  ps->lreduce *= FREDUCE;
+  ps->lreduce /= 100;
+  report (ps, 1, '+');
+}
+
+static void
+backtrack (PS * ps)
+{
+  unsigned new_level;
+  Cls * c;
+
+  ps->conflicts++;
+  LOG ( fprintf (ps->out, "%sconflict ", ps->prefix); dumpclsnl (ps, ps->conflict));
+
+  analyze (ps);
+  new_level = drive (ps);
+  // TODO: why not? assert (new_level != 1  || (ps->ahead - ps->added) == 2);
+  c = add_simplified_clause (ps, 1);
+  undo (ps, new_level);
+  force (ps, c);
+
+  if (
+#ifndef NFL
+      !ps->simplifying &&
+#endif
+      !--ps->lreduceadjustcnt)
+    {
+      /* With FREDUCE==110 and FREDADJ=121 we stir 'lreduce' to be
+       * proportional to 'sqrt(conflicts)'.  In earlier version we actually
+       * used  'FREDADJ=150', which results in 'lreduce' to approximate
+       * 'conflicts^(log(1.1)/log(1.5))' which is close to the fourth root
+       * of 'conflicts', since log(1.1)/log(1.5)=0.235 (as observed by
+       * Donald Knuth). The square root is the same we get by a Glucose
+       * style increase, which simply adds a constant at every reduction.
+       * This would be way simpler to implement but for now we keep the more
+       * complicated code using the adjust increments and counters.
+       */
+      ps->lreduceadjustinc *= FREDADJ; ps->lreduceadjustinc /= 100; ps->lreduceadjustcnt
+      = ps->lreduceadjustinc;
+      inc_lreduce (ps);
+    }
+
+  if (ps->verbosity >= 4 && !(ps->conflicts % 1000))
+    report (ps, 4, 'C');
+}
+
+static void
+inc_cinc (PS * ps)
+{
+  ps->cinc = mulflt (ps->cinc, ps->fcinc);
+  if (ps->lcinc < ps->cinc)
+    crescore (ps);
+}
+
+static void
+incincs (PS * ps)
+{
+  inc_vinc (ps);
+  inc_cinc (ps);
+#ifdef VISCORES
+  viscores (ps);
+#endif
+}
+
+static void
+disconnect_clause (PS * ps, Cls * c)
+{
+  assert (c->connected);
+
+  if (c->size > 2)
+    {
+      if (c->learned)
+    {
+      assert (ps->nlclauses > 0);
+      ps->nlclauses--;
+
+      assert (ps->llits >= c->size);
+      ps->llits -= c->size;
+    }
+      else
+    {
+      assert (ps->noclauses > 0);
+      ps->noclauses--;
+
+      assert (ps->olits >= c->size);
+      ps->olits -= c->size;
+    }
+    }
+
+#ifndef NDEBUG
+  c->connected = 0;
+#endif
+}
+
+static int
+clause_is_toplevel_satisfied (PS * ps, Cls * c)
+{
+  Lit *lit, **p, **eol = end_of_lits (c);
+  Var *v;
+
+  for (p = c->lits; p < eol; p++)
+    {
+      lit = *p;
+      if (lit->val == TRUE)
+    {
+      v = LIT2VAR (lit);
+      if (!v->level)
+        return 1;
+    }
+    }
+
+  return 0;
+}
+
+static int
+collect_clause (PS * ps, Cls * c)
+{
+  assert (c->collect);
+  c->collect = 0;
+
+#ifdef TRACE
+  assert (!c->collected);
+  c->collected = 1;
+#endif
+  disconnect_clause (ps, c);
+
+#ifdef TRACE
+  if (ps->trace && (!c->learned || c->used))
+    return 0;
+#endif
+  delete_clause (ps, c);
+
+  return 1;
+}
+
+static size_t
+collect_clauses (PS * ps)
+{
+  Cls *c, **p, **q, * next;
+  Lit * lit, * eol;
+  size_t res;
+  int i;
+
+  res = ps->current_bytes;
+
+  eol = ps->lits + 2 * ps->max_var + 1;
+  for (lit = ps->lits + 2; lit <= eol; lit++)
+    {
+      for (i = 0; i <= 1; i++)
+    {
+      if (i)
+        {
+#ifdef NO_BINARY_CLAUSES
+          Ltk * lstk = LIT2IMPLS (lit);
+          Lit ** r, ** s;
+          r = lstk->start;
+          if (lit->val != TRUE || LIT2VAR (lit)->level)
+        for (s = r; s < lstk->start + lstk->count; s++)
+          {
+            Lit * other = *s;
+            Var *v = LIT2VAR (other);
+            if (v->level ||
+                other->val != TRUE)
+              *r++ = other;
+          }
+          lstk->count = r - lstk->start;
+          continue;
+#else
+          p = LIT2IMPLS (lit);
+#endif
+        }
+      else
+        p = LIT2HTPS (lit);
+
+      for (c = *p; c; c = next)
+        {
+          q = c->next;
+          if (c->lits[0] != lit)
+        q++;
+
+          next = *q;
+          if (c->collect)
+        *p = next;
+          else
+        p = q;
+        }
+    }
+    }
+
+#ifndef NDSC
+  for (lit = ps->lits + 2; lit <= eol; lit++)
+    {
+      p = LIT2DHTPS (lit);
+      while ((c = *p))
+    {
+      Lit * other = c->lits[0];
+      if (other == lit)
+        {
+          q = c->next + 1;
+        }
+      else
+        {
+          assert (c->lits[1] == lit);
+          q = c->next;
+        }
+
+      if (c->collect)
+        *p = *q;
+      else
+        p = q;
+    }
+    }
+#endif
+
+  for (p = SOC; p != EOC; p = NXC (p))
+    {
+      c = *p;
+
+      if (!c)
+    continue;
+
+      if (!c->collect)
+    continue;
+
+      if (collect_clause (ps, c))
+    *p = 0;
+    }
+
+#ifdef TRACE
+  if (!ps->trace)
+#endif
+    {
+      q = ps->oclauses;
+      for (p = q; p < ps->ohead; p++)
+    if ((c = *p))
+      *q++ = c;
+      ps->ohead = q;
+
+      q = ps->lclauses;
+      for (p = q; p < ps->lhead; p++)
+    if ((c = *p))
+      *q++ = c;
+      ps->lhead = q;
+    }
+
+  assert (ps->current_bytes <= res);
+  res -= ps->current_bytes;
+  ps->recycled += res;
+
+  LOG ( fprintf (ps->out, "%scollected %ld bytes\n", ps->prefix, (long)res));
+
+  return res;
+}
+
+static int
+need_to_reduce (PS * ps)
+{
+  return ps->nlclauses >= reduce_limit_on_lclauses (ps);
+}
+
+#ifdef NLUBY
+
+static void
+inc_drestart (PS * ps)
+{
+  ps->drestart *= FRESTART;
+  ps->drestart /= 100;
+
+  if (ps->drestart >= MAXRESTART)
+    ps->drestart = MAXRESTART;
+}
+
+static void
+inc_ddrestart (PS * ps)
+{
+  ps->ddrestart *= FRESTART;
+  ps->ddrestart /= 100;
+
+  if (ps->ddrestart >= MAXRESTART)
+    ps->ddrestart = MAXRESTART;
+}
+
+#else
+
+static unsigned
+luby (unsigned i)
+{
+  unsigned k;
+  for (k = 1; k < 32; k++)
+    if (i == (1u << k) - 1)
+      return 1u << (k - 1);
+
+  for (k = 1;; k++)
+    if ((1u << (k - 1)) <= i && i < (1u << k) - 1)
+      return luby (i - (1u << (k-1)) + 1);
+}
+
+#endif
+
+#ifndef NLUBY
+static void
+inc_lrestart (PS * ps, int skip)
+{
+  unsigned delta;
+
+  delta = 100 * luby (++ps->lubycnt);
+  ps->lrestart = ps->conflicts + delta;
+
+  if (ps->waslubymaxdelta)
+    report (ps, 1, skip ? 'N' : 'R');
+  else
+    report (ps, 2, skip ? 'n' : 'r');
+
+  if (delta > ps->lubymaxdelta)
+    {
+      ps->lubymaxdelta = delta;
+      ps->waslubymaxdelta = 1;
+    }
+  else
+    ps->waslubymaxdelta = 0;
+}
+#endif
+
+static void
+init_restart (PS * ps)
+{
+#ifdef NLUBY
+  /* TODO: why is it better in incremental usage to have smaller initial
+   * outer restart interval?
+   */
+  ps->ddrestart = ps->calls > 1 ? MINRESTART : 1000;
+  ps->drestart = MINRESTART;
+  ps->lrestart = ps->conflicts + ps->drestart;
+#else
+  ps->lubycnt = 0;
+  ps->lubymaxdelta = 0;
+  ps->waslubymaxdelta = 0;
+  inc_lrestart (ps, 0);
+#endif
+}
+
+static void
+restart (PS * ps)
+{
+  int skip;
+#ifdef NLUBY
+  char kind;
+  int outer;
+
+  inc_drestart (ps);
+  outer = (ps->drestart >= ps->ddrestart);
+
+  if (outer)
+    skip = very_high_agility (ps);
+  else
+    skip = high_agility (ps);
+#else
+  skip = medium_agility (ps);
+#endif
+
+#ifdef STATS
+  if (skip)
+    ps->skippedrestarts++;
+#endif
+
+  assert (ps->conflicts >= ps->lrestart);
+
+  if (!skip)
+    {
+      ps->restarts++;
+      assert (ps->LEVEL > 1);
+      LOG ( fprintf (ps->out, "%srestart %u\n", ps->prefix, ps->restarts));
+      undo (ps, 0);
+    }
+
+#ifdef NLUBY
+  if (outer)
+    {
+      kind = skip ? 'N' : 'R';
+      inc_ddrestart (ps);
+      ps->drestart = MINRESTART;
+    }
+  else  if (skip)
+    {
+      kind = 'n';
+    }
+  else
+    {
+      kind = 'r';
+    }
+
+  assert (ps->drestart <= MAXRESTART);
+  ps->lrestart = ps->conflicts + ps->drestart;
+  assert (ps->lrestart > ps->conflicts);
+
+  report (outer ? 1 : 2, kind);
+#else
+  inc_lrestart (ps, skip);
+#endif
+}
+
+inline static void
+assign_decision (PS * ps, Lit * lit)
+{
+  assert (!ps->conflict);
+
+  ps->LEVEL++;
+
+  LOG ( fprintf (ps->out, "%snew level %u\n", ps->prefix, ps->LEVEL));
+  LOG ( fprintf (ps->out,
+         "%sassign %d at level %d <= DECISION\n",
+         ps->prefix, LIT2INT (lit), ps->LEVEL));
+
+  assign (ps, lit, 0);
+}
+
+#ifndef NFL
+
+static int
+lit_has_binary_clauses (PS * ps, Lit * lit)
+{
+#ifdef NO_BINARY_CLAUSES
+  Ltk* lstk = LIT2IMPLS (lit);
+  return lstk->count != 0;
+#else
+  return *LIT2IMPLS (lit) != 0;
+#endif
+}
+
+static void
+flbcp (PS * ps)
+{
+#ifdef STATS
+  unsigned long long propagaions_before_bcp = ps->propagations;
+#endif
+  bcp (ps);
+#ifdef STATS
+  ps->flprops += ps->propagations - propagaions_before_bcp;
+#endif
+}
+
+inline static int
+cmp_inverse_rnk (PS * ps, Rnk * a, Rnk * b)
+{
+  (void) ps;
+  return -cmp_rnk (a, b);
+}
+
+inline static Flt
+rnk2jwh (PS * ps, Rnk * r)
+{
+  Flt res, sum, pjwh, njwh;
+  Lit * plit, * nlit;
+
+  plit = RNK2LIT (r);
+  nlit = plit + 1;
+  
+  pjwh = *LIT2JWH (plit);
+  njwh = *LIT2JWH (nlit);
+
+  res = mulflt (pjwh, njwh);
+
+  sum = addflt (pjwh, njwh);
+  sum = mulflt (sum, base2flt (1, -10));
+  res = addflt (res, sum);
+
+  return res;
+}
+
+static int
+cmp_inverse_jwh_rnk (PS * ps, Rnk * r, Rnk * s)
+{
+  Flt a = rnk2jwh (ps, r);
+  Flt b = rnk2jwh (ps, s);
+  int res = cmpflt (a, b);
+
+  if (res)
+    return -res;
+
+  return cmp_inverse_rnk (ps, r, s);
+}
+
+static void
+faillits (PS * ps)
+{
+  unsigned i, j, old_trail_count, common, saved_count;
+  unsigned new_saved_size, oldladded = ps->ladded;
+  unsigned long long limit, delta;
+  Lit * lit, * other, * pivot;
+  Rnk * r, ** p, ** q;
+  int new_trail_count;
+  double started;
+
+  if (ps->plain)
+    return;
+
+  if (ps->heap + 1 >= ps->hhead)
+    return;
+
+  if (ps->propagations < ps->fllimit)
+    return;
+
+  sflush (ps);
+  started = ps->seconds;
+
+  ps->flcalls++;
+#ifdef STATSA
+  ps->flrounds++;
+#endif
+  delta = ps->propagations/10;
+  if (delta >= 100*1000*1000) delta = 100*1000*1000;
+  else if (delta <= 100*1000) delta = 100*1000;
+
+  limit = ps->propagations + delta;
+  ps->fllimit = ps->propagations;
+
+  assert (!ps->LEVEL);
+  assert (ps->simplifying);
+
+  if (ps->flcalls <= 1)
+    SORT (Rnk *, cmp_inverse_jwh_rnk, ps->heap + 1, ps->hhead - (ps->heap + 1));
+  else
+    SORT (Rnk *, cmp_inverse_rnk, ps->heap + 1, ps->hhead - (ps->heap + 1));
+
+  i = 1;        /* NOTE: heap starts at position '1' */
+
+  while (ps->propagations < limit)
+    {
+      if (ps->heap + i == ps->hhead)
+    {
+      if (ps->ladded == oldladded)
+        break;
+
+      i = 1;
+#ifdef STATS
+      ps->flrounds++;
+#endif
+      oldladded = ps->ladded;
+    }
+
+      assert (ps->heap + i < ps->hhead);
+
+      r = ps->heap[i++];
+      lit = RNK2LIT (r);
+
+      if (lit->val)
+    continue;
+
+      if (!lit_has_binary_clauses (ps, NOTLIT (lit)))
+    {
+#ifdef STATS
+      ps->flskipped++;
+#endif
+      continue;
+    }
+
+#ifdef STATS
+      ps->fltried++;
+#endif
+      LOG ( fprintf (ps->out, "%strying %d as failed literal\n",
+        ps->prefix, LIT2INT (lit)));
+
+      assign_decision (ps, lit);
+      old_trail_count = ps->thead - ps->trail;
+      flbcp (ps);
+
+      if (ps->conflict)
+    {
+EXPLICITLY_FAILED_LITERAL:
+      LOG ( fprintf (ps->out, "%sfound explicitly failed literal %d\n",
+        ps->prefix, LIT2INT (lit)));
+
+      ps->failedlits++;
+      ps->efailedlits++;
+
+      backtrack (ps);
+      flbcp (ps);
+
+      if (!ps->conflict)
+        continue;
+
+CONTRADICTION:
+      assert (!ps->LEVEL);
+      backtrack (ps);
+      assert (ps->mtcls);
+
+      goto RETURN;
+    }
+
+      if (ps->propagations >= limit)
+    {
+      undo (ps, 0);
+      break;
+    }
+
+      lit = NOTLIT (lit);
+
+      if (!lit_has_binary_clauses (ps, NOTLIT (lit)))
+    {
+#ifdef STATS
+      ps->flskipped++;
+#endif
+      undo (ps, 0);
+      continue;
+    }
+
+#ifdef STATS
+      ps->fltried++;
+#endif
+      LOG ( fprintf (ps->out, "%strying %d as failed literals\n",
+        ps->prefix, LIT2INT (lit)));
+
+      new_trail_count = ps->thead - ps->trail;
+      saved_count = new_trail_count - old_trail_count;
+
+      if (saved_count > ps->saved_size)
+    {
+      new_saved_size = ps->saved_size ? 2 * ps->saved_size : 1;
+      while (saved_count > new_saved_size)
+        new_saved_size *= 2;
+
+      RESIZEN (ps->saved, ps->saved_size, new_saved_size);
+      ps->saved_size = new_saved_size;
+    }
+
+      for (j = 0; j < saved_count; j++)
+    ps->saved[j] = ps->trail[old_trail_count + j];
+
+      undo (ps, 0);
+
+      assign_decision (ps, lit);
+      flbcp (ps);
+
+      if (ps->conflict)
+    goto EXPLICITLY_FAILED_LITERAL;
+
+      pivot = (ps->thead - ps->trail <= new_trail_count) ? lit : NOTLIT (lit);
+
+      common = 0;
+      for (j = 0; j < saved_count; j++)
+    if ((other = ps->saved[j])->val == TRUE)
+      ps->saved[common++] = other;
+
+      undo (ps, 0);
+
+      LOG (if (common)
+         fprintf (ps->out,
+              "%sfound %d literals implied by %d and %d\n",
+              ps->prefix, common,
+              LIT2INT (NOTLIT (lit)), LIT2INT (lit)));
+
+#if 1 // set to zero to disable 'lifting'
+      for (j = 0;
+       j < common
+      /* TODO: For some Velev benchmarks, extracting the common implicit
+       * failed literals took quite some time.  This needs to be fixed by
+       * a dedicated analyzer.  Up to then we bound the number of
+       * propagations in this loop as well.
+       */
+       && ps->propagations < limit + delta
+       ; j++)
+    {
+      other = ps->saved[j];
+
+      if (other->val == TRUE)
+        continue;
+
+      assert (!other->val);
+
+      LOG ( fprintf (ps->out,
+            "%sforcing %d as forced implicitly failed literal\n",
+            ps->prefix, LIT2INT (other)));
+
+      assert (pivot != NOTLIT (other));
+      assert (pivot != other);
+
+      assign_decision (ps, NOTLIT (other));
+      flbcp (ps);
+
+      assert (ps->LEVEL == 1);
+
+      if (ps->conflict)
+        {
+          backtrack (ps);
+          assert (!ps->LEVEL);
+        }
+      else
+        {
+          assign_decision (ps, pivot);
+          flbcp (ps);
+
+          backtrack (ps);
+
+          if (ps->LEVEL)
+        {
+          assert (ps->LEVEL == 1);
+
+          flbcp (ps);
+
+          if (ps->conflict)
+            {
+              backtrack (ps);
+              assert (!ps->LEVEL);
+            }
+          else
+            {
+              assign_decision (ps, NOTLIT (pivot));
+              flbcp (ps);
+              backtrack (ps);
+
+              if (ps->LEVEL)
+            {
+              assert (ps->LEVEL == 1);
+              flbcp (ps);
+
+              if (!ps->conflict)
+                {
+#ifdef STATS
+                  ps->floopsed++;
+#endif
+                  undo (ps, 0);
+                  continue;
+                }
+
+              backtrack (ps);
+            }
+
+              assert (!ps->LEVEL);
+            }
+
+          assert (!ps->LEVEL);
+        }
+        }
+      assert (!ps->LEVEL);
+      flbcp (ps);
+
+      ps->failedlits++;
+      ps->ifailedlits++;
+
+      if (ps->conflict)
+        goto CONTRADICTION;
+    }
+#endif
+    }
+
+  ps->fllimit += 9 * (ps->propagations - ps->fllimit);    /* 10% for failed literals */
+
+RETURN:
+
+  /* First flush top level assigned literals.  Those are prohibited from
+   * being pushed up the heap during 'faillits' since 'simplifying' is set.
+   */
+  assert (ps->heap < ps->hhead);
+  for (p = q = ps->heap + 1; p < ps->hhead; p++)
+    {
+      r = *p;
+      lit = RNK2LIT (r);
+      if (lit->val)
+           r->pos = 0;
+      else
+    *q++ = r;
+    }
+
+  /* Then resort with respect to EVSIDS score and fix positions.
+   */
+  SORT (Rnk *, cmp_inverse_rnk, ps->heap + 1, ps->hhead - (ps->heap + 1));
+  for (p = ps->heap + 1; p < ps->hhead; p++)
+    (*p)->pos = p - ps->heap;
+
+  sflush (ps);
+  ps->flseconds += ps->seconds - started;
+}
+
+#endif
+
+static void
+simplify (PS * ps, int forced)
+{
+  Lit * lit, * notlit, ** t;
+  unsigned collect, delta;
+#ifdef STATS
+  size_t bytes_collected;
+#endif
+  int * q, ilit;
+  Cls **p, *c;
+  Var * v;
+
+#ifndef NDEDBUG
+  (void) forced;
+#endif
+
+  assert (!ps->mtcls);
+  assert (!satisfied (ps));
+  assert (forced || ps->lsimplify <= ps->propagations);
+  assert (forced || ps->fsimplify <= ps->fixed);
+
+  if (ps->LEVEL)
+    undo (ps, 0);
+#ifndef NFL
+  ps->simplifying = 1;
+  faillits (ps);
+  ps->simplifying = 0;
+
+  if (ps->mtcls)
+    return;
+#endif
+
+  if (ps->cils != ps->cilshead)
+    {
+      assert (ps->ttail == ps->thead);
+      assert (ps->ttail2 == ps->thead);
+      ps->ttail = ps->trail;
+      for (t = ps->trail; t < ps->thead; t++)
+    {
+      lit = *t;
+      v = LIT2VAR (lit);
+      if (v->internal)
+        {
+          assert (LIT2INT (lit) < 0);
+          assert (lit->val == TRUE);
+          unassign (ps, lit);
+        }
+      else
+        *ps->ttail++ = lit;
+    }
+      ps->ttail2 = ps->thead = ps->ttail;
+
+      for (q = ps->cils; q != ps->cilshead; q++)
+    {
+      ilit = *q;
+      assert (0 < ilit && ilit <= (int) ps->max_var);
+      v = ps->vars + ilit;
+      assert (v->internal);
+      v->level = 0;
+      v->reason = 0;
+      lit = int2lit (ps, -ilit);
+      assert (lit->val == UNDEF);
+      lit->val = TRUE;
+      notlit = NOTLIT (lit);
+      assert (notlit->val == UNDEF);
+      notlit->val = FALSE;
+    }
+    }
+
+  collect = 0;
+  for (p = SOC; p != EOC; p = NXC (p))
+    {
+      c = *p;
+      if (!c)
+    continue;
+
+#ifdef TRACE
+      if (c->collected)
+    continue;
+#endif
+
+      if (c->locked)
+    continue;
+      
+      assert (!c->collect);
+      if (clause_is_toplevel_satisfied (ps, c))
+    {
+      mark_clause_to_be_collected (c);
+      collect++;
+    }
+    }
+
+  LOG ( fprintf (ps->out, "%scollecting %d clauses\n", ps->prefix, collect));
+#ifdef STATS
+  bytes_collected =
+#endif
+  collect_clauses (ps);
+#ifdef STATS
+  ps->srecycled += bytes_collected;
+#endif
+
+  if (ps->cils != ps->cilshead)
+    {
+      for (q = ps->cils; q != ps->cilshead; q++)
+    {
+      ilit = *q;
+      assert (0 < ilit && ilit <= (int) ps->max_var);
+      assert (ps->vars[ilit].internal);
+      if (ps->rilshead == ps->eorils)
+        ENLARGE (ps->rils, ps->rilshead, ps->eorils);
+      *ps->rilshead++ = ilit;
+      lit = int2lit (ps, -ilit);
+      assert (lit->val == TRUE);
+      lit->val = UNDEF;
+      notlit = NOTLIT (lit);
+      assert (notlit->val == FALSE);
+      notlit->val = UNDEF;
+    }
+      ps->cilshead = ps->cils;
+    }
+
+  delta = 10 * (ps->olits + ps->llits) + 100000;
+  if (delta > 2000000)
+    delta = 2000000;
+  ps->lsimplify = ps->propagations + delta;
+  ps->fsimplify = ps->fixed;
+  ps->simps++;
+
+  report (ps, 1, 's');
+}
+
+static void
+iteration (PS * ps)
+{
+  assert (!ps->LEVEL);
+  assert (bcp_queue_is_empty (ps));
+  assert (ps->isimplify < ps->fixed);
+
+  ps->iterations++;
+  report (ps, 2, 'i');
+#ifdef NLUBY
+  ps->drestart = MINRESTART;
+  ps->lrestart = ps->conflicts + ps->drestart;
+#else
+  init_restart (ps);
+#endif
+  ps->isimplify = ps->fixed;
+}
+
+static int
+cmp_glue_activity_size (PS * ps, Cls * c, Cls * d)
+{
+  Act a, b, * p, * q;
+
+  (void) ps;
+
+  assert (c->learned);
+  assert (d->learned);
+
+  if (c->glue < d->glue)        // smaller glue preferred
+    return 1;
+
+  if (c->glue > d->glue)
+    return -1;
+
+  p = CLS2ACT (c);
+  q = CLS2ACT (d);
+  a = *p;
+  b = *q;
+
+  if (a < b)                // then higher activity
+    return -1;
+
+  if (b < a)
+    return 1;
+
+  if (c->size < d->size)        // then smaller size
+    return 1;
+
+  if (c->size > d->size)
+    return -1;
+
+  return 0;
+}
+
+static void
+reduce (PS * ps, unsigned percentage)
+{
+  unsigned redcount, lcollect, collect, target;
+#ifdef STATS
+  size_t bytes_collected;
+#endif
+  Cls **p, *c;
+
+  assert (ps->rhead == ps->resolved);
+
+  ps->lastreduceconflicts = ps->conflicts;
+
+  assert (percentage <= 100);
+  LOG ( fprintf (ps->out,
+                "%sreducing %u%% learned clauses\n",
+        ps->prefix, percentage));
+
+  while (ps->nlclauses - ps->llocked > (unsigned)(ps->eor - ps->resolved))
+    ENLARGE (ps->resolved, ps->rhead, ps->eor);
+
+  collect = 0;
+  lcollect = 0;
+
+  for (p = ((ps->fsimplify < ps->fixed) ? SOC : ps->lclauses); p != EOC; p = NXC (p))
+    {
+      c = *p;
+      if (!c)
+    continue;
+
+#ifdef TRACE
+      if (c->collected)
+    continue;
+#endif
+
+      if (c->locked)
+    continue;
+
+      assert (!c->collect);
+      if (ps->fsimplify < ps->fixed && clause_is_toplevel_satisfied (ps, c))
+    {
+      mark_clause_to_be_collected (c);
+      collect++;
+
+      if (c->learned && c->size > 2)
+        lcollect++;
+
+      continue;
+    }
+
+      if (!c->learned)
+    continue;
+
+      if (c->size <= 2)
+    continue;
+
+      assert (ps->rhead < ps->eor);
+      *ps->rhead++ = c;
+    }
+  assert (ps->rhead <= ps->eor);
+
+  ps->fsimplify = ps->fixed;
+
+  redcount = ps->rhead - ps->resolved;
+  SORT (Cls *, cmp_glue_activity_size, ps->resolved, redcount);
+
+  assert (ps->nlclauses >= lcollect);
+  target = ps->nlclauses - lcollect + 1;
+
+  target = (percentage * target + 99) / 100;
+
+  if (target >= redcount)
+    target = redcount;
+
+  ps->rhead = ps->resolved + target;
+  while (ps->rhead > ps->resolved)
+    {
+      c = *--ps->rhead;
+      mark_clause_to_be_collected (c);
+
+      collect++;
+      if (c->learned && c->size > 2)    /* just for consistency */
+    lcollect++;
+    }
+
+  if (collect)
+    {
+      ps->reductions++;
+#ifdef STATS
+      bytes_collected =
+#endif
+      collect_clauses (ps);
+#ifdef STATS
+      ps->rrecycled += bytes_collected;
+#endif
+      report (ps, 2, '-');
+    }
+
+  if (!lcollect)
+    inc_lreduce (ps);        /* avoid dead lock */
+
+  assert (ps->rhead == ps->resolved);
+}
+
+static void
+init_reduce (PS * ps)
+{
+  // lreduce = loadded / 2;
+  ps->lreduce = 1000;
+
+  if (ps->lreduce < 100)
+    ps->lreduce = 100;
+
+  if (ps->verbosity)
+     fprintf (ps->out,
+             "%s\n%sinitial reduction limit %u clauses\n%s\n",
+         ps->prefix, ps->prefix, ps->lreduce, ps->prefix);
+}
+
+static unsigned
+rng (PS * ps)
+{
+  unsigned res = ps->srng;
+  ps->srng *= 1664525u;
+  ps->srng += 1013904223u;
+  NOLOG ( fprintf (ps->out, "%srng () = %u\n", ps->prefix, res));
+  return res;
+}
+
+static unsigned
+rrng (PS * ps, unsigned low, unsigned high)
+{
+  unsigned long long tmp;
+  unsigned res, elements;
+  assert (low <= high);
+  elements = high - low + 1;
+  tmp = rng (ps);
+  tmp *= elements;
+  tmp >>= 32;
+  tmp += low;
+  res = tmp;
+  NOLOG ( fprintf (ps->out, "%srrng (ps, %u, %u) = %u\n", ps->prefix, low, high, res));
+  assert (low <= res);
+  assert (res <= high);
+  return res;
+}
+
+static Lit *
+decide_phase (PS * ps, Lit * lit)
+{
+  Lit * not_lit = NOTLIT (lit);
+  Var *v = LIT2VAR (lit);
+
+  assert (LIT2SGN (lit) > 0);
+  if (v->usedefphase)
+    {
+      if (v->defphase)
+    {
+      /* assign to TRUE */
+    }
+      else
+    {
+      /* assign to FALSE */
+      lit = not_lit;
+    }
+    }
+  else if (!v->assigned)
+    {
+#ifdef STATS
+      ps->staticphasedecisions++;
+#endif
+      if (ps->defaultphase == POSPHASE)
+    {
+      /* assign to TRUE */
+    }
+      else if (ps->defaultphase == NEGPHASE)
+    {
+      /* assign to FALSE */
+      lit = not_lit;
+    }
+      else if (ps->defaultphase == RNDPHASE)
+    {
+      /* randomly assign default phase */
+      if (rrng (ps, 1, 2) != 2)
+        lit = not_lit;
+    }
+      else if (*LIT2JWH(lit) <= *LIT2JWH (not_lit))
+    {
+      /* assign to FALSE (Jeroslow-Wang says there are more short
+       * clauses with negative occurence of this variable, so satisfy
+       * those, to minimize BCP)
+       */
+      lit = not_lit;
+    }
+      else
+    {
+      /* assign to TRUE (... but strictly more positive occurrences) */
+    }
+    }
+  else
+    {
+      /* repeat last phase: phase saving heuristic */
+
+      if (v->phase)
+    {
+      /* assign to TRUE (last phase was TRUE as well) */
+    }
+      else
+    {
+      /* assign to FALSE (last phase was FALSE as well) */
+      lit = not_lit;
+    }
+    }
+
+  return lit;
+}
+
+static unsigned
+gcd (unsigned a, unsigned b)
+{
+  unsigned tmp;
+
+  assert (a);
+  assert (b);
+
+  if (a < b)
+    {
+      tmp = a;
+      a = b;
+      b = tmp;
+    }
+
+  while (b)
+    {
+      assert (a >= b);
+      tmp = b;
+      b = a % b;
+      a = tmp;
+    }
+
+  return a;
+}
+
+static Lit *
+rdecide (PS * ps)
+{
+  unsigned idx, delta, spread;
+  Lit * res;
+
+  spread = RDECIDE;
+  if (rrng (ps, 1, spread) != 2)
+    return 0;
+
+  assert (1 <= ps->max_var);
+  idx = rrng (ps, 1, ps->max_var);
+  res = int2lit (ps, idx);
+
+  if (res->val != UNDEF)
+    {
+      delta = rrng (ps, 1, ps->max_var);
+      while (gcd (delta, ps->max_var) != 1)
+    delta--;
+
+      assert (1 <= delta);
+      assert (delta <= ps->max_var);
+
+      do {
+    idx += delta;
+    if (idx > ps->max_var)
+      idx -= ps->max_var;
+    res = int2lit (ps, idx);
+      } while (res->val != UNDEF);
+    }
+
+#ifdef STATS
+  ps->rdecisions++;
+#endif
+  res = decide_phase (ps, res);
+  LOG ( fprintf (ps->out, "%srdecide %d\n", ps->prefix, LIT2INT (res)));
+
+  return res;
+}
+
+static Lit *
+sdecide (PS * ps)
+{
+  Lit *res;
+  Rnk *r;
+
+  for (;;)
+    {
+      r = htop (ps);
+      res = RNK2LIT (r);
+      if (res->val == UNDEF) break;
+      (void) hpop (ps);
+      NOLOG ( fprintf (ps->out,
+                      "%shpop %u %u %u\n",
+              ps->prefix, r - ps->rnks,
+              FLTMANTISSA(r->score),
+              FLTEXPONENT(r->score)));
+    }
+
+#ifdef STATS
+  ps->sdecisions++;
+#endif
+  res = decide_phase (ps, res);
+
+  LOG ( fprintf (ps->out, "%ssdecide %d\n", ps->prefix, LIT2INT (res)));
+
+  return res;
+}
+
+static Lit *
+adecide (PS * ps)
+{
+  Lit *lit;
+  Var * v;
+
+  assert (ps->als < ps->alshead);
+  assert (!ps->failed_assumption);
+
+  while (ps->alstail < ps->alshead)
+    {
+      lit = *ps->alstail++;
+
+      if (lit->val == FALSE)
+    {
+      ps->failed_assumption = lit;
+      v = LIT2VAR (lit);
+
+      use_var (ps, v);
+
+      LOG ( fprintf (ps->out, "%sfirst failed assumption %d\n",
+            ps->prefix, LIT2INT (ps->failed_assumption)));
+      fanalyze (ps);
+      return 0;
+    }
+
+      if (lit->val == TRUE)
+    {
+      v = LIT2VAR (lit);
+      if (v->level > ps->adecidelevel)
+        ps->adecidelevel = v->level;
+      continue;
+    }
+
+#ifdef STATS
+      ps->assumptions++;
+#endif
+      LOG ( fprintf (ps->out, "%sadecide %d\n", ps->prefix, LIT2INT (lit)));
+      ps->adecidelevel = ps->LEVEL + 1;
+
+      return lit;
+    }
+
+  return 0;
+}
+
+static void
+decide (PS * ps)
+{
+  Lit * lit;
+
+  assert (!satisfied (ps));
+  assert (!ps->conflict);
+
+  if (ps->alstail < ps->alshead && (lit = adecide (ps)))
+    ;
+  else if (ps->failed_assumption)
+    return;
+  else if (satisfied (ps))
+    return;
+  else if (!(lit = rdecide (ps)))
+    lit = sdecide (ps);
+
+  assert (lit);
+  assign_decision (ps, lit);
+
+  ps->levelsum += ps->LEVEL;
+  ps->decisions++;
+}
+
+static int
+sat (PS * ps, int l)
+{
+  int count = 0, backtracked;
+
+  if (!ps->conflict)
+    bcp (ps);
+
+  if (ps->conflict)
+    backtrack (ps);
+
+  if (ps->mtcls)
+    return PICOSAT_UNSATISFIABLE;
+
+  if (satisfied (ps))
+    goto SATISFIED;
+
+  if (ps->lsimplify <= ps->propagations)
+    simplify (ps, 0);
+
+  if (ps->mtcls)
+    return PICOSAT_UNSATISFIABLE;
+
+  if (satisfied (ps))
+    goto SATISFIED;
+
+  init_restart (ps);
+
+  if (!ps->lreduce)
+    init_reduce (ps);
+
+  ps->isimplify = ps->fixed;
+  backtracked = 0;
+
+  for (;;)
+    {
+      if (!ps->conflict)
+    bcp (ps);
+
+      if (ps->conflict)
+    {
+      incincs (ps);
+      backtrack (ps);
+
+      if (ps->mtcls)
+        return PICOSAT_UNSATISFIABLE;
+      backtracked = 1;
+      continue;
+    }
+
+      if (satisfied (ps))
+    {
+SATISFIED:
+#ifndef NDEBUG
+      original_clauses_satisfied (ps);
+      assumptions_satisfied (ps);
+#endif
+      return PICOSAT_SATISFIABLE;
+    }
+
+      if (backtracked)
+    {
+      backtracked = 0;
+      if (!ps->LEVEL && ps->isimplify < ps->fixed)
+        iteration (ps);
+    }
+
+      if (l >= 0 && count >= l)        /* decision limit reached ? */
+    return PICOSAT_UNKNOWN;
+
+      if (ps->interrupt.function &&        /* external interrupt */
+      count > 0 && !(count % INTERRUPTLIM) &&
+      ps->interrupt.function (ps->interrupt.state))
+    return PICOSAT_UNKNOWN;
+
+      if (ps->propagations >= ps->lpropagations)/* propagation limit reached ? */
+    return PICOSAT_UNKNOWN;
+
+#ifndef NADC
+      if (!ps->adodisabled && ps->adoconflicts >= ps->adoconflictlimit)
+    {
+      assert (bcp_queue_is_empty (ps));
+      return PICOSAT_UNKNOWN;
+    }
+#endif
+
+      if (ps->fsimplify < ps->fixed && ps->lsimplify <= ps->propagations)
+    {
+      simplify (ps, 0);
+      if (!bcp_queue_is_empty (ps))
+        continue;
+#ifndef NFL
+      if (ps->mtcls)
+        return PICOSAT_UNSATISFIABLE;
+
+      if (satisfied (ps))
+        return PICOSAT_SATISFIABLE;
+
+      assert (!ps->LEVEL);
+#endif
+    }
+
+      if (need_to_reduce (ps))
+    reduce (ps, 50);
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 04/12] Add picosat.c (3/3)
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
                   ` (2 preceding siblings ...)
  2021-10-20  9:37 ` [RFC 03/12] Add picosat.c (2/3) Thorsten Berger
@ 2021-10-20  9:38 ` Thorsten Berger
  2021-10-20  9:40 ` [RFC 05/12] Add definitions Thorsten Berger
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:38 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/picosat.c | 2502 +++++++++++++++++++++++++++++++++++++
 1 file changed, 2502 insertions(+)

diff --git a/scripts/kconfig/picosat.c b/scripts/kconfig/picosat.c
index 0a6eb3d5a45d..76db7ae0028a 100644
--- a/scripts/kconfig/picosat.c
+++ b/scripts/kconfig/picosat.c
@@ -5998,3 +5998,2505 @@ sat (PS * ps, int l)
 
       if (need_to_reduce (ps))
     reduce (ps, 50);
+
+      if (ps->conflicts >= ps->lrestart && ps->LEVEL > 2)
+    restart (ps);
+
+      decide (ps);
+      if (ps->failed_assumption)
+    return PICOSAT_UNSATISFIABLE;
+      count++;
+    }
+}
+
+static void
+rebias (PS * ps)
+{
+  Cls ** p, * c;
+  Var * v;
+
+  for (v = ps->vars + 1; v <= ps->vars + ps->max_var; v++)
+    v->assigned = 0;
+
+  memset (ps->jwh, 0, 2 * (ps->max_var + 1) * sizeof *ps->jwh);
+
+  for (p = ps->oclauses; p < ps->ohead; p++)
+    {
+      c = *p;
+
+      if (!c)
+    continue;
+
+      if (c->learned)
+    continue;
+
+      incjwh (ps, c);
+    }
+}
+
+#ifdef TRACE
+
+static unsigned
+core (PS * ps)
+{
+  unsigned idx, prev, this, delta, i, lcore, vcore;
+  unsigned *stack, *shead, *eos;
+  Lit **q, **eol, *lit;
+  Cls *c, *reason;
+  Znt *p, byte;
+  Zhn *zhain;
+  Var *v;
+
+  assert (ps->trace);
+
+  assert (ps->mtcls || ps->failed_assumption);
+  if (ps->ocore >= 0)
+    return ps->ocore;
+
+  lcore = ps->ocore = vcore = 0;
+
+  stack = shead = eos = 0;
+  ENLARGE (stack, shead, eos);
+
+  if (ps->mtcls)
+    {
+      idx = CLS2IDX (ps->mtcls);
+      *shead++ = idx;
+    }
+  else
+    {
+      assert (ps->failed_assumption);
+      v = LIT2VAR (ps->failed_assumption);
+      reason = v->reason;
+      assert (reason);
+      idx = CLS2IDX (reason);
+      *shead++ = idx;
+    }
+
+  while (shead > stack)
+    {
+      idx = *--shead;
+      zhain = IDX2ZHN (idx);
+
+      if (zhain)
+    {
+      if (zhain->core)
+        continue;
+
+      zhain->core = 1;
+      lcore++;
+
+      c = IDX2CLS (idx);
+      if (c)
+        {
+          assert (!c->core);
+          c->core = 1;
+        }
+
+      i = 0;
+      delta = 0;
+      prev = 0;
+      for (p = zhain->znt; (byte = *p); p++, i += 7)
+        {
+          delta |= (byte & 0x7f) << i;
+          if (byte & 0x80)
+        continue;
+
+          this = prev + delta;
+          assert (prev < this);    /* no overflow */
+
+          if (shead == eos)
+        ENLARGE (stack, shead, eos);
+          *shead++ = this;
+
+          prev = this;
+          delta = 0;
+          i = -7;
+        }
+    }
+      else
+    {
+      c = IDX2CLS (idx);
+
+      assert (c);
+      assert (!c->learned);
+
+      if (c->core)
+        continue;
+
+      c->core = 1;
+      ps->ocore++;
+
+      eol = end_of_lits (c);
+      for (q = c->lits; q < eol; q++)
+        {
+          lit = *q;
+          v = LIT2VAR (lit);
+          if (v->core)
+        continue;
+
+          v->core = 1;
+          vcore++;
+
+          if (!ps->failed_assumption) continue;
+          if (lit != ps->failed_assumption) continue;
+
+          reason = v->reason;
+          if (!reason) continue;
+          if (reason->core) continue;
+
+          idx = CLS2IDX (reason);
+          if (shead == eos)
+        ENLARGE (stack, shead, eos);
+          *shead++ = idx;
+        }
+    }
+    }
+
+  DELETEN (stack, eos - stack);
+
+  if (ps->verbosity)
+     fprintf (ps->out,
+         "%s%u core variables out of %u (%.1f%%)\n"
+         "%s%u core original clauses out of %u (%.1f%%)\n"
+         "%s%u core learned clauses out of %u (%.1f%%)\n",
+         ps->prefix, vcore, ps->max_var, PERCENT (vcore, ps->max_var),
+         ps->prefix, ps->ocore, ps->oadded, PERCENT (ps->ocore, ps->oadded),
+         ps->prefix, lcore, ps->ladded, PERCENT (lcore, ps->ladded));
+
+  return ps->ocore;
+}
+
+static void
+trace_lits (PS * ps, Cls * c, FILE * file)
+{
+  Lit **p, **eol = end_of_lits (c);
+
+  assert (c);
+  assert (c->core);
+
+  for (p = c->lits; p < eol; p++)
+    fprintf (file, "%d ", LIT2INT (*p));
+
+  fputc ('0', file);
+}
+
+static void
+write_idx (PS * ps, unsigned idx, FILE * file)
+{
+  fprintf (file, "%ld", EXPORTIDX (idx));
+}
+
+static void
+trace_clause (PS * ps, unsigned idx, Cls * c, FILE * file, int fmt)
+{
+  assert (c);
+  assert (c->core);
+  assert (fmt == RUP_TRACE_FMT || !c->learned);
+  assert (CLS2IDX (c) == idx);
+
+  if (fmt != RUP_TRACE_FMT)
+    {
+      write_idx (ps, idx, file);
+      fputc (' ', file);
+    }
+
+  trace_lits (ps, c, file);
+
+  if (fmt != RUP_TRACE_FMT)
+    fputs (" 0", file);
+
+  fputc ('\n', file);
+}
+
+static void
+trace_zhain (PS * ps, unsigned idx, Zhn * zhain, FILE * file, int fmt)
+{
+  unsigned prev, this, delta, i;
+  Znt *p, byte;
+  Cls * c;
+
+  assert (zhain);
+  assert (zhain->core);
+
+  write_idx (ps, idx, file);
+  fputc (' ', file);
+
+  if (fmt == EXTENDED_TRACECHECK_TRACE_FMT)
+    {
+      c = IDX2CLS (idx);
+      assert (c);
+      trace_lits (ps, c, file);
+    }
+  else
+    {
+      assert (fmt == COMPACT_TRACECHECK_TRACE_FMT);
+      putc ('*', file);
+    }
+
+  i = 0;
+  delta = 0;
+  prev = 0;
+
+  for (p = zhain->znt; (byte = *p); p++, i += 7)
+    {
+      delta |= (byte & 0x7f) << i;
+      if (byte & 0x80)
+    continue;
+
+      this = prev + delta;
+
+      putc (' ', file);
+      write_idx (ps, this, file);
+
+      prev = this;
+      delta = 0;
+      i = -7;
+    }
+
+  fputs (" 0\n", file);
+}
+
+static void
+write_core (PS * ps, FILE * file)
+{
+  Lit **q, **eol;
+  Cls **p, *c;
+
+  fprintf (file, "p cnf %u %u\n", ps->max_var, core (ps));
+
+  for (p = SOC; p != EOC; p = NXC (p))
+    {
+      c = *p;
+
+      if (!c || c->learned || !c->core)
+    continue;
+
+      eol = end_of_lits (c);
+      for (q = c->lits; q < eol; q++)
+    fprintf (file, "%d ", LIT2INT (*q));
+
+      fputs ("0\n", file);
+    }
+}
+
+#endif
+
+static void
+write_trace (PS * ps, FILE * file, int fmt)
+{
+#ifdef TRACE
+  Cls *c, ** p;
+  Zhn *zhain;
+  unsigned i;
+
+  core (ps);
+
+  if (fmt == RUP_TRACE_FMT)
+    {
+      ps->rupvariables = picosat_variables (ps),
+      ps->rupclauses = picosat_added_original_clauses (ps);
+      write_rup_header (ps, file);
+    }
+
+  for (p = SOC; p != EOC; p = NXC (p))
+    {
+      c = *p;
+
+      if (ps->oclauses <= p && p < ps->eoo)
+    {
+      i = OIDX2IDX (p - ps->oclauses);
+      assert (!c || CLS2IDX (c) == i);
+    }
+      else
+    {
+          assert (ps->lclauses <= p && p < ps->EOL);
+      i = LIDX2IDX (p - ps->lclauses);
+    }
+
+      zhain = IDX2ZHN (i);
+
+      if (zhain)
+    {
+      if (zhain->core)
+        {
+          if (fmt == RUP_TRACE_FMT)
+        trace_clause (ps,i, c, file, fmt);
+          else
+        trace_zhain (ps, i, zhain, file, fmt);
+        }
+    }
+      else if (c)
+    {
+      if (fmt != RUP_TRACE_FMT && c)
+        {
+          if (c->core)
+        trace_clause (ps, i, c, file, fmt);
+        }
+    }
+    }
+#else
+  (void) file;
+  (void) fmt;
+  (void) ps;
+#endif
+}
+
+static void
+write_core_wrapper (PS * ps, FILE * file, int fmt)
+{
+  (void) fmt;
+#ifdef TRACE
+  write_core (ps, file);
+#else
+  (void) ps;
+  (void) file;
+#endif
+}
+
+static Lit *
+import_lit (PS * ps, int lit, int nointernal)
+{
+  Lit * res;
+  Var * v;
+
+  ABORTIF (lit == INT_MIN, "API usage: INT_MIN literal");
+  ABORTIF (abs (lit) > (int) ps->max_var && ps->CLS != ps->clshead,
+           "API usage: new variable index after 'picosat_push'");
+
+  if (abs (lit) <= (int) ps->max_var)
+    {
+      res = int2lit (ps, lit);
+      v = LIT2VAR (res);
+      if (nointernal && v->internal)
+    ABORT ("API usage: trying to import invalid literal");
+      else if (!nointernal && !v->internal)
+    ABORT ("API usage: trying to import invalid context");
+    }
+  else
+    {
+      while (abs (lit) > (int) ps->max_var)
+    inc_max_var (ps);
+      res = int2lit (ps, lit);
+    }
+
+  return res;
+}
+
+#ifdef TRACE
+static void
+reset_core (PS * ps)
+{
+  Cls ** p, * c;
+  Zhn ** q, * z;
+  unsigned i;
+
+  for (i = 1; i <= ps->max_var; i++)
+    ps->vars[i].core = 0;
+
+  for (p = SOC; p != EOC; p = NXC (p))
+    if ((c = *p))
+      c->core = 0;
+
+  for (q = ps->zhains; q != ps->zhead; q++)
+    if ((z = *q))
+      z->core = 0;
+
+  ps->ocore = -1;
+}
+#endif
+
+static void
+reset_assumptions (PS * ps)
+{
+  Lit ** p;
+
+  ps->failed_assumption = 0;
+
+  if (ps->extracted_all_failed_assumptions)
+    {
+      for (p = ps->als; p < ps->alshead; p++)
+    LIT2VAR (*p)->failed = 0;
+
+      ps->extracted_all_failed_assumptions = 0;
+    }
+
+  ps->alstail = ps->alshead = ps->als;
+  ps->adecidelevel = 0;
+}
+
+static void
+check_ready (PS * ps)
+{
+  ABORTIF (!ps || ps->state == RESET, "API usage: uninitialized");
+}
+
+static void
+check_sat_state (PS * ps)
+{
+  ABORTIF (ps->state != SAT, "API usage: expected to be in SAT state");
+}
+
+static void
+check_unsat_state (PS * ps)
+{
+  ABORTIF (ps->state != UNSAT, "API usage: expected to be in UNSAT state");
+}
+
+static void
+check_sat_or_unsat_or_unknown_state (PS * ps)
+{
+  ABORTIF (ps->state != SAT && ps->state != UNSAT && ps->state != UNKNOWN,
+           "API usage: expected to be in SAT, UNSAT, or UNKNOWN state");
+}
+
+static void
+reset_partial (PS * ps)
+{
+  unsigned idx;
+  if (!ps->partial)
+    return;
+  for (idx = 1; idx <= ps->max_var; idx++)
+    ps->vars[idx].partial = 0;
+  ps->partial = 0;
+}
+
+static void
+reset_incremental_usage (PS * ps)
+{
+  unsigned num_non_false;
+  Lit * lit, ** q;
+
+  check_sat_or_unsat_or_unknown_state (ps);
+
+  LOG ( fprintf (ps->out, "%sRESET incremental usage\n", ps->prefix));
+
+  if (ps->LEVEL)
+    undo (ps, 0);
+
+  reset_assumptions (ps);
+
+  if (ps->conflict)
+    {
+      num_non_false = 0;
+      for (q = ps->conflict->lits; q < end_of_lits (ps->conflict); q++)
+    {
+      lit = *q;
+      if (lit->val != FALSE)
+        num_non_false++;
+    }
+
+      // assert (num_non_false >= 2); // TODO: why this assertion?
+#ifdef NO_BINARY_CLAUSES
+      if (ps->conflict == &ps->cimpl)
+    resetcimpl (ps);
+#endif
+#ifndef NADC
+      if (ps->conflict == ps->adoconflict)
+    resetadoconflict (ps);
+#endif
+      ps->conflict = 0;
+    }
+
+#ifdef TRACE
+  reset_core (ps);
+#endif
+
+  reset_partial (ps);
+
+  ps->saved_flips = ps->flips;
+  ps->min_flipped = UINT_MAX;
+  ps->saved_max_var = ps->max_var;
+
+  ps->state = READY;
+}
+
+static void
+enter (PS * ps)
+{
+  if (ps->nentered++)
+    return;
+
+  check_ready (ps);
+  ps->entered = picosat_time_stamp ();
+}
+
+static void
+leave (PS * ps)
+{
+  assert (ps->nentered);
+  if (--ps->nentered)
+    return;
+
+  sflush (ps);
+}
+
+static void
+check_trace_support_and_execute (PS * ps,
+                                 FILE * file,
+                 void (*f)(PS*,FILE*,int), int fmt)
+{
+  check_ready (ps);
+  check_unsat_state (ps);
+#ifdef TRACE
+  ABORTIF (!ps->trace, "API usage: tracing disabled");
+  enter (ps);
+  f (ps, file, fmt);
+  leave (ps);
+#else
+  (void) file;
+  (void) fmt;
+  (void) f;
+  ABORT ("compiled without trace support");
+#endif
+}
+
+static void
+extract_all_failed_assumptions (PS * ps)
+{
+  Lit ** p, ** eol;
+  Var * v, * u;
+  int pos;
+  Cls * c;
+
+  assert (!ps->extracted_all_failed_assumptions);
+
+  assert (ps->failed_assumption);
+  assert (ps->mhead == ps->marked);
+
+  if (ps->marked == ps->eom)
+    ENLARGE (ps->marked, ps->mhead, ps->eom);
+
+  v = LIT2VAR (ps->failed_assumption);
+  mark_var (ps, v);
+  pos = 0;
+
+  while (pos < ps->mhead - ps->marked)
+    {
+      v = ps->marked[pos++];
+      assert (v->mark);
+      c = var2reason (ps, v);
+      if (!c)
+    continue;
+      eol = end_of_lits (c);
+      for (p = c->lits; p < eol; p++)
+    {
+      u = LIT2VAR (*p);
+      if (!u->mark)
+        mark_var (ps, u);
+    }
+#ifdef NO_BINARY_CLAUSES
+      if (c == &ps->impl)
+    resetimpl (ps);
+#endif
+    }
+
+  for (p = ps->als; p < ps->alshead; p++)
+    {
+      u = LIT2VAR (*p);
+      if (!u->mark) continue;
+      u->failed = 1;
+      LOG ( fprintf (ps->out,
+                     "%sfailed assumption %d\n",
+             ps->prefix, LIT2INT (*p)));
+    }
+
+  while (ps->mhead > ps->marked)
+    (*--ps->mhead)->mark = 0;
+
+  ps->extracted_all_failed_assumptions = 1;
+}
+
+const char *
+picosat_copyright (void)
+{
+  return "Copyright (c) 2006 - 2014 Armin Biere JKU Linz";
+}
+
+PicoSAT *
+picosat_init (void)
+{
+  return init (0, 0, 0, 0);
+}
+
+PicoSAT *
+picosat_minit (void * pmgr,
+           picosat_malloc pnew,
+           picosat_realloc presize,
+           picosat_free pfree)
+{
+  ABORTIF (!pnew, "API usage: zero 'picosat_malloc' argument");
+  ABORTIF (!presize, "API usage: zero 'picosat_realloc' argument");
+  ABORTIF (!pfree, "API usage: zero 'picosat_free' argument");
+  return init (pmgr, pnew, presize, pfree);
+}
+
+
+void
+picosat_adjust (PS * ps, int new_max_var)
+{
+  unsigned new_size_vars;
+
+  ABORTIF (abs (new_max_var) > (int) ps->max_var && ps->CLS != ps->clshead,
+           "API usage: adjusting variable index after 'picosat_push'");
+  enter (ps);
+
+  new_max_var = abs (new_max_var);
+  new_size_vars = new_max_var + 1;
+
+  if (ps->size_vars < new_size_vars)
+    enlarge (ps, new_size_vars);
+
+  while (ps->max_var < (unsigned) new_max_var)
+    inc_max_var (ps);
+
+  leave (ps);
+}
+
+int
+picosat_inc_max_var (PS * ps)
+{
+  if (ps->measurealltimeinlib)
+    enter (ps);
+  else
+    check_ready (ps);
+
+  inc_max_var (ps);
+
+  if (ps->measurealltimeinlib)
+    leave (ps);
+
+  return ps->max_var;
+}
+
+int
+picosat_context (PS * ps)
+{
+  return ps->clshead == ps->CLS ? 0 : LIT2INT (ps->clshead[-1]);
+}
+
+int
+picosat_push (PS * ps)
+{
+  int res;
+  Lit *lit;
+  Var * v;
+
+  if (ps->measurealltimeinlib)
+    enter (ps);
+  else
+    check_ready (ps);
+
+  if (ps->state != READY)
+    reset_incremental_usage (ps);
+
+  if (ps->rils != ps->rilshead)
+    {
+      res = *--ps->rilshead;
+      assert (ps->vars[res].internal);
+    }
+  else
+    {
+      inc_max_var (ps);
+      res = ps->max_var;
+      v = ps->vars + res;
+      assert (!v->internal);
+      v->internal = 1;
+      ps->internals++;
+      LOG ( fprintf (ps->out, "%snew internal variable index %d\n", ps->prefix, res));
+    }
+
+  lit = int2lit (ps, res);
+
+  if (ps->clshead == ps->eocls)
+    ENLARGE (ps->CLS, ps->clshead, ps->eocls);
+  *ps->clshead++ = lit;
+
+  ps->contexts++;
+
+  LOG ( fprintf (ps->out, "%snew context %d at depth %ld after push\n",
+                 ps->prefix, res, (long)(ps->clshead - ps->CLS)));
+
+  if (ps->measurealltimeinlib)
+    leave (ps);
+
+  return res;
+}
+
+int
+picosat_pop (PS * ps)
+{
+  Lit * lit;
+  int res;
+  ABORTIF (ps->CLS == ps->clshead, "API usage: too many 'picosat_pop'");
+  ABORTIF (ps->added != ps->ahead, "API usage: incomplete clause");
+
+  if (ps->measurealltimeinlib)
+    enter (ps);
+  else
+    check_ready (ps);
+
+  if (ps->state != READY)
+    reset_incremental_usage (ps);
+
+  assert (ps->CLS < ps->clshead);
+  lit = *--ps->clshead;
+  LOG ( fprintf (ps->out, "%sclosing context %d at depth %ld after pop\n",
+                 ps->prefix, LIT2INT (lit), (long)(ps->clshead - ps->CLS) + 1));
+
+  if (ps->cilshead == ps->eocils)
+    ENLARGE (ps->cils, ps->cilshead, ps->eocils);
+  *ps->cilshead++ = LIT2INT (lit);
+
+  if (ps->cilshead - ps->cils > MAXCILS) {
+    LOG ( fprintf (ps->out,
+                  "%srecycling %ld interals with forced simplification\n",
+          ps->prefix, (long)(ps->cilshead - ps->cils)));
+    simplify (ps, 1);
+  }
+
+  res = picosat_context (ps);
+  if (res)
+    LOG ( fprintf (ps->out, "%snew context %d at depth %ld after pop\n",
+           ps->prefix, res, (long)(ps->clshead - ps->CLS)));
+  else
+    LOG ( fprintf (ps->out, "%souter most context reached after pop\n", ps->prefix));
+
+  if (ps->measurealltimeinlib)
+    leave (ps);
+  
+  return res;
+}
+
+void
+picosat_set_verbosity (PS * ps, int new_verbosity_level)
+{
+  check_ready (ps);
+  ps->verbosity = new_verbosity_level;
+}
+
+void
+picosat_set_plain (PS * ps, int new_plain_value)
+{
+  check_ready (ps);
+  ps->plain = new_plain_value;
+}
+
+int
+picosat_enable_trace_generation (PS * ps)
+{
+  int res = 0;
+  check_ready (ps);
+#ifdef TRACE
+  ABORTIF (ps->addedclauses,
+           "API usage: trace generation enabled after adding clauses");
+  res = ps->trace = 1;
+#endif
+  return res;
+}
+
+void
+picosat_set_incremental_rup_file (PS * ps, FILE * rup_file, int m, int n)
+{
+  check_ready (ps);
+  assert (!ps->rupstarted);
+  ps->rup = rup_file;
+  ps->rupvariables = m;
+  ps->rupclauses = n;
+}
+
+void
+picosat_set_output (PS * ps, FILE * output_file)
+{
+  check_ready (ps);
+  ps->out = output_file;
+}
+
+void
+picosat_measure_all_calls (PS * ps)
+{
+  check_ready (ps);
+  ps->measurealltimeinlib = 1;
+}
+
+void
+picosat_set_prefix (PS * ps, const char * str)
+{
+  check_ready (ps);
+  new_prefix (ps, str);
+}
+
+void
+picosat_set_seed (PS * ps, unsigned s)
+{
+  check_ready (ps);
+  ps->srng = s;
+}
+
+void
+picosat_reset (PS * ps)
+{
+  check_ready (ps);
+  reset (ps);
+}
+
+int
+picosat_add (PS * ps, int int_lit)
+{
+  int res = ps->oadded;
+  Lit *lit;
+
+  if (ps->measurealltimeinlib)
+    enter (ps);
+  else
+    check_ready (ps);
+
+  ABORTIF (ps->rup && ps->rupstarted && ps->oadded >= (unsigned)ps->rupclauses,
+           "API usage: adding too many clauses after RUP header written");
+#ifndef NADC
+  ABORTIF (ps->addingtoado,
+           "API usage: 'picosat_add' and 'picosat_add_ado_lit' mixed");
+#endif
+  if (ps->state != READY)
+    reset_incremental_usage (ps);
+
+  if (ps->saveorig)
+    {
+      if (ps->sohead == ps->eoso)
+    ENLARGE (ps->soclauses, ps->sohead, ps->eoso);
+
+      *ps->sohead++ = int_lit;
+    }
+
+  if (int_lit)
+    {
+      lit = import_lit (ps, int_lit, 1);
+      add_lit (ps, lit);
+    }
+  else
+    simplify_and_add_original_clause (ps);
+
+  if (ps->measurealltimeinlib)
+    leave (ps);
+
+  return res;
+}
+
+int
+picosat_add_arg (PS * ps, ...)
+{
+  int lit;
+  va_list ap;
+  va_start (ap, ps);
+  while ((lit = va_arg (ap, int)))
+    (void) picosat_add (ps, lit);
+  va_end (ap);
+  return picosat_add (ps, 0);
+}
+
+int
+picosat_add_lits (PS * ps, int * lits)
+{
+  const int * p;
+  int lit;
+  for (p = lits; (lit = *p); p++)
+    (void) picosat_add (ps, lit);
+  return picosat_add (ps, 0);
+}
+
+void
+picosat_add_ado_lit (PS * ps, int external_lit)
+{
+#ifndef NADC
+  Lit * internal_lit;
+
+  if (ps->measurealltimeinlib)
+    enter (ps);
+  else
+    check_ready (ps);
+
+  if (ps->state != READY)
+    reset_incremental_usage (ps);
+
+  ABORTIF (!ps->addingtoado && ps->ahead > ps->added,
+           "API usage: 'picosat_add' and 'picosat_add_ado_lit' mixed");
+
+  if (external_lit)
+    {
+      ps->addingtoado = 1;
+      internal_lit = import_lit (ps, external_lit, 1);
+      add_lit (ps, internal_lit);
+    }
+  else
+    {
+      ps->addingtoado = 0;
+      add_ado (ps);
+    }
+  if (ps->measurealltimeinlib)
+    leave (ps);
+#else
+  (void) ps;
+  (void) external_lit;
+  ABORT ("compiled without all different constraint support");
+#endif
+}
+
+static void
+assume (PS * ps, Lit * lit)
+{
+  if (ps->alshead == ps->eoals)
+    {
+      assert (ps->alstail == ps->als);
+      ENLARGE (ps->als, ps->alshead, ps->eoals);
+      ps->alstail = ps->als;
+    }
+
+  *ps->alshead++ = lit;
+  LOG ( fprintf (ps->out, "%sassumption %d\n", ps->prefix, LIT2INT (lit)));
+}
+
+static void
+assume_contexts (PS * ps)
+{
+  Lit ** p;
+  if (ps->als != ps->alshead)
+    return;
+  for (p = ps->CLS; p != ps->clshead; p++)
+    assume (ps, *p);
+}
+
+#ifndef RCODE
+static const char * enumstr (int i) {
+  int last = i % 10;
+  if (last == 1) return "st";
+  if (last == 2) return "nd";
+  if (last == 3) return "rd";
+  return "th";
+}
+#endif
+
+static int
+tderef (PS * ps, int int_lit)
+{
+  Lit * lit;
+  Var * v;
+
+  assert (abs (int_lit) <= (int) ps->max_var);
+
+  lit = int2lit (ps, int_lit);
+
+  v = LIT2VAR (lit);
+  if (v->level > 0)
+    return 0;
+
+  if (lit->val == TRUE)
+    return 1;
+
+  if (lit->val == FALSE)
+    return -1;
+
+  return 0;
+}
+
+static int
+pderef (PS * ps, int int_lit)
+{
+  Lit * lit;
+  Var * v;
+
+  assert (abs (int_lit) <= (int) ps->max_var);
+
+  v = ps->vars + abs (int_lit);
+  if (!v->partial)
+    return 0;
+
+  lit = int2lit (ps, int_lit);
+
+  if (lit->val == TRUE)
+    return 1;
+
+  if (lit->val == FALSE)
+    return -1;
+
+  return 0;
+}
+
+static void
+minautarky (PS * ps)
+{
+  unsigned * occs, maxoccs, tmpoccs, npartial;
+  int * p, * c, lit, best, val;
+#ifdef LOGGING
+  int tl;
+#endif
+
+  assert (!ps->partial);
+
+  npartial = 0;
+
+  NEWN (occs, 2*ps->max_var + 1);
+  CLRN (occs, 2*ps->max_var + 1);
+  occs += ps->max_var;
+  for (p = ps->soclauses; p < ps->sohead; p++)
+    occs[*p]++;
+  assert (occs[0] == ps->oadded);
+
+  for (c = ps->soclauses; c < ps->sohead; c = p + 1)
+    {
+#ifdef LOGGING
+      tl = 0;
+#endif
+      best = 0;
+      maxoccs = 0;
+      for (p = c; (lit = *p); p++)
+    {
+      val = tderef (ps, lit);
+      if (val < 0)
+        continue;
+      if (val > 0)
+        {
+#ifdef LOGGING
+          tl = 1;
+#endif
+          best = lit;
+          maxoccs = occs[lit];
+        }
+
+      val = pderef (ps, lit);
+      if (val > 0)
+        break;
+      if (val < 0)
+        continue;
+      val = int2lit (ps, lit)->val;
+      assert (val);
+      if (val < 0)
+        continue;
+      tmpoccs = occs[lit];
+      if (best && tmpoccs <= maxoccs)
+        continue;
+      best = lit;
+      maxoccs = tmpoccs;
+    }
+      if (!lit)
+    {
+      assert (best);
+      LOG ( fprintf (ps->out, "%sautark %d with %d occs%s\n",
+           ps->prefix, best, maxoccs, tl ? " (top)" : ""));
+      ps->vars[abs (best)].partial = 1;
+      npartial++;
+    }
+      for (p = c; (lit = *p); p++)
+    {
+      assert (occs[lit] > 0);
+      occs[lit]--;
+    }
+    }
+  occs -= ps->max_var;
+  DELETEN (occs, 2*ps->max_var + 1);
+  ps->partial = 1;
+
+  if (ps->verbosity)
+     fprintf (ps->out,
+      "%sautarky of size %u out of %u satisfying all clauses (%.1f%%)\n",
+      ps->prefix, npartial, ps->max_var, PERCENT (npartial, ps->max_var));
+}
+
+void
+picosat_assume (PS * ps, int int_lit)
+{
+  Lit *lit;
+
+  if (ps->measurealltimeinlib)
+    enter (ps);
+  else
+    check_ready (ps);
+
+  if (ps->state != READY)
+    reset_incremental_usage (ps);
+
+  assume_contexts (ps);
+  lit = import_lit (ps, int_lit, 1);
+  assume (ps, lit);
+
+  if (ps->measurealltimeinlib)
+    leave (ps);
+}
+
+int
+picosat_sat (PS * ps, int l)
+{
+  int res;
+  char ch;
+
+  enter (ps);
+
+  ps->calls++;
+  LOG ( fprintf (ps->out, "%sSTART call %u\n", ps->prefix, ps->calls));
+
+  if (ps->added < ps->ahead)
+    {
+#ifndef NADC
+      if (ps->addingtoado)
+    ABORT ("API usage: incomplete all different constraint");
+      else
+#endif
+    ABORT ("API usage: incomplete clause");
+    }
+
+  if (ps->state != READY)
+    reset_incremental_usage (ps);
+
+  assume_contexts (ps);
+
+  res = sat (ps, l);
+
+  assert (ps->state == READY);
+
+  switch (res)
+    {
+    case PICOSAT_UNSATISFIABLE:
+      ch = '0';
+      ps->state = UNSAT;
+      break;
+    case PICOSAT_SATISFIABLE:
+      ch = '1';
+      ps->state = SAT;
+      break;
+    default:
+      ch = '?';
+      ps->state = UNKNOWN;
+      break;
+    }
+
+  if (ps->verbosity)
+    {
+      report (ps, 1, ch);
+      rheader (ps);
+    }
+
+  leave (ps);
+  LOG ( fprintf (ps->out, "%sEND call %u result %d\n", ps->prefix, ps->calls, res));
+
+  ps->last_sat_call_result = res;
+
+  return res;
+}
+
+int
+picosat_res (PS * ps)
+{
+  return ps->last_sat_call_result;
+}
+
+int
+picosat_deref (PS * ps, int int_lit)
+{
+  Lit *lit;
+
+  check_ready (ps);
+  check_sat_state (ps);
+  ABORTIF (!int_lit, "API usage: can not deref zero literal");
+  ABORTIF (ps->mtcls, "API usage: deref after empty clause generated");
+
+#ifdef STATS
+  ps->derefs++;
+#endif
+
+  if (abs (int_lit) > (int) ps->max_var)
+    return 0;
+
+  lit = int2lit (ps, int_lit);
+
+  if (lit->val == TRUE)
+    return 1;
+
+  if (lit->val == FALSE)
+    return -1;
+
+  return 0;
+}
+
+int
+picosat_deref_toplevel (PS * ps, int int_lit)
+{
+  check_ready (ps);
+  ABORTIF (!int_lit, "API usage: can not deref zero literal");
+
+#ifdef STATS
+  ps->derefs++;
+#endif
+  if (abs (int_lit) > (int) ps->max_var)
+    return 0;
+
+  return tderef (ps, int_lit);
+}
+
+int
+picosat_inconsistent (PS * ps)
+{
+  check_ready (ps);
+  return ps->mtcls != 0;
+}
+
+int
+picosat_corelit (PS * ps, int int_lit)
+{
+  check_ready (ps);
+  check_unsat_state (ps);
+  ABORTIF (!int_lit, "API usage: zero literal can not be in core");
+
+  assert (ps->mtcls || ps->failed_assumption);
+
+#ifdef TRACE
+  {
+    int res = 0;
+    ABORTIF (!ps->trace, "tracing disabled");
+    if (ps->measurealltimeinlib)
+      enter (ps);
+    core (ps);
+    if (abs (int_lit) <= (int) ps->max_var)
+      res = ps->vars[abs (int_lit)].core;
+    assert (!res || ps->failed_assumption || ps->vars[abs (int_lit)].used);
+    if (ps->measurealltimeinlib)
+      leave (ps);
+    return res;
+  }
+#else
+  ABORT ("compiled without trace support");
+  return 0;
+#endif
+}
+
+int
+picosat_coreclause (PS * ps, int ocls)
+{
+  check_ready (ps);
+  check_unsat_state (ps);
+
+  ABORTIF (ocls < 0, "API usage: negative original clause index");
+  ABORTIF (ocls >= (int)ps->oadded, "API usage: original clause index exceeded");
+
+  assert (ps->mtcls || ps->failed_assumption);
+
+#ifdef TRACE
+  {
+    Cls ** clsptr, * c;
+    int res  = 0;
+
+    ABORTIF (!ps->trace, "tracing disabled");
+    if (ps->measurealltimeinlib)
+      enter (ps);
+    core (ps);
+    clsptr = ps->oclauses + ocls;
+    assert (clsptr < ps->ohead);
+    c = *clsptr;
+    if (c)
+      res = c->core;
+    if (ps->measurealltimeinlib)
+      leave (ps);
+
+    return res;
+  }
+#else
+  ABORT ("compiled without trace support");
+  return 0;
+#endif
+}
+
+int
+picosat_failed_assumption (PS * ps, int int_lit)
+{
+  Lit * lit;
+  Var * v;
+  ABORTIF (!int_lit, "API usage: zero literal as assumption");
+  check_ready (ps);
+  check_unsat_state (ps);
+  if (ps->mtcls)
+    return 0;
+  assert (ps->failed_assumption);
+  if (abs (int_lit) > (int) ps->max_var)
+    return 0;
+  if (!ps->extracted_all_failed_assumptions)
+    extract_all_failed_assumptions (ps);
+  lit = import_lit (ps, int_lit, 1);
+  v = LIT2VAR (lit);
+  return v->failed;
+}
+
+int
+picosat_failed_context (PS * ps, int int_lit)
+{
+  Lit * lit;
+  Var * v;
+  ABORTIF (!int_lit, "API usage: zero literal as context");
+  ABORTIF (abs (int_lit) > (int) ps->max_var, "API usage: invalid context");
+  check_ready (ps);
+  check_unsat_state (ps);
+  assert (ps->failed_assumption);
+  if (!ps->extracted_all_failed_assumptions)
+    extract_all_failed_assumptions (ps);
+  lit = import_lit (ps, int_lit, 0);
+  v = LIT2VAR (lit);
+  return v->failed;
+}
+
+const int *
+picosat_failed_assumptions (PS * ps)
+{
+  Lit ** p, * lit;
+  Var * v;
+  int ilit;
+
+  ps->falshead = ps->fals;
+  check_ready (ps);
+  check_unsat_state (ps);
+  if (!ps->mtcls)
+    {
+      assert (ps->failed_assumption);
+      if (!ps->extracted_all_failed_assumptions)
+    extract_all_failed_assumptions (ps);
+
+      for (p = ps->als; p < ps->alshead; p++)
+    {
+      lit = *p;
+      v = LIT2VAR (*p);
+      if (!v->failed)
+        continue;
+      ilit = LIT2INT (lit);
+      if (ps->falshead == ps->eofals)
+        ENLARGE (ps->fals, ps->falshead, ps->eofals);
+      *ps->falshead++ = ilit;
+    }
+    }
+  if (ps->falshead == ps->eofals)
+    ENLARGE (ps->fals, ps->falshead, ps->eofals);
+  *ps->falshead++ = 0;
+  return ps->fals;
+}
+
+const int *
+picosat_mus_assumptions (PS * ps, void * s, void (*cb)(void*,const int*), int fix)
+{
+  int i, j, ilit, len, nwork, * work, res;
+  signed char * redundant;
+  Lit ** p, * lit;
+  int failed;
+  Var * v;
+#ifndef NDEBUG
+  int oldlen;
+#endif
+#ifndef RCODE
+  int norig = ps->alshead - ps->als;
+#endif
+
+  check_ready (ps);
+  check_unsat_state (ps);
+  len = 0;
+  if (!ps->mtcls)
+    {
+      assert (ps->failed_assumption);
+      if (!ps->extracted_all_failed_assumptions)
+    extract_all_failed_assumptions (ps);
+
+      for (p = ps->als; p < ps->alshead; p++)
+    if (LIT2VAR (*p)->failed)
+      len++;
+    }
+
+  if (ps->mass)
+    DELETEN (ps->mass, ps->szmass);
+  ps->szmass = len + 1;
+  NEWN (ps->mass, ps->szmass);
+
+  i = 0;
+  for (p = ps->als; p < ps->alshead; p++)
+    {
+      lit = *p;
+      v = LIT2VAR (lit);
+      if (!v->failed)
+    continue;
+      ilit = LIT2INT (lit);
+      assert (i < len);
+      ps->mass[i++] = ilit;
+    }
+  assert (i == len);
+  ps->mass[i] = 0;
+  if (ps->verbosity)
+     fprintf (ps->out,
+      "%sinitial set of failed assumptions of size %d out of %d (%.0f%%)\n",
+      ps->prefix, len, norig, PERCENT (len, norig));
+  if (cb)
+    cb (s, ps->mass);
+
+  nwork = len;
+  NEWN (work, nwork);
+  for (i = 0; i < len; i++)
+    work[i] = ps->mass[i];
+
+  NEWN (redundant, nwork);
+  CLRN (redundant, nwork);
+
+  for (i = 0; i < nwork; i++)
+    {
+      if (redundant[i])
+    continue;
+
+      if (ps->verbosity > 1)
+     fprintf (ps->out,
+             "%strying to drop %d%s assumption %d\n",
+         ps->prefix, i, enumstr (i), work[i]);
+      for (j = 0; j < nwork; j++)
+    {
+      if (i == j) continue;
+      if (j < i && fix) continue;
+      if (redundant[j]) continue;
+      picosat_assume (ps, work[j]);
+    }
+
+      res = picosat_sat (ps, -1);
+      if (res == 10)
+    {
+      if (ps->verbosity > 1)
+         fprintf (ps->out,
+             "%sfailed to drop %d%s assumption %d\n",
+             ps->prefix, i, enumstr (i), work[i]);
+
+      if (fix)
+        {
+          picosat_add (ps, work[i]);
+          picosat_add (ps, 0);
+        }
+    }
+      else
+    {
+      assert (res == 20);
+      if (ps->verbosity > 1)
+         fprintf (ps->out,
+             "%ssuceeded to drop %d%s assumption %d\n",
+             ps->prefix, i, enumstr (i), work[i]);
+      redundant[i] = 1;
+      for (j = 0; j < nwork; j++)
+        {
+          failed = picosat_failed_assumption (ps, work[j]);
+          if (j <= i)
+        {
+          assert ((j < i && fix) || redundant[j] == !failed);
+          continue;
+        }
+
+          if (!failed)
+        {
+          redundant[j] = -1;
+          if (ps->verbosity > 1)
+             fprintf (ps->out,
+                 "%salso suceeded to drop %d%s assumption %d\n",
+                 ps->prefix, j, enumstr (j), work[j]);
+        }
+        }
+
+#ifndef NDEBUG
+        oldlen = len;
+#endif
+        len = 0;
+        for (j = 0; j < nwork; j++)
+          if (!redundant[j])
+        ps->mass[len++] = work[j];
+        ps->mass[len] = 0;
+        assert (len < oldlen);
+
+        if (fix)
+          {
+        picosat_add (ps, -work[i]);
+        picosat_add (ps, 0);
+          }
+
+#ifndef NDEBUG
+        for (j = 0; j <= i; j++)
+          assert (redundant[j] >= 0);
+#endif
+        for (j = i + 1; j < nwork; j++)
+          {
+        if (redundant[j] >= 0)
+          continue;
+
+        if (fix)
+          {
+            picosat_add (ps, -work[j]);
+            picosat_add (ps, 0);
+          }
+
+        redundant[j] = 1;
+          }
+
+        if (ps->verbosity)
+           fprintf (ps->out,
+    "%sreduced set of failed assumptions of size %d out of %d (%.0f%%)\n",
+        ps->prefix, len, norig, PERCENT (len, norig));
+        if (cb)
+          cb (s, ps->mass);
+    }
+    }
+
+  DELETEN (work, nwork);
+  DELETEN (redundant, nwork);
+
+  if (ps->verbosity)
+    {
+       fprintf (ps->out, "%sreinitializing unsat state\n", ps->prefix);
+      fflush (ps->out);
+    }
+
+  for (i = 0; i < len; i++)
+    picosat_assume (ps, ps->mass[i]);
+
+#ifndef NDEBUG
+  res =
+#endif
+  picosat_sat (ps, -1);
+  assert (res == 20);
+
+  if (!ps->mtcls)
+    {
+      assert (!ps->extracted_all_failed_assumptions);
+      extract_all_failed_assumptions (ps);
+    }
+
+  return ps->mass;
+}
+
+static const int *
+mss (PS * ps, int * a, int size)
+{
+  int i, j, k, res;
+
+  assert (!ps->mtcls);
+
+  if (ps->szmssass)
+    DELETEN (ps->mssass, ps->szmssass);
+
+  ps->szmssass = 0;
+  ps->mssass = 0;
+
+  ps->szmssass = size + 1;
+  NEWN (ps->mssass, ps->szmssass);
+
+  LOG ( fprintf (ps->out, "%ssearch MSS over %d assumptions\n", ps->prefix, size));
+
+  k = 0;
+  for (i = k; i < size; i++)
+    {
+      for (j = 0; j < k; j++)
+    picosat_assume (ps, ps->mssass[j]);
+
+      LOG ( fprintf (ps->out,
+             "%strying to add assumption %d to MSS : %d\n",
+         ps->prefix, i, a[i]));
+
+      picosat_assume (ps, a[i]);
+
+      res = picosat_sat (ps, -1);
+      if (res == 10)
+    {
+      LOG ( fprintf (ps->out,
+         "%sadding assumption %d to MSS : %d\n", ps->prefix, i, a[i]));
+
+      ps->mssass[k++] = a[i];
+
+      for (j = i + 1; j < size; j++)
+        {
+          if (picosat_deref (ps, a[j]) <= 0)
+        continue;
+
+          LOG ( fprintf (ps->out,
+             "%salso adding assumption %d to MSS : %d\n",
+             ps->prefix, j, a[j]));
+
+          ps->mssass[k++] = a[j];
+
+          if (++i != j)
+        {
+          int tmp = a[i];
+          a[i] = a[j];
+          a[j] = tmp;
+        }
+        }
+    }
+      else
+    {
+      assert (res == 20);
+
+      LOG ( fprintf (ps->out,
+         "%signoring assumption %d in MSS : %d\n", ps->prefix, i, a[i]));
+    }
+    }
+  ps->mssass[k] = 0;
+  LOG ( fprintf (ps->out, "%sfound MSS of size %d\n", ps->prefix, k));
+
+  return ps->mssass;
+}
+
+static void
+reassume (PS * ps, const int * a, int size)
+{
+  int i;
+  LOG ( fprintf (ps->out, "%sreassuming all assumptions\n", ps->prefix));
+  for (i = 0; i < size; i++)
+    picosat_assume (ps, a[i]);
+}
+
+const int *
+picosat_maximal_satisfiable_subset_of_assumptions (PS * ps)
+{
+  const int * res;
+  int i, *a, size;
+
+  ABORTIF (ps->mtcls,
+           "API usage: CNF inconsistent (use 'picosat_inconsistent')");
+
+  enter (ps);
+
+  size = ps->alshead - ps->als;
+  NEWN (a, size);
+
+  for (i = 0; i < size; i++)
+    a[i] = LIT2INT (ps->als[i]);
+
+  res = mss (ps, a, size);
+  reassume (ps, a, size);
+
+  DELETEN (a, size);
+
+  leave (ps);
+
+  return res;
+}
+
+static void
+check_mss_flags_clean (PS * ps)
+{
+#ifndef NDEBUG
+  unsigned i;
+  for (i = 1; i <= ps->max_var; i++)
+    {
+      assert (!ps->vars[i].msspos);
+      assert (!ps->vars[i].mssneg);
+    }
+#else
+  (void) ps;
+#endif
+}
+
+static void
+push_mcsass (PS * ps, int lit)
+{
+  if (ps->nmcsass == ps->szmcsass)
+    {
+      ps->szmcsass = ps->szmcsass ? 2*ps->szmcsass : 1;
+      RESIZEN (ps->mcsass, ps->nmcsass, ps->szmcsass);
+    }
+
+  ps->mcsass[ps->nmcsass++] = lit;
+}
+
+static const int *
+next_mss (PS * ps, int mcs)
+{
+  int i, *a, size, mssize, mcsize, lit, inmss;
+  const int * res, * p;
+  Var * v;
+
+  if (ps->mtcls) return 0;
+
+  check_mss_flags_clean (ps);
+
+  if (mcs && ps->mcsass)
+    {
+      DELETEN (ps->mcsass, ps->szmcsass);
+      ps->nmcsass = ps->szmcsass = 0;
+      ps->mcsass = 0;
+    }
+
+  size = ps->alshead - ps->als;
+  NEWN (a, size);
+
+  for (i = 0; i < size; i++)
+    a[i] = LIT2INT (ps->als[i]);
+
+  (void) picosat_sat (ps, -1);
+
+  //TODO short cut for 'picosat_res () == 10'?
+
+  if (ps->mtcls)
+    {
+      assert (picosat_res (ps) == 20);
+      res = 0;
+      goto DONE;
+    }
+
+  res = mss (ps, a, size);
+
+  if (ps->mtcls)
+    {
+      res = 0;
+      goto DONE;
+    }
+
+  for (p = res; (lit = *p); p++)
+    {
+      v = ps->vars + abs (lit);
+      if (lit < 0)
+    {
+      assert (!v->msspos);
+      v->mssneg = 1;
+    }
+      else
+    {
+      assert (!v->mssneg);
+      v->msspos = 1;
+    }
+    }
+
+  mssize = p - res;
+  mcsize = INT_MIN;
+
+  for (i = 0; i < size; i++)
+    {
+      lit = a[i];
+      v = ps->vars + abs (lit);
+      if (lit > 0 && v->msspos)
+    inmss = 1;
+      else if (lit < 0 && v->mssneg)
+    inmss = 1;
+      else
+    inmss = 0;
+
+      if (mssize < mcsize)
+    {
+      if (inmss)
+        picosat_add (ps, -lit);
+    }
+      else
+    {
+      if (!inmss)
+        picosat_add (ps, lit);
+    }
+
+      if (!inmss && mcs)
+    push_mcsass (ps, lit);
+    }
+  picosat_add (ps, 0);
+  if (mcs)
+    push_mcsass (ps, 0);
+
+  for (i = 0; i < size; i++)
+    {
+      lit = a[i];
+      v = ps->vars + abs (lit);
+      v->msspos = 0;
+      v->mssneg = 0;
+    }
+
+DONE:
+
+  reassume (ps, a, size);
+  DELETEN (a, size);
+
+  return res;
+}
+
+const int *
+picosat_next_maximal_satisfiable_subset_of_assumptions (PS * ps)
+{
+  const int * res;
+  enter (ps);
+  res = next_mss (ps, 0);
+  leave (ps);
+  return  res;
+}
+
+const int *
+picosat_next_minimal_correcting_subset_of_assumptions (PS * ps)
+{
+  const int * res, * tmp;
+  enter (ps);
+  tmp = next_mss (ps, 1);
+  res = tmp ? ps->mcsass : 0;
+  leave (ps);
+  return res;
+}
+
+const int *
+picosat_humus (PS * ps,
+               void (*callback)(void*state,int nmcs,int nhumus),
+           void * state)
+{
+  int lit, nmcs, j, nhumus;
+  const int * mcs, * p;
+  unsigned i;
+  Var * v;
+  enter (ps);
+#ifndef NDEBUG
+  for (i = 1; i <= ps->max_var; i++)
+    {
+      v = ps->vars + i;
+      assert (!v->humuspos);
+      assert (!v->humusneg);
+    }
+#endif
+  nhumus = nmcs = 0;
+  while ((mcs = picosat_next_minimal_correcting_subset_of_assumptions (ps)))
+    {
+      for (p = mcs; (lit = *p); p++)
+    {
+      v = ps->vars + abs (lit);
+      if (lit < 0)
+        {
+          if (!v->humusneg)
+        {
+          v->humusneg = 1;
+          nhumus++;
+        }
+        }
+      else
+        {
+          if (!v->humuspos)
+        {
+          v->humuspos = 1;
+          nhumus++;
+        }
+        }
+    }
+      nmcs++;
+      LOG ( fprintf (ps->out,
+             "%smcs %d of size %d humus %d\n",
+         ps->prefix, nmcs, (int)(p - mcs), nhumus));
+      if (callback)
+    callback (state, nmcs, nhumus);
+    }
+  assert (!ps->szhumus);
+  ps->szhumus = 1;
+  for (i = 1; i <= ps->max_var; i++)
+    {
+      v = ps->vars + i;
+      if (v->humuspos)
+    ps->szhumus++;
+      if (v->humusneg)
+    ps->szhumus++;
+    }
+  assert (nhumus + 1 == ps->szhumus);
+  NEWN (ps->humus, ps->szhumus);
+  j = 0;
+  for (i = 1; i <= ps->max_var; i++)
+    {
+      v = ps->vars + i;
+      if (v->humuspos)
+    {
+      assert (j < nhumus);
+      ps->humus[j++] = (int) i;
+    }
+      if (v->humusneg)
+    {
+      assert (j < nhumus);
+      assert (i < INT_MAX);
+      ps->humus[j++] = - (int) i;
+    }
+    }
+  assert (j == nhumus);
+  assert (j < ps->szhumus);
+  ps->humus[j] = 0;
+  leave (ps);
+  return ps->humus;
+}
+
+int
+picosat_usedlit (PS * ps, int int_lit)
+{
+  int res;
+  check_ready (ps);
+  check_sat_or_unsat_or_unknown_state (ps);
+  ABORTIF (!int_lit, "API usage: zero literal can not be used");
+  int_lit = abs (int_lit);
+  res = (int_lit <= (int) ps->max_var) ? ps->vars[int_lit].used : 0;
+  return res;
+}
+
+void
+picosat_write_clausal_core (PS * ps, FILE * file)
+{
+  check_trace_support_and_execute (ps, file, write_core_wrapper, 0);
+}
+
+void
+picosat_write_compact_trace (PS * ps, FILE * file)
+{
+  check_trace_support_and_execute (ps, file, write_trace,
+                                   COMPACT_TRACECHECK_TRACE_FMT);
+}
+
+void
+picosat_write_extended_trace (PS * ps, FILE * file)
+{
+  check_trace_support_and_execute (ps, file, write_trace,
+                                   EXTENDED_TRACECHECK_TRACE_FMT);
+}
+
+void
+picosat_write_rup_trace (PS * ps, FILE * file)
+{
+  check_trace_support_and_execute (ps, file, write_trace, RUP_TRACE_FMT);
+}
+
+size_t
+picosat_max_bytes_allocated (PS * ps)
+{
+  check_ready (ps);
+  return ps->max_bytes;
+}
+
+void
+picosat_set_propagation_limit (PS * ps, unsigned long long l)
+{
+  ps->lpropagations = l;
+}
+
+unsigned long long
+picosat_propagations (PS * ps)
+{
+  return ps->propagations;
+}
+
+unsigned long long
+picosat_visits (PS * ps)
+{
+  return ps->visits;
+}
+
+unsigned long long
+picosat_decisions (PS * ps)
+{
+  return ps->decisions;
+}
+
+int
+picosat_variables (PS * ps)
+{
+  check_ready (ps);
+  return (int) ps->max_var;
+}
+
+int
+picosat_added_original_clauses (PS * ps)
+{
+  check_ready (ps);
+  return (int) ps->oadded;
+}
+
+void
+picosat_stats (PS * ps)
+{
+#ifndef RCODE
+  unsigned redlits;
+#endif
+#ifdef STATS
+  check_ready (ps);
+  assert (ps->sdecisions + ps->rdecisions + ps->assumptions == ps->decisions);
+#endif
+  if (ps->calls > 1)
+     fprintf (ps->out, "%s%u calls\n", ps->prefix, ps->calls);
+  if (ps->contexts)
+    {
+       fprintf (ps->out, "%s%u contexts", ps->prefix, ps->contexts);
+#ifdef STATS
+       fprintf (ps->out, " %u internal variables", ps->internals);
+#endif
+       fprintf (ps->out, "\n");
+    }
+   fprintf (ps->out, "%s%u iterations\n", ps->prefix, ps->iterations);
+   fprintf (ps->out, "%s%u restarts", ps->prefix, ps->restarts);
+#ifdef STATS
+   fprintf (ps->out, " (%u skipped)", ps->skippedrestarts);
+#endif
+  fputc ('\n', ps->out);
+#ifndef NFL
+   fprintf (ps->out, "%s%u failed literals", ps->prefix, ps->failedlits);
+#ifdef STATS
+   fprintf (ps->out,
+           ", %u calls, %u rounds, %llu propagations",
+           ps->flcalls, ps->flrounds, ps->flprops);
+#endif
+  fputc ('\n', ps->out);
+#ifdef STATS
+   fprintf (ps->out,
+    "%sfl: %u = %.1f%% implicit, %llu oopsed, %llu tried, %llu skipped\n",
+    ps->prefix,
+    ps->ifailedlits, PERCENT (ps->ifailedlits, ps->failedlits),
+    ps->floopsed, ps->fltried, ps->flskipped);
+#endif
+#endif
+   fprintf (ps->out, "%s%u conflicts", ps->prefix, ps->conflicts);
+#ifdef STATS
+   fprintf (ps->out, " (%u uips = %.1f%%)\n", ps->uips, PERCENT(ps->uips,ps->conflicts));
+#else
+  fputc ('\n', ps->out);
+#endif
+#ifndef NADC
+   fprintf (ps->out, "%s%u adc conflicts\n", ps->prefix, ps->adoconflicts);
+#endif
+#ifdef STATS
+   fprintf (ps->out, "%s%llu dereferenced literals\n", ps->prefix, ps->derefs);
+#endif
+   fprintf (ps->out, "%s%u decisions", ps->prefix, ps->decisions);
+#ifdef STATS
+   fprintf (ps->out, " (%u random = %.2f%%",
+           ps->rdecisions, PERCENT (ps->rdecisions, ps->decisions));
+   fprintf (ps->out, ", %u assumptions", ps->assumptions);
+  fputc (')', ps->out);
+#endif
+  fputc ('\n', ps->out);
+#ifdef STATS
+   fprintf (ps->out,
+           "%s%u static phase decisions (%.1f%% of all variables)\n",
+       ps->prefix,
+       ps->staticphasedecisions, PERCENT (ps->staticphasedecisions, ps->max_var));
+#endif
+   fprintf (ps->out, "%s%u fixed variables\n", ps->prefix, ps->fixed);
+  assert (ps->nonminimizedllits >= ps->minimizedllits);
+#ifndef RCODE
+  redlits = ps->nonminimizedllits - ps->minimizedllits;
+#endif
+   fprintf (ps->out, "%s%u learned literals\n", ps->prefix, ps->llitsadded);
+   fprintf (ps->out, "%s%.1f%% deleted literals\n",
+     ps->prefix, PERCENT (redlits, ps->nonminimizedllits));
+
+#ifdef STATS
+#ifdef TRACE
+   fprintf (ps->out,
+       "%s%llu antecedents (%.1f antecedents per clause",
+       ps->prefix, ps->antecedents, AVERAGE (ps->antecedents, ps->conflicts));
+  if (ps->trace)
+     fprintf (ps->out, ", %.1f bytes/antecedent)", AVERAGE (ps->znts, ps->antecedents));
+  fputs (")\n", ps->out);
+#endif
+
+   fprintf (ps->out, "%s%llu propagations (%.1f propagations per decision)\n",
+           ps->prefix, ps->propagations, AVERAGE (ps->propagations, ps->decisions));
+   fprintf (ps->out, "%s%llu visits (%.1f per propagation)\n",
+       ps->prefix, ps->visits, AVERAGE (ps->visits, ps->propagations));
+   fprintf (ps->out,
+           "%s%llu binary clauses visited (%.1f%% %.1f per propagation)\n",
+       ps->prefix, ps->bvisits,
+       PERCENT (ps->bvisits, ps->visits),
+       AVERAGE (ps->bvisits, ps->propagations));
+   fprintf (ps->out,
+           "%s%llu ternary clauses visited (%.1f%% %.1f per propagation)\n",
+       ps->prefix, ps->tvisits,
+       PERCENT (ps->tvisits, ps->visits),
+       AVERAGE (ps->tvisits, ps->propagations));
+   fprintf (ps->out,
+           "%s%llu large clauses visited (%.1f%% %.1f per propagation)\n",
+       ps->prefix, ps->lvisits,
+       PERCENT (ps->lvisits, ps->visits),
+       AVERAGE (ps->lvisits, ps->propagations));
+   fprintf (ps->out, "%s%llu other true (%.1f%% of visited clauses)\n",
+       ps->prefix, ps->othertrue, PERCENT (ps->othertrue, ps->visits));
+   fprintf (ps->out,
+           "%s%llu other true in binary clauses (%.1f%%)"
+       ", %llu upper (%.1f%%)\n",
+           ps->prefix, ps->othertrue2, PERCENT (ps->othertrue2, ps->othertrue),
+       ps->othertrue2u, PERCENT (ps->othertrue2u, ps->othertrue2));
+   fprintf (ps->out,
+           "%s%llu other true in large clauses (%.1f%%)"
+       ", %llu upper (%.1f%%)\n",
+           ps->prefix, ps->othertruel, PERCENT (ps->othertruel, ps->othertrue),
+       ps->othertruelu, PERCENT (ps->othertruelu, ps->othertruel));
+   fprintf (ps->out, "%s%llu ternary and large traversals (%.1f per visit)\n",
+       ps->prefix, ps->traversals, AVERAGE (ps->traversals, ps->visits));
+   fprintf (ps->out, "%s%llu large traversals (%.1f per large visit)\n",
+       ps->prefix, ps->ltraversals, AVERAGE (ps->ltraversals, ps->lvisits));
+   fprintf (ps->out, "%s%llu assignments\n", ps->prefix, ps->assignments);
+#else
+   fprintf (ps->out, "%s%llu propagations\n", ps->prefix, picosat_propagations (ps));
+   fprintf (ps->out, "%s%llu visits\n", ps->prefix, picosat_visits (ps));
+#endif
+   fprintf (ps->out, "%s%.1f%% variables used\n", ps->prefix, PERCENT (ps->vused, ps->max_var));
+
+  sflush (ps);
+   fprintf (ps->out, "%s%.1f seconds in library\n", ps->prefix, ps->seconds);
+   fprintf (ps->out, "%s%.1f megaprops/second\n",
+       ps->prefix, AVERAGE (ps->propagations / 1e6f, ps->seconds));
+   fprintf (ps->out, "%s%.1f megavisits/second\n",
+       ps->prefix, AVERAGE (ps->visits / 1e6f, ps->seconds));
+   fprintf (ps->out, "%sprobing %.1f seconds %.0f%%\n",
+           ps->prefix, ps->flseconds, PERCENT (ps->flseconds, ps->seconds));
+#ifdef STATS
+   fprintf (ps->out,
+       "%srecycled %.1f MB in %u reductions\n",
+       ps->prefix, ps->rrecycled / (double) (1 << 20), ps->reductions);
+   fprintf (ps->out,
+       "%srecycled %.1f MB in %u simplifications\n",
+       ps->prefix, ps->srecycled / (double) (1 << 20), ps->simps);
+#else
+   fprintf (ps->out, "%s%u simplifications\n", ps->prefix, ps->simps);
+   fprintf (ps->out, "%s%u reductions\n", ps->prefix, ps->reductions);
+   fprintf (ps->out, "%s%.1f MB recycled\n", ps->prefix, ps->recycled / (double) (1 << 20));
+#endif
+   fprintf (ps->out, "%s%.1f MB maximally allocated\n",
+        ps->prefix, picosat_max_bytes_allocated (ps) / (double) (1 << 20));
+}
+
+#ifndef NGETRUSAGE
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/unistd.h>
+#endif
+
+double
+picosat_time_stamp (void)
+{
+  double res = -1;
+#ifndef NGETRUSAGE
+  struct rusage u;
+  res = 0;
+  if (!getrusage (RUSAGE_SELF, &u))
+    {
+      res += u.ru_utime.tv_sec + 1e-6 * u.ru_utime.tv_usec;
+      res += u.ru_stime.tv_sec + 1e-6 * u.ru_stime.tv_usec;
+    }
+#endif
+  return res;
+}
+
+double
+picosat_seconds (PS * ps)
+{
+  check_ready (ps);
+  return ps->seconds;
+}
+
+void
+picosat_print (PS * ps, FILE * file)
+{
+#ifdef NO_BINARY_CLAUSES
+  Lit * lit, *other, * last;
+  Ltk * stack;
+#endif
+  Lit **q, **eol;
+  Cls **p, *c;
+  unsigned n;
+
+  if (ps->measurealltimeinlib)
+    enter (ps);
+  else
+    check_ready (ps);
+
+  n = 0;
+  n +=  ps->alshead - ps->als;
+
+  for (p = SOC; p != EOC; p = NXC (p))
+    {
+      c = *p;
+
+      if (!c)
+    continue;
+
+#ifdef TRACE
+      if (c->collected)
+    continue;
+#endif
+      n++;
+    }
+
+#ifdef NO_BINARY_CLAUSES
+  last = int2lit (ps, -ps->max_var);
+  for (lit = int2lit (ps, 1); lit <= last; lit++)
+    {
+      stack = LIT2IMPLS (lit);
+      eol = stack->start + stack->count;
+      for (q = stack->start; q < eol; q++)
+    if (*q >= lit)
+      n++;
+    }
+#endif
+
+  fprintf (file, "p cnf %d %u\n", ps->max_var, n);
+
+  for (p = SOC; p != EOC; p = NXC (p))
+    {
+      c = *p;
+      if (!c)
+    continue;
+
+#ifdef TRACE
+      if (c->collected)
+    continue;
+#endif
+
+      eol = end_of_lits (c);
+      for (q = c->lits; q < eol; q++)
+    fprintf (file, "%d ", LIT2INT (*q));
+
+      fputs ("0\n", file);
+    }
+
+#ifdef NO_BINARY_CLAUSES
+  last = int2lit (ps, -ps->max_var);
+  for (lit = int2lit (ps, 1); lit <= last; lit++)
+    {
+      stack = LIT2IMPLS (lit);
+      eol = stack->start + stack->count;
+      for (q = stack->start; q < eol; q++)
+    if ((other = *q) >= lit)
+      fprintf (file, "%d %d 0\n", LIT2INT (lit), LIT2INT (other));
+    }
+#endif
+
+  {
+    Lit **r;
+    for (r = ps->als; r < ps->alshead; r++)
+      fprintf (file, "%d 0\n", LIT2INT (*r));
+  }
+
+  fflush (file);
+
+  if (ps->measurealltimeinlib)
+    leave (ps);
+}
+
+void
+picosat_enter (PS * ps)
+{
+  enter (ps);
+}
+
+void
+picosat_leave (PS * ps)
+{
+  leave (ps);
+}
+
+void
+picosat_message (PS * ps, int vlevel, const char * fmt, ...)
+{
+  va_list ap;
+
+  if (vlevel > ps->verbosity)
+    return;
+
+  fputs (ps->prefix, ps->out);
+  va_start (ap, fmt);
+  vfprintf (ps->out, fmt, ap);
+  va_end (ap);
+  fputc ('\n', ps->out);
+}
+
+int
+picosat_changed (PS * ps)
+{
+  int res;
+
+  check_ready (ps);
+  check_sat_state (ps);
+
+  res = (ps->min_flipped <= ps->saved_max_var);
+  assert (!res || ps->saved_flips != ps->flips);
+
+  return res;
+}
+
+void
+picosat_reset_phases (PS * ps)
+{
+  rebias (ps);
+}
+
+void
+picosat_reset_scores (PS * ps)
+{
+  Rnk * r;
+  ps->hhead = ps->heap + 1;
+  for (r = ps->rnks + 1; r <= ps->rnks + ps->max_var; r++)
+    {
+      CLR (r);
+      hpush (ps, r);
+    }
+}
+
+void
+picosat_remove_learned (PS * ps, unsigned percentage)
+{
+  enter (ps);
+  reset_incremental_usage (ps);
+  reduce (ps, percentage);
+  leave (ps);
+}
+
+void
+picosat_set_global_default_phase (PS * ps, int phase)
+{
+  check_ready (ps);
+  ABORTIF (phase < 0, "API usage: 'picosat_set_global_default_phase' "
+                      "with negative argument");
+  ABORTIF (phase > 3, "API usage: 'picosat_set_global_default_phase' "
+                      "with argument > 3");
+  ps->defaultphase = phase;
+}
+
+void
+picosat_set_default_phase_lit (PS * ps, int int_lit, int phase)
+{
+  unsigned newphase;
+  Lit * lit;
+  Var * v;
+
+  check_ready (ps);
+
+  lit = import_lit (ps, int_lit, 1);
+  v = LIT2VAR (lit);
+
+  if (phase)
+    {
+      newphase = (int_lit < 0) == (phase < 0);
+      v->defphase = v->phase = newphase;
+      v->usedefphase = v->assigned = 1;
+    }
+  else
+    {
+      v->usedefphase = v->assigned = 0;
+    }
+}
+
+void
+picosat_set_more_important_lit (PS * ps, int int_lit)
+{
+  Lit * lit;
+  Var * v;
+  Rnk * r;
+
+  check_ready (ps);
+
+  lit = import_lit (ps, int_lit, 1);
+  v = LIT2VAR (lit);
+  r = VAR2RNK (v);
+
+  ABORTIF (r->lessimportant, "can not mark variable more and less important");
+
+  if (r->moreimportant)
+    return;
+
+  r->moreimportant = 1;
+
+  if (r->pos)
+    hup (ps, r);
+}
+
+void
+picosat_set_less_important_lit (PS * ps, int int_lit)
+{
+  Lit * lit;
+  Var * v;
+  Rnk * r;
+
+  check_ready (ps);
+
+  lit = import_lit (ps, int_lit, 1);
+  v = LIT2VAR (lit);
+  r = VAR2RNK (v);
+
+  ABORTIF (r->moreimportant, "can not mark variable more and less important");
+
+  if (r->lessimportant)
+    return;
+
+  r->lessimportant = 1;
+
+  if (r->pos)
+    hdown (ps, r);
+}
+
+#ifndef NADC
+
+unsigned
+picosat_ado_conflicts (PS * ps)
+{
+  check_ready (ps);
+  return ps->adoconflicts;
+}
+
+void
+picosat_disable_ado (PS * ps)
+{
+  check_ready (ps);
+  assert (!ps->adodisabled);
+  ps->adodisabled = 1;
+}
+
+void
+picosat_enable_ado (PS * ps)
+{
+  check_ready (ps);
+  assert (ps->adodisabled);
+  ps->adodisabled = 0;
+}
+
+void
+picosat_set_ado_conflict_limit (PS * ps, unsigned newadoconflictlimit)
+{
+  check_ready (ps);
+  ps->adoconflictlimit = newadoconflictlimit;
+}
+
+#endif
+
+void
+picosat_simplify (PS * ps)
+{
+  enter (ps);
+  reset_incremental_usage (ps);
+  simplify (ps, 1);
+  leave (ps);
+}
+
+int
+picosat_haveados (void)
+{
+#ifndef NADC
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+void
+picosat_save_original_clauses (PS * ps)
+{
+  if (ps->saveorig) return;
+  ABORTIF (ps->oadded, "API usage: 'picosat_save_original_clauses' too late");
+  ps->saveorig = 1;
+}
+
+void picosat_set_interrupt (PicoSAT * ps,
+                            void * external_state,
+                int (*interrupted)(void * external_state))
+{
+  ps->interrupt.state = external_state;
+  ps->interrupt.function = interrupted;
+}
+
+int
+picosat_deref_partial (PS * ps, int int_lit)
+{
+  check_ready (ps);
+  check_sat_state (ps);
+  ABORTIF (!int_lit, "API usage: can not partial deref zero literal");
+  ABORTIF (ps->mtcls, "API usage: deref partial after empty clause generated");
+  ABORTIF (!ps->saveorig, "API usage: 'picosat_save_original_clauses' missing");
+
+#ifdef STATS
+  ps->derefs++;
+#endif
+
+  if (!ps->partial)
+    minautarky (ps);
+
+  return pderef (ps, int_lit);
+}
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 05/12] Add definitions
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
                   ` (3 preceding siblings ...)
  2021-10-20  9:38 ` [RFC 04/12] Add picosat.c (3/3) Thorsten Berger
@ 2021-10-20  9:40 ` Thorsten Berger
  2021-10-20  9:41 ` [RFC 06/12] Add files for building constraints Thorsten Berger
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:40 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/Makefile  |  19 +++-
 scripts/kconfig/cf_defs.h | 233 ++++++++++++++++++++++++++++++++++++++
 scripts/kconfig/expr.h    |  13 +++
 3 files changed, 262 insertions(+), 3 deletions(-)
 create mode 100644 scripts/kconfig/cf_defs.h

diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 5a215880b268..75caf1b755b0 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -35,6 +35,8 @@ menuconfig-prog    := mconf
 nconfig-prog    := nconf
 gconfig-prog    := gconf
 xconfig-prog    := qconf
+cfconfig-prog    := cfconfig
+cfoutconfig-prog := cfoutconfig
 
 define config_rule
 PHONY += $(1)
@@ -45,7 +47,8 @@ PHONY += build_$(1)
 build_$(1): $(obj)/$($(1)-prog)
 endef
 
-$(foreach c, config menuconfig nconfig gconfig xconfig, $(eval $(call config_rule,$(c))))
+$(foreach c, config menuconfig nconfig gconfig xconfig cfconfig \
+cfoutconfig, $(eval $(call config_rule,$(c))))
 
 PHONY += localmodconfig localyesconfig
 localyesconfig localmodconfig: $(obj)/conf
@@ -140,6 +143,8 @@ help:
     @echo  '                    default value without prompting'
     @echo  '  tinyconfig      - Configure the tiniest possible kernel'
     @echo  '  testconfig      - Run Kconfig unit tests (requires python3 and pytest)'
+    @echo  '  cfconfig        - CLI tool for debugging ConfigFix'
+    @echo  '  cfoutconfig     - Print constraints and DIMACS-output into files'
 
 # ===========================================================================
 # object files used by all kconfig flavours
@@ -176,12 +181,20 @@ $(foreach f, mconf.o $(lxdialog), \
 
 $(addprefix $(obj)/, mconf.o $(lxdialog)): $(obj)/mconf-cfg
 
+# configfix: Used for the xconfig target as well as for its debugging tools
+hostprogs        += cfconfig cfoutconfig
+cfconf-objs      := configfix.o cf_constraints.o cf_expr.o cf_rangefix.o cf_satutils.o cf_utils.o picosat.o
+cfconfig-objs    := cfconfig.o $(cfconf-objs) $(common-objs)
+cfoutconfig-objs := cfoutconfig.o $(cfconf-objs) $(common-objs)
+
+HOSTCFLAGS_picosat.o = -DTRACE -Wno-missing-prototypes -Wno-pointer-compare
+
 # qconf: Used for the xconfig target based on Qt
 hostprogs    += qconf
 qconf-cxxobjs    := qconf.o qconf-moc.o
-qconf-objs    := images.o $(common-objs)
+qconf-objs    := images.o $(common-objs) $(cfconf-objs)
 
-HOSTLDLIBS_qconf    = $(shell . $(obj)/qconf-cfg && echo $$libs)
+HOSTLDLIBS_qconf    = $(shell . $(obj)/qconf-cfg && echo $$libs && echo -lpthread)
 HOSTCXXFLAGS_qconf.o    = $(shell . $(obj)/qconf-cfg && echo $$cflags)
 HOSTCXXFLAGS_qconf-moc.o = $(shell . $(obj)/qconf-cfg && echo $$cflags)
 
diff --git a/scripts/kconfig/cf_defs.h b/scripts/kconfig/cf_defs.h
new file mode 100644
index 000000000000..342327a31dc2
--- /dev/null
+++ b/scripts/kconfig/cf_defs.h
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#ifndef DEFS_H
+#define DEFS_H
+
+/* external variables */
+extern unsigned int sat_variable_nr;
+extern unsigned int tmp_variable_nr;
+extern struct fexpr *satmap; // map SAT variables to fexpr
+extern size_t satmap_size;
+
+extern struct sdv_list *sdv_symbols; /* array with conflict-symbols */
+extern bool CFDEBUG;
+extern bool stop_rangefix;
+extern struct fexpr *const_false;
+extern struct fexpr *const_true;
+extern struct fexpr *symbol_yes_fexpr;
+extern struct fexpr *symbol_mod_fexpr;
+extern struct fexpr *symbol_no_fexpr;
+
+#define printd(fmt...) if (CFDEBUG) printf(fmt)
+
+/* different types for f_expr */
+enum fexpr_type {
+    FE_SYMBOL,
+    FE_NPC, /* no prompt condition */
+    FE_TRUE,  /* constant of value True */
+    FE_FALSE,  /* constant of value False */
+    FE_NONBOOL,  /* for all non-(boolean/tristate) known values */
+    FE_CHOICE, /* symbols of type choice */
+    FE_SELECT, /* auxiliary variable for selected symbols */
+    FE_TMPSATVAR /* temporary sat-variable (Tseytin) */
+};
+
+/* struct for a propositional logic formula */
+struct fexpr {
+    /* name of the feature expr */
+    struct gstr name;
+
+    /* associated symbol */
+    struct symbol *sym;
+
+    /* integer value for the SAT solver */
+    int satval;
+
+    /* assumption in the last call to PicoSAT */
+    bool assumption;
+
+    /* type of the fexpr */
+    enum fexpr_type type;
+
+    union {
+        /* symbol */
+        struct {
+            tristate tri;
+        };
+        /* AND, OR, NOT */
+        struct {
+            struct fexpr *left;
+            struct fexpr *right; /* not used for NOT */
+        };
+        /* EQUALS */
+        struct {
+            struct symbol *eqsym;
+            struct symbol *eqvalue;
+        };
+        /* HEX, INTEGER, STRING */
+        struct {
+            struct gstr nb_val;
+        };
+    };
+
+};
+
+struct fexpr_list {
+    struct fexpr_node *head, *tail;
+    unsigned int size;
+};
+
+struct fexpr_node {
+    struct fexpr *elem;
+    struct fexpr_node *next, *prev;
+};
+
+struct fexl_list {
+    struct fexl_node *head, *tail;
+    unsigned int size;
+};
+
+struct fexl_node {
+    struct fexpr_list *elem;
+    struct fexl_node *next, *prev;
+};
+
+enum pexpr_type {
+    PE_SYMBOL,
+    PE_AND,
+    PE_OR,
+    PE_NOT
+};
+
+union pexpr_data {
+    struct pexpr *pexpr;
+    struct fexpr *fexpr;
+};
+
+struct pexpr {
+    enum pexpr_type type;
+    union pexpr_data left, right;
+};
+
+struct pexpr_list {
+    struct pexpr_node *head, *tail;
+    unsigned int size;
+};
+
+struct pexpr_node {
+    struct pexpr *elem;
+    struct pexpr_node *next, *prev;
+};
+
+struct default_map {
+    struct fexpr *val;
+
+    struct pexpr *e;
+};
+
+struct defm_list {
+    struct defm_node *head, *tail;
+    unsigned int size;
+};
+
+struct defm_node {
+    struct default_map *elem;
+    struct defm_node *next, *prev;
+};
+
+enum symboldv_type {
+    SDV_BOOLEAN,    /* boolean/tristate */
+    SDV_NONBOOLEAN    /* string/int/hex */
+};
+
+struct symbol_dvalue {
+    struct symbol *sym;
+
+    enum symboldv_type type;
+
+    union {
+        /* boolean/tristate */
+        tristate tri;
+
+        /* string/int/hex */
+        struct gstr nb_val;
+    };
+};
+
+struct sdv_list {
+    struct sdv_node *head, *tail;
+    unsigned int size;
+};
+
+struct sdv_node {
+    struct symbol_dvalue *elem;
+    struct sdv_node *next, *prev;
+};
+
+enum symbolfix_type {
+    SF_BOOLEAN,    /* boolean/tristate */
+    SF_NONBOOLEAN,    /* string/int/hex */
+    SF_DISALLOWED    /* disallowed non-boolean values */
+};
+
+struct symbol_fix {
+    struct symbol *sym;
+
+    enum symbolfix_type type;
+
+    union {
+        /* boolean/tristate */
+        tristate tri;
+
+        /* string/int/hex */
+        struct gstr nb_val;
+
+        /* disallowed non-boolean values */
+        struct gstr disallowed;
+    };
+};
+
+struct sfix_list {
+    struct sfix_node *head, *tail;
+    unsigned int size;
+};
+
+struct sfix_node {
+    struct symbol_fix *elem;
+    struct sfix_node *next, *prev;
+};
+
+struct sfl_list {
+    struct sfl_node *head, *tail;
+    unsigned int size;
+};
+
+struct sfl_node {
+    struct sfix_list *elem;
+    struct sfl_node *next, *prev;
+};
+
+struct sym_list {
+    struct sym_node *head, *tail;
+    unsigned int size;
+};
+
+struct sym_node {
+    struct symbol *elem;
+    struct sym_node *next, *prev;
+};
+
+struct prop_list {
+    struct prop_node *head, *tail;
+    unsigned int size;
+};
+
+struct prop_node {
+    struct property *elem;
+    struct prop_node *next, *prev;
+};
+
+#endif
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 9c9caca5bd5f..9c5327dd6be8 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -129,6 +129,19 @@ struct symbol {
      * "Weak" reverse dependencies through being implied by other symbols
      */
     struct expr_value implied;
+
+    /*
+     * ConfigFix
+     */
+    struct fexpr *fexpr_y;
+    struct fexpr *fexpr_m;
+    struct fexpr *fexpr_sel_y;
+    struct fexpr *fexpr_sel_m;
+    struct pexpr *list_sel_y;
+    struct pexpr *list_sel_m;
+    struct fexpr *noPromptCond;
+    struct fexpr_list *nb_vals; /* used for non-booleans */
+    struct pexpr_list *constraints; /* list of constraints for symbol */
 };
 
 #define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next)
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 06/12] Add files for building constraints
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
                   ` (4 preceding siblings ...)
  2021-10-20  9:40 ` [RFC 05/12] Add definitions Thorsten Berger
@ 2021-10-20  9:41 ` Thorsten Berger
  2021-10-20  9:43 ` [RFC 07/12] Add files for handling expressions Thorsten Berger
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:41 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/cf_constraints.c | 1219 ++++++++++++++++++++++++++++++
 scripts/kconfig/cf_constraints.h |   23 +
 2 files changed, 1242 insertions(+)
 create mode 100644 scripts/kconfig/cf_constraints.c
 create mode 100644 scripts/kconfig/cf_constraints.h

diff --git a/scripts/kconfig/cf_constraints.c b/scripts/kconfig/cf_constraints.c
new file mode 100644
index 000000000000..d1f3b2bd9945
--- /dev/null
+++ b/scripts/kconfig/cf_constraints.c
@@ -0,0 +1,1219 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "configfix.h"
+
+#define KCR_CMP false
+#define NPC_OPTIMISATION true
+
+static void init_constraints(void);
+static void get_constraints_bool(void);
+static void get_constraints_select(void);
+static void get_constraints_nonbool(void);
+
+static void build_tristate_constraint_clause(struct symbol *sym);
+
+static void add_selects_kcr(struct symbol *sym);
+static void add_selects(struct symbol *sym);
+
+static void add_dependencies_bool(struct symbol* sym);
+static void add_dependencies_bool_kcr(struct symbol* sym);
+static void add_dependencies_nonbool(struct symbol *sym);
+
+static void add_choice_prompt_cond(struct symbol *sym);
+static void add_choice_dependencies(struct symbol *sym);
+static void add_choice_constraints(struct symbol *sym);
+static void add_invisible_constraints(struct symbol *sym);
+static void sym_nonbool_at_least_1(struct symbol *sym);
+static void sym_nonbool_at_most_1(struct symbol *sym);
+static void sym_add_nonbool_values_from_default_range(struct symbol *sym);
+static void sym_add_range_constraints(struct symbol *sym);
+static void sym_add_nonbool_prompt_constraint(struct symbol *sym);
+
+static struct default_map * create_default_map_entry(struct fexpr *val, struct pexpr *e);
+static struct defm_list * get_defaults(struct symbol *sym);
+static struct pexpr * get_default_y(struct defm_list *list);
+static struct pexpr * get_default_m(struct defm_list *list);
+static struct pexpr *get_default_any(struct symbol *sym);
+static long sym_get_range_val(struct symbol *sym, int base);
+
+/* -------------------------------------- */
+
+/*
+ * build the constraints for each symbol
+ */
+void get_constraints(void)
+{
+    printd("Building constraints...");
+
+    init_constraints();
+    get_constraints_bool();
+    get_constraints_select();
+    get_constraints_nonbool();
+}
+
+/*
+ * need to go through the constraints once to find all "known values"
+ * for the non-Boolean symbols
+ */
+static void init_constraints(void)
+{
+    unsigned int i;
+    struct symbol *sym;
+    struct property *p;
+    for_all_symbols(i, sym) {
+        if (sym->type == S_UNKNOWN)
+            continue;
+
+        if (sym_is_boolean(sym)) {
+            for_all_properties(sym, p, P_SELECT)
+                expr_calculate_pexpr_both(p->visible.expr);
+
+            for_all_properties(sym, p, P_IMPLY)
+                expr_calculate_pexpr_both(p->visible.expr);
+        }
+
+        if (sym->dir_dep.expr)
+            expr_calculate_pexpr_both(sym->dir_dep.expr);
+
+        struct property *prompt = sym_get_prompt(sym);
+        if (prompt != NULL && prompt->visible.expr) {
+            expr_calculate_pexpr_both(prompt->visible.expr);
+            get_defaults(sym);
+        }
+
+        if (sym_is_nonboolean(sym)) {
+            for_all_defaults(sym, p) {
+                if (p == NULL)
+                    continue;
+
+                sym_create_nonbool_fexpr(sym, p->expr->left.sym->name);
+            }
+            for_all_properties(sym, p, P_RANGE) {
+                if (p == NULL)
+                    continue;
+
+                sym_create_nonbool_fexpr(sym, p->expr->left.sym->name);
+                sym_create_nonbool_fexpr(sym, p->expr->right.sym->name);
+            }
+            const char *curr = sym_get_string_value(sym);
+            if (strcmp(curr, "") != 0)
+                sym_create_nonbool_fexpr(sym, (char *) curr);
+        }
+
+        if (sym->type == S_HEX || sym->type == S_INT)
+            sym_add_nonbool_values_from_default_range(sym);
+    }
+}
+
+
+/*
+ *  build constraints for boolean symbols
+ */
+static void get_constraints_bool(void)
+{
+    unsigned int i;
+    struct symbol *sym;
+    for_all_symbols(i, sym) {
+
+        if (!sym_is_boolean(sym))
+            continue;
+
+        /* build tristate constraints */
+        if (sym->type == S_TRISTATE)
+            build_tristate_constraint_clause(sym);
+
+        /* build constraints for select statements
+         * need to treat choice symbols seperately */
+        if (!KCR_CMP) {
+            add_selects(sym);
+        } else {
+            if (sym->rev_dep.expr && !sym_is_choice(sym) && !sym_is_choice_value(sym))
+                add_selects_kcr(sym);
+        }
+
+        /* build constraints for dependencies for booleans */
+        if (sym->dir_dep.expr && !sym_is_choice(sym) && !sym_is_choice_value(sym)) {
+            if (!KCR_CMP)
+                add_dependencies_bool(sym);
+            else
+                add_dependencies_bool_kcr(sym);
+        }
+
+        /* build constraints for choice prompts */
+        if (sym_is_choice(sym))
+            add_choice_prompt_cond(sym);
+
+        /* build constraints for dependencies (choice symbols and options) */
+        if (sym_is_choice(sym) || sym_is_choice_value(sym))
+            add_choice_dependencies(sym);
+
+        /* build constraints for the choice groups */
+        if (sym_is_choice(sym))
+            add_choice_constraints(sym);
+
+
+        /* build invisible constraints */
+        add_invisible_constraints(sym);
+    }
+}
+
+/*
+* build the constraints for select-variables
+* skip non-Booleans, choice symbols/options och symbols without rev_dir
+*/
+static void get_constraints_select(void)
+{
+    unsigned int i;
+    struct symbol *sym;
+    for_all_symbols(i, sym) {
+        if (KCR_CMP)
+            continue;
+
+        if (!sym_is_boolean(sym))
+            continue;
+
+        if (sym_is_choice(sym) || sym_is_choice_value(sym))
+            continue;
+
+        if (!sym->rev_dep.expr)
+            continue;
+
+        if (sym->list_sel_y == NULL)
+            continue;
+
+        struct pexpr *sel_y = pexpr_implies(
+                    pexf(sym->fexpr_sel_y),
+                    pexf(sym->fexpr_y));
+        sym_add_constraint(sym, sel_y);
+
+        struct pexpr *c1 = pexpr_implies(
+                    pexf(sym->fexpr_sel_y),
+                    sym->list_sel_y);
+        sym_add_constraint(sym, c1);
+
+        /* only continue for tristates */
+        if (sym->type == S_BOOLEAN)
+            continue;
+
+        struct pexpr *sel_m = pexpr_implies(
+                    pexf(sym->fexpr_sel_m),
+                    sym_get_fexpr_both(sym));
+        sym_add_constraint(sym, sel_m);
+
+        struct pexpr *c2 = pexpr_implies(
+                    pexf(sym->fexpr_sel_m),
+                    sym->list_sel_m);
+        sym_add_constraint(sym, c2);
+    }
+}
+
+/*
+ * build constraints for non-booleans
+ */
+static void get_constraints_nonbool(void)
+{
+    unsigned int i;
+    struct symbol *sym;
+    for_all_symbols(i, sym) {
+
+        if (!sym_is_nonboolean(sym))
+            continue;
+
+        /* the symbol must have a value, if there is a prompt */
+        if (sym_has_prompt(sym))
+            sym_add_nonbool_prompt_constraint(sym);
+
+        /* build the range constraints for int/hex */
+        if (sym->type == S_HEX || sym->type == S_INT)
+            sym_add_range_constraints(sym);
+
+        /* build constraints for dependencies for non-booleans */
+        if (sym->dir_dep.expr)
+            add_dependencies_nonbool(sym);
+
+        /* build invisible constraints */
+        add_invisible_constraints(sym);
+
+        /* exactly one of the symbols must be true */
+        sym_nonbool_at_least_1(sym);
+        sym_nonbool_at_most_1(sym);
+    }
+}
+
+/*
+ * enforce tristate constraints
+ */
+static void build_tristate_constraint_clause(struct symbol *sym)
+{
+    if (sym->type != S_TRISTATE)
+        return;
+
+    struct pexpr *X = pexf(sym->fexpr_y), *X_m = pexf(sym->fexpr_m), *modules = pexf(modules_sym->fexpr_y);
+
+    /* -X v -X_m */
+    struct pexpr *c = pexpr_or(pexpr_not(X), pexpr_not(X_m));
+    sym_add_constraint(sym, c);
+
+    /* X_m -> MODULES */
+    if (modules_sym->fexpr_y != NULL) {
+        struct pexpr *c2 = pexpr_implies(X_m, modules);
+        sym_add_constraint(sym, c2);
+    }
+}
+
+/*
+ * build the select constraints
+ * - RDep(X) implies X
+ */
+static void add_selects_kcr(struct symbol *sym)
+{
+    struct pexpr *rdep_y = expr_calculate_pexpr_y(sym->rev_dep.expr);
+    struct pexpr *c1 = pexpr_implies(rdep_y, pexf(sym->fexpr_y));
+    sym_add_constraint(sym, c1);
+
+    struct pexpr *rdep_both = expr_calculate_pexpr_both(sym->rev_dep.expr);
+    struct pexpr *c2 = pexpr_implies(rdep_both, sym_get_fexpr_both(sym));
+    sym_add_constraint(sym, c2);
+}
+
+/*
+ * build the select constraints simplified
+ * - RDep(X) implies X
+ */
+static void add_selects(struct symbol *sym)
+{
+    if (!sym_is_boolean(sym))
+        return;
+
+    struct property *p;
+    for_all_properties(sym, p, P_SELECT) {
+        struct symbol *selected = p->expr->left.sym;
+
+        if (selected->type == S_UNKNOWN)
+            continue;
+
+        if (!selected->rev_dep.expr)
+            continue;
+
+        struct pexpr *cond_y = pexf(const_true);
+        struct pexpr *cond_both = pexf(const_true);
+        if (p->visible.expr) {
+            cond_y = expr_calculate_pexpr_y(p->visible.expr);
+            cond_both = expr_calculate_pexpr_both(p->visible.expr);
+        }
+
+        if (selected->type == S_BOOLEAN) {
+            /* imply that symbol is selected to y */
+            struct pexpr *e1 = pexpr_and(cond_both, sym_get_fexpr_both(sym));
+            struct pexpr *c1 = pexpr_implies(e1, pexf(selected->fexpr_sel_y));
+            sym_add_constraint(selected, c1);
+
+            if (selected->list_sel_y == NULL)
+                selected->list_sel_y = e1;
+            else
+                selected->list_sel_y = pexpr_or(selected->list_sel_y, e1);
+        }
+
+        if (selected->type == S_TRISTATE) {
+            /* imply that symbol is selected to y */
+            struct pexpr *e2 = pexpr_and(cond_y, pexf(sym->fexpr_y));
+            struct pexpr *c2 = pexpr_implies(e2, pexf(selected->fexpr_sel_y));
+            sym_add_constraint(selected, c2);
+
+            if (selected->list_sel_y == NULL)
+                selected->list_sel_y = e2;
+            else
+                selected->list_sel_y = pexpr_or(selected->list_sel_y, e2);
+
+            /* imply that symbol is selected to m */
+            struct pexpr *e3 = pexpr_and(cond_both, sym_get_fexpr_both(sym));
+            struct pexpr *c3 = pexpr_implies(e3, pexf(selected->fexpr_sel_m));
+            sym_add_constraint(selected, c3);
+
+            if (selected->list_sel_m == NULL)
+                selected->list_sel_m = e3;
+            else
+                selected->list_sel_m = pexpr_or(selected->list_sel_m, e3);
+        }
+    }
+}
+
+/*
+ * build the dependency constraints for booleans
+ *  - X implies Dep(X) or RDep(X)
+ */
+static void add_dependencies_bool(struct symbol *sym)
+{
+    if (!sym_is_boolean(sym) || !sym->dir_dep.expr)
+        return;
+
+    struct pexpr *dep_both = expr_calculate_pexpr_both(sym->dir_dep.expr);
+
+    if (sym->type == S_TRISTATE) {
+        struct pexpr *dep_y = expr_calculate_pexpr_y(sym->dir_dep.expr);
+        struct pexpr *sel_y = sym->rev_dep.expr ? pexf(sym->fexpr_sel_y) : pexf(const_false);
+
+        struct pexpr *c1 = pexpr_implies(pexf(sym->fexpr_y), pexpr_or(dep_y, sel_y));
+
+        sym_add_constraint(sym, c1);
+
+        struct pexpr *c2 = pexpr_implies(pexf(sym->fexpr_m), pexpr_or(dep_both, sym_get_fexpr_sel_both(sym)));
+
+        sym_add_constraint(sym, c2);
+    } else if (sym->type == S_BOOLEAN) {
+        struct pexpr *c = pexpr_implies(pexf(sym->fexpr_y), pexpr_or(dep_both, sym_get_fexpr_sel_both(sym)));
+        sym_add_constraint(sym, c);
+    }
+}
+
+/*
+ * build the dependency constraints for booleans (KCR)
+ *  - X implies Dep(X) or RDep(X)
+ */
+static void add_dependencies_bool_kcr(struct symbol *sym)
+{
+    if (!sym_is_boolean(sym) || !sym->dir_dep.expr)
+        return;
+
+    struct pexpr *dep_both = expr_calculate_pexpr_both(sym->dir_dep.expr);
+
+    struct pexpr *sel_both = sym->rev_dep.expr ? expr_calculate_pexpr_both(sym->rev_dep.expr) : pexf(const_false);
+
+    if (sym->type == S_TRISTATE) {
+        struct pexpr *dep_y = expr_calculate_pexpr_y(sym->dir_dep.expr);
+        struct pexpr *sel_y = sym->rev_dep.expr ? expr_calculate_pexpr_y(sym->rev_dep.expr) : pexf(const_false);
+        struct pexpr *c1 = pexpr_implies(pexf(sym->fexpr_y), pexpr_or(dep_y, sel_y));
+        sym_add_constraint(sym, c1);
+
+        struct pexpr *c2 = pexpr_implies(pexf(sym->fexpr_m), pexpr_or(dep_both, sel_both));
+        sym_add_constraint(sym, c2);
+    } else if (sym->type == S_BOOLEAN) {
+        struct pexpr *c = pexpr_implies(pexf(sym->fexpr_y), pexpr_or(dep_both, sel_both));
+        sym_add_constraint(sym, c);
+    }
+}
+
+/*
+ * build the dependency constraints for non-booleans
+ * X_i implies Dep(X)
+ */
+static void add_dependencies_nonbool(struct symbol *sym)
+{
+    if (!sym_is_nonboolean(sym) || !sym->dir_dep.expr || sym->rev_dep.expr)
+        return;
+
+    struct pexpr *dep_both = expr_calculate_pexpr_both(sym->dir_dep.expr);
+
+    struct pexpr *nb_vals = pexf(const_false);
+    struct fexpr_node *node;
+    /* can skip the first non-boolean value, since this is 'n' */
+    fexpr_list_for_each(node, sym->nb_vals) {
+        if (node->prev == NULL)
+            continue;
+
+        nb_vals = pexpr_or(nb_vals, pexf(node->elem));
+    }
+
+    struct pexpr *c = pexpr_implies(nb_vals, dep_both);
+    sym_add_constraint(sym, c);
+}
+
+/*
+ * build the constraints for the choice prompt
+ */
+static void add_choice_prompt_cond(struct symbol* sym)
+{
+    if (!sym_is_boolean(sym))
+        return;
+
+    struct property *prompt = sym_get_prompt(sym);
+    if (prompt == NULL)
+        return;
+
+    struct pexpr *promptCondition = prompt->visible.expr ? expr_calculate_pexpr_both(prompt->visible.expr) : pexf(const_true);
+
+    struct pexpr *fe_both = sym_get_fexpr_both(sym);
+
+    if (!sym_is_optional(sym)) {
+        struct pexpr *req_cond = pexpr_implies(promptCondition, fe_both);
+        sym_add_constraint(sym, req_cond);
+    }
+
+    struct pexpr *pr_cond = pexpr_implies(fe_both, promptCondition);
+    sym_add_constraint(sym, pr_cond);
+}
+
+/*
+ * build constraints for dependencies (choice symbols and options)
+ */
+static void add_choice_dependencies(struct symbol *sym)
+{
+    if (!sym_is_choice(sym) || !sym_is_choice_value(sym))
+        return;
+
+    struct property *prompt = sym_get_prompt(sym);
+    if (prompt == NULL)
+        return;
+
+    struct expr *to_parse;
+    if (sym_is_choice(sym)) {
+        if (!prompt->visible.expr)
+            return;
+        to_parse = prompt->visible.expr;
+    } else {
+        if (!sym->dir_dep.expr)
+            return;
+        to_parse = sym->dir_dep.expr;
+    }
+
+    struct pexpr *dep_both = expr_calculate_pexpr_both(to_parse);
+
+    if (sym->type == S_TRISTATE) {
+        struct pexpr *dep_y = expr_calculate_pexpr_y(to_parse);
+        struct pexpr *c1 = pexpr_implies(pexf(sym->fexpr_y), dep_y);
+        sym_add_constraint_eq(sym, c1);
+
+        struct pexpr *c2 = pexpr_implies(pexf(sym->fexpr_m), dep_both);
+        sym_add_constraint_eq(sym, c2);
+    } else if (sym->type == S_BOOLEAN) {
+        struct pexpr *c = pexpr_implies(pexf(sym->fexpr_y), dep_both);
+        sym_add_constraint_eq(sym, c);
+    }
+}
+
+/*
+ * build constraints for the choice groups
+ */
+static void add_choice_constraints(struct symbol *sym)
+{
+    if (!sym_is_boolean(sym))
+        return;
+
+    struct property *prompt = sym_get_prompt(sym);
+    if (prompt == NULL)
+        return;
+
+    struct symbol *choice, *choice2;
+    struct sym_node *node, *node2;
+
+    /* create list of all choice options */
+    struct sym_list *items = sym_list_init();
+    /* create list of choice options with a prompt */
+    struct sym_list *promptItems = sym_list_init();
+
+    struct property *prop;
+    for_all_choices(sym, prop) {
+        struct expr *expr;
+        expr_list_for_each_sym(prop->expr, expr, choice) {
+            sym_list_add(items, choice);
+            if (sym_get_prompt(choice) != NULL)
+                sym_list_add(promptItems, choice);
+        }
+    }
+
+    /* if the choice is set to yes, at least one child must be set to yes */
+    struct pexpr *c1 = NULL;
+    sym_list_for_each(node, promptItems) {
+        choice = node->elem;
+        c1 = node->prev == NULL ? pexf(choice->fexpr_y) : pexpr_or(c1, pexf(choice->fexpr_y));
+    }
+    if (c1 != NULL) {
+        struct pexpr *c2 = pexpr_implies(pexf(sym->fexpr_y), c1);
+        sym_add_constraint(sym, c2);
+    }
+
+    /* every choice option (even those without a prompt) implies the choice */
+    sym_list_for_each(node, items) {
+        choice = node->elem;
+        c1 = pexpr_implies(sym_get_fexpr_both(choice), sym_get_fexpr_both(sym));
+        sym_add_constraint(sym, c1);
+    }
+
+    /* choice options can only select mod, if the entire choice is mod */
+    if (sym->type == S_TRISTATE) {
+        sym_list_for_each(node, items) {
+            choice = node->elem;
+            if (choice->type == S_TRISTATE) {
+                c1 = pexpr_implies(pexf(choice->fexpr_m), pexf(sym->fexpr_m));
+                sym_add_constraint(sym, c1);
+            }
+        }
+    }
+
+    /* tristate options cannot be m, if the choice symbol is boolean */
+    if (sym->type == S_BOOLEAN) {
+        sym_list_for_each(node, items) {
+            choice = node->elem;
+            if (choice->type == S_TRISTATE)
+                sym_add_constraint(sym, pexpr_not(pexf(choice->fexpr_m)));
+        }
+    }
+
+    /* all choice options are mutually exclusive for yes */
+    sym_list_for_each(node, promptItems) {
+        choice = node->elem;
+        for (node2 = node->next; node2 != NULL; node2 = node2->next) {
+            choice2 = node2->elem;
+            c1 = pexpr_or(pexpr_not(pexf(choice->fexpr_y)), pexpr_not(pexf(choice2->fexpr_y)));
+            sym_add_constraint(sym, c1);
+        }
+    }
+
+    /* if one choice option with a prompt is set to yes,
+     * then no other option may be set to mod */
+    if (sym->type == S_TRISTATE) {
+        sym_list_for_each(node, promptItems) {
+            choice = node->elem;
+
+            struct sym_list *tmp = sym_list_init();
+            for (node2 = node->next; node2 != NULL; node2 = node2->next) {
+                choice2 = node2->elem;
+                if (choice2->type == S_TRISTATE)
+                    sym_list_add(tmp, choice2);
+            }
+            if (tmp->size == 0) continue;
+
+            sym_list_for_each(node2, tmp) {
+                choice2 = node2->elem;
+                if (node2->prev == NULL)
+                    c1 = pexpr_not(pexf(choice2->fexpr_m));
+                else
+                    c1 = pexpr_and(c1, pexpr_not(pexf(choice2->fexpr_m)));
+            }
+            c1 = pexpr_implies(pexf(choice->fexpr_y), c1);
+            sym_add_constraint(sym, c1);
+        }
+    }
+}
+
+/*
+ * build the constraints for invisible options such as defaults
+ */
+static void add_invisible_constraints(struct symbol *sym)
+{
+    struct property *prompt = sym_get_prompt(sym);
+
+    /* no constraints for the prompt, nothing to do here */
+    if (prompt != NULL && !prompt->visible.expr)
+        return;
+
+    struct pexpr *promptCondition_both, *promptCondition_yes, *noPromptCond;
+    if (prompt == NULL) {
+        promptCondition_both = pexf(const_false);
+        promptCondition_yes = pexf(const_false);
+        noPromptCond = pexf(const_true);
+    } else {
+        promptCondition_both = pexf(const_false);
+        promptCondition_yes = pexf(const_false);
+
+        /* some symbols have multiple prompts */
+        struct property *p;
+        for_all_prompts(sym, p) {
+            promptCondition_both = pexpr_or(promptCondition_both,
+                expr_calculate_pexpr_both(p->visible.expr));
+            promptCondition_yes = pexpr_or(promptCondition_yes,
+                expr_calculate_pexpr_y(p->visible.expr));
+        }
+        noPromptCond = pexpr_not(promptCondition_both);
+    }
+
+    struct pexpr *npc;
+    if (NPC_OPTIMISATION) {
+        struct fexpr * npc_fe = fexpr_create(sat_variable_nr++, FE_NPC, "");
+        if (sym_is_choice(sym))
+            str_append(&npc_fe->name, "Choice_");
+
+        str_append(&npc_fe->name, sym_get_name(sym));
+        str_append(&npc_fe->name, "_NPC");
+        sym->noPromptCond = npc_fe;
+        fexpr_add_to_satmap(npc_fe);
+
+        npc = pexf(npc_fe);
+
+        struct pexpr *c = pexpr_implies(noPromptCond, npc);
+
+        if (!sym_is_choice_value(sym) && !sym_is_choice(sym))
+            sym_add_constraint(sym, c);
+    } else {
+        npc = noPromptCond;
+    }
+
+    struct defm_list *defaults = get_defaults(sym);
+    struct pexpr *default_y = get_default_y(defaults);
+    struct pexpr *default_m = get_default_m(defaults);
+    struct pexpr *default_both = pexpr_or(default_y, default_m);
+
+    /* tristate elements are only selectable as yes, if they are visible as yes */
+    if (sym->type == S_TRISTATE) {
+        struct pexpr *e1 = pexpr_implies(promptCondition_both, pexpr_implies(pexf(sym->fexpr_y), promptCondition_yes));
+        sym_add_constraint(sym, e1);
+    }
+
+    /* if invisible and off by default, then a symbol can only be deactivated by its reverse dependencies */
+    if (sym->type == S_TRISTATE) {
+        struct pexpr *sel_y, *sel_m, *sel_both;
+        if (sym->fexpr_sel_y != NULL) {
+            sel_y = pexpr_implies(pexf(sym->fexpr_y), pexf(sym->fexpr_sel_y));
+            sel_m = pexpr_implies(pexf(sym->fexpr_m), pexf(sym->fexpr_sel_m));
+            sel_both = pexpr_implies(pexf(sym->fexpr_y), pexpr_or(pexf(sym->fexpr_sel_m), pexf(sym->fexpr_sel_y)));
+        } else {
+            sel_y = pexpr_not(pexf(sym->fexpr_y));
+            sel_m = pexpr_not(pexf(sym->fexpr_m));
+            sel_both = sel_y;
+        }
+
+        struct pexpr *c1 = pexpr_implies(pexpr_not(default_y), sel_y);
+        struct pexpr *c2 = pexpr_implies(pexf(modules_sym->fexpr_y), c1);
+        struct pexpr *c3 = pexpr_implies(npc, c2);
+        sym_add_constraint(sym, c3);
+
+        struct pexpr *d1 = pexpr_implies(pexpr_not(default_m), sel_m);
+        struct pexpr *d2 = pexpr_implies(pexf(modules_sym->fexpr_y), d1);
+        struct pexpr *d3 = pexpr_implies(npc, d2);
+        sym_add_constraint(sym, d3);
+
+        struct pexpr *e1 = pexpr_implies(pexpr_not(default_both), sel_both);
+        struct pexpr *e2 = pexpr_implies(pexpr_not(pexf(modules_sym->fexpr_y)), e1);
+        struct pexpr *e3 = pexpr_implies(npc, e2);
+        sym_add_constraint(sym, e3);
+    } else if (sym->type == S_BOOLEAN) {
+        struct pexpr *sel_y;
+        if (sym->fexpr_sel_y != NULL)
+            sel_y = pexpr_implies(pexf(sym->fexpr_y), pexf(sym->fexpr_sel_y)); //sym->fexpr_sel_y;
+        else
+            sel_y = pexpr_not(pexf(sym->fexpr_y));
+
+        struct pexpr *e1 = pexpr_implies(pexpr_not(default_both), sel_y);
+        struct pexpr *e2 = pexpr_implies(npc, e1);
+
+        sym_add_constraint_eq(sym, e2);
+    } else {
+        struct pexpr *default_any = get_default_any(sym);
+        struct pexpr *e1 = pexf(const_true);
+        struct fexpr_node *node;
+        for (node = sym->nb_vals->head->next; node != NULL; node = node->next)
+            e1 = pexpr_and(e1, pexpr_not(pexf(node->elem)));
+
+        struct pexpr *e2 = pexpr_implies(pexpr_not(default_any), e1);
+        struct pexpr *e3 = pexpr_implies(npc, e2);
+
+        sym_add_constraint(sym, e3);
+    }
+
+    /* if invisible and on by default, then a symbol can only be deactivated by its dependencies */
+    if (sym->type == S_TRISTATE) {
+        if (defaults->size == 0)
+            return;
+
+        struct pexpr *e1 = pexpr_implies(npc, pexpr_implies(default_y, pexf(sym->fexpr_y)));
+        sym_add_constraint(sym, e1);
+
+        struct pexpr *e2 = pexpr_implies(npc, pexpr_implies(default_m, sym_get_fexpr_both(sym)));
+        sym_add_constraint(sym, e2);
+    } else if (sym->type == S_BOOLEAN) {
+        if (defaults->size == 0)
+            return;
+
+        struct pexpr *c = pexpr_implies(default_both, pexf(sym->fexpr_y));
+
+        // TODO tristate choice hack
+
+        struct pexpr *c2 = pexpr_implies(npc, c);
+        sym_add_constraint(sym, c2);
+    } else {
+        struct defm_node *node;
+        struct pexpr *cond, *c;
+        struct fexpr *f;
+        defm_list_for_each(node, defaults) {
+            f = node->elem->val;
+            cond = node->elem->e;
+            c = pexpr_implies(npc, pexpr_implies(cond, pexf(f)));
+            sym_add_constraint(sym, c);
+        }
+    }
+}
+
+/*
+ * add the known values from the default and range properties
+ */
+static void sym_add_nonbool_values_from_default_range(struct symbol *sym)
+{
+    struct property *p;
+
+    for_all_defaults(sym, p) {
+        if (p == NULL)
+            continue;
+
+        /* add the value to known values, if it doesn't exist yet */
+        sym_create_nonbool_fexpr(sym, p->expr->left.sym->name);
+    }
+
+    for_all_properties(sym, p, P_RANGE) {
+        if (p == NULL)
+            continue;
+
+        /* add the values to known values, if they don't exist yet */
+        sym_create_nonbool_fexpr(sym, p->expr->left.sym->name);
+        sym_create_nonbool_fexpr(sym, p->expr->right.sym->name);
+    }
+}
+
+/*
+ * build the range constraints for int/hex
+ */
+static void sym_add_range_constraints(struct symbol *sym)
+{
+    struct property *prop;
+    struct pexpr *prevs, *propCond;
+    struct pexpr_list *prevCond = pexpr_list_init();
+    for_all_properties(sym, prop, P_RANGE) {
+        if (prop == NULL)
+            continue;
+
+        prevs = pexf(const_true);
+        propCond = prop_get_condition(prop);
+
+        if (prevCond->size == 0) {
+            prevs = propCond;
+        } else {
+            struct pexpr_node *node;
+            pexpr_list_for_each(node, prevCond)
+                prevs = pexpr_and(pexpr_not(node->elem), prevs);
+
+            prevs = pexpr_and(propCond, prevs);
+        }
+        pexpr_list_add(prevCond, propCond);
+
+        int base;
+        long long range_min, range_max, tmp;
+
+        switch (sym->type) {
+        case S_INT:
+            base = 10;
+            break;
+        case S_HEX:
+            base = 16;
+            break;
+        default:
+            return;
+        }
+
+        range_min = sym_get_range_val(prop->expr->left.sym, base);
+        range_max = sym_get_range_val(prop->expr->right.sym, base);
+
+        /* can skip the first non-boolean value, since this is 'n' */
+        struct fexpr_node *node;
+        fexpr_list_for_each(node, sym->nb_vals) {
+            if (node->prev == NULL)
+                continue;
+
+            tmp = strtoll(str_get(&node->elem->nb_val), NULL, base);
+
+            /* known value is in range, nothing to do here */
+            if (tmp >= range_min && tmp <= range_max)
+                continue;
+
+            struct pexpr *not_nb_val = pexpr_not(pexf(node->elem));
+            if (tmp < range_min) {
+                struct pexpr *c = pexpr_implies(prevs, not_nb_val);
+                sym_add_constraint(sym, c);
+            }
+
+            if (tmp > range_max) {
+                struct pexpr *c = pexpr_implies(prevs, not_nb_val);
+                sym_add_constraint(sym, c);
+            }
+        }
+    }
+}
+
+/*
+ * at least 1 of the known values for a non-boolean symbol must be true
+ */
+static void sym_nonbool_at_least_1(struct symbol *sym)
+{
+    if (!sym_is_nonboolean(sym))
+        return;
+
+    struct pexpr *e = NULL;
+    struct fexpr_node *node;
+    fexpr_list_for_each(node, sym->nb_vals) {
+        if (node->prev == NULL)
+            e = pexf(node->elem);
+        else
+            e = pexpr_or(e, pexf(node->elem));
+    }
+    sym_add_constraint(sym, e);
+}
+
+/*
+ * at most 1 of the known values for a non-boolean symbol can be true
+ */
+static void sym_nonbool_at_most_1(struct symbol *sym)
+{
+    if (!sym_is_nonboolean(sym))
+        return;
+
+    struct pexpr *e1, *e2;
+    struct fexpr_node *node1, *node2;
+    fexpr_list_for_each(node1, sym->nb_vals) {
+        e1 = pexf(node1->elem);
+        for (node2 = node1->next; node2 != NULL; node2 = node2->next) {
+            e2 = pexf(node2->elem);
+            struct pexpr *e = pexpr_or(pexpr_not(e1), pexpr_not(e2));
+            sym_add_constraint(sym, e);
+        }
+    }
+}
+
+/*
+ * a visible prompt for a non-boolean implies a value for the symbol
+ */
+static void sym_add_nonbool_prompt_constraint(struct symbol *sym)
+{
+    struct property *prompt = sym_get_prompt(sym);
+    if (prompt == NULL)
+        return;
+
+    struct pexpr *promptCondition = prop_get_condition(prompt);
+    struct pexpr *n = pexf(sym_get_nonbool_fexpr(sym, "n"));
+
+    if (n->type != PE_SYMBOL)
+        return;
+    if (n->left.fexpr == NULL)
+        return;
+
+    struct pexpr *c = pexpr_implies(promptCondition, pexpr_not(n));
+
+    sym_add_constraint(sym, c);
+}
+
+static struct default_map * create_default_map_entry(struct fexpr *val, struct pexpr *e)
+{
+    struct default_map *map = malloc(sizeof(struct default_map));
+    map->val = val;
+    map->e = e;
+
+    return map;
+}
+
+static struct pexpr * findDefaultEntry(struct fexpr *val, struct defm_list *defaults)
+{
+    struct defm_node *node;
+    defm_list_for_each(node, defaults)
+        if (val == node->elem->val)
+            return node->elem->e;
+
+    return pexf(const_false);
+}
+
+/* add a default value to the list */
+
+/*
+ * return all defaults for a symbol
+ */
+static struct pexpr *covered;
+static bool is_tri_as_num(struct symbol *sym) {
+    if (!sym->name)
+        return false;
+
+    return !strcmp(sym->name, "0") ||
+        !strcmp(sym->name, "1") ||
+        !strcmp(sym->name, "2");
+}
+static void add_to_default_map(struct defm_list *defaults, struct default_map *entry, struct symbol *sym)
+{
+    /* as this is a map, the entry must be replaced if it already exists */
+    if (sym_is_boolean(sym)) {
+        struct default_map *map;
+        struct defm_node *node;
+        defm_list_for_each(node, defaults) {
+            map = node->elem;
+            if (map->val->sym == entry->val->sym) {
+                map->e = entry->e;
+                return;
+            }
+        }
+        defm_list_add(defaults, entry);
+    } else {
+        struct default_map *map;
+        struct defm_node *node;
+        defm_list_for_each(node, defaults) {
+            map = node->elem;
+            if (map->val->satval == entry->val->satval) {
+                map->e = entry->e;
+                return;
+            }
+        }
+        defm_list_add(defaults, entry);
+    }
+}
+static void updateDefaultList(struct fexpr *val, struct pexpr *newCond, struct defm_list *result, struct symbol *sym)
+{
+    struct pexpr *prevCond = findDefaultEntry(val, result);
+    struct pexpr *cond = pexpr_or(prevCond, pexpr_and(newCond, pexpr_not(covered)));
+    struct default_map *entry = create_default_map_entry(val, cond);
+    add_to_default_map(result, entry, sym);
+    covered = pexpr_or(covered, newCond);
+}
+static void add_defaults(struct prop_list *defaults, struct expr *ctx, struct defm_list *result, struct symbol *sym)
+{
+    struct prop_node *node;
+    struct property *p;
+    struct expr *expr;
+
+    prop_list_for_each(node, defaults) {
+        p = node->elem;
+        if (p->visible.expr) {
+            if (ctx == NULL)
+                expr = p->visible.expr;
+            else
+                expr = expr_alloc_and(p->visible.expr, ctx);
+        } else {
+            if (ctx == NULL)
+                expr = expr_alloc_symbol(&symbol_yes);
+            else
+                expr = expr_alloc_and(expr_alloc_symbol(&symbol_yes), ctx);
+        }
+
+        /* if tristate and def.value = y */
+        if (p->expr->type == E_SYMBOL && sym->type == S_TRISTATE && p->expr->left.sym == &symbol_yes) {
+            struct pexpr *expr_y = expr_calculate_pexpr_y(expr);
+            struct pexpr *expr_m = expr_calculate_pexpr_m(expr);
+
+            updateDefaultList(symbol_yes_fexpr, expr_y, result, sym);
+            updateDefaultList(symbol_mod_fexpr, expr_m, result, sym);
+        }
+        /* if def.value = n/m/y */
+        else if (p->expr->type == E_SYMBOL && sym_is_tristate_constant(p->expr->left.sym)) {
+            struct fexpr *s;
+            if (p->expr->left.sym == &symbol_yes)
+                s = symbol_yes_fexpr;
+            else if (p->expr->left.sym == &symbol_mod)
+                s = symbol_mod_fexpr;
+            else
+                s = symbol_no_fexpr;
+
+            updateDefaultList(s, expr_calculate_pexpr_both(expr), result, sym);
+        }
+        /* if def.value = n/m/y, but written as 0/1/2 for a boolean */
+        else if (sym_is_boolean(sym) &&
+            p->expr->type == E_SYMBOL &&
+            p->expr->left.sym->type == S_UNKNOWN &&
+            is_tri_as_num(p->expr->left.sym)) {
+
+            struct fexpr *s;
+            if (!strcmp(p->expr->left.sym->name, "0"))
+                s = symbol_no_fexpr;
+            else if (!strcmp(p->expr->left.sym->name, "1"))
+                s = symbol_mod_fexpr;
+            else
+                s = symbol_yes_fexpr;
+
+            updateDefaultList(s, expr_calculate_pexpr_both(expr), result, sym);
+        }
+        /* if def.value = non-boolean constant */
+        else if (expr_is_nonbool_constant(p->expr)) {
+            struct fexpr *s = sym_get_or_create_nonbool_fexpr(sym, p->expr->left.sym->name);
+            updateDefaultList(s, expr_calculate_pexpr_both(expr), result, sym);
+        }
+        /* any expression which evaluates to n/m/y for a tristate */
+        else if (sym->type == S_TRISTATE) {
+            struct expr *e_tmp = expr_alloc_and(p->expr, expr);
+            struct pexpr *expr_y = expr_calculate_pexpr_y(e_tmp);
+            struct pexpr *expr_m = expr_calculate_pexpr_m(e_tmp);
+            updateDefaultList(symbol_yes_fexpr, expr_y, result, sym);
+            updateDefaultList(symbol_mod_fexpr, expr_m, result, sym);
+        }
+        /* if non-boolean && def.value = non-boolean symbol */
+        else if (p->expr->type == E_SYMBOL && sym_is_nonboolean(sym) && sym_is_nonboolean(p->expr->left.sym)) {
+            struct prop_list *nb_sym_defaults = prop_list_init();
+            struct property *p_tmp;
+            for_all_defaults(p->expr->left.sym, p_tmp)
+                prop_list_add(nb_sym_defaults, p_tmp);
+
+            add_defaults(nb_sym_defaults, expr, result, sym);
+        }
+        /* any expression which evaluates to n/m/y */
+        else {
+            struct expr *e_tmp = expr_alloc_and(p->expr, expr);
+            struct pexpr *expr_both = expr_calculate_pexpr_both(e_tmp);
+            updateDefaultList(symbol_yes_fexpr, expr_both, result, sym);
+        }
+    }
+}
+static struct defm_list * get_defaults(struct symbol *sym)
+{
+    struct defm_list *result = defm_list_init();
+    covered = pexf(const_false);
+
+    struct prop_list *defaults = prop_list_init();
+    struct property *p;
+    for_all_defaults(sym, p)
+        prop_list_add(defaults, p);
+
+    add_defaults(defaults, NULL, result, sym);
+
+    return result;
+}
+
+/*
+ * return the default_map for "y", False if it doesn't exist
+ */
+static struct pexpr * get_default_y(struct defm_list *list)
+{
+    struct default_map *entry;
+    struct defm_node *node;
+
+    defm_list_for_each(node, list) {
+        entry = node->elem;
+        if (entry->val->type == FE_SYMBOL && entry->val->sym == &symbol_yes)
+            return entry->e;
+    }
+
+    return pexf(const_false);
+}
+
+/*
+ * return the default map for "m", False if it doesn't exist
+ */
+static struct pexpr *get_default_m(struct defm_list *list)
+{
+    struct default_map *entry;
+    struct defm_node *node;
+
+    defm_list_for_each(node, list) {
+        entry = node->elem;
+        if (entry->val->type == FE_SYMBOL && entry->val->sym == &symbol_mod)
+            return entry->e;
+    }
+
+    return pexf(const_false);
+}
+
+/*
+ * return the constraint when _some_ default value will be applied
+ */
+static struct pexpr *get_default_any(struct symbol *sym)
+{
+    if (!sym_is_nonboolean(sym))
+        return NULL;
+
+    struct property *prop;
+    struct expr *e;
+    struct pexpr *p = pexf(const_false);
+    for_all_defaults(sym, prop) {
+        if (prop->visible.expr)
+            e = prop->visible.expr;
+        else
+            e = expr_alloc_symbol(&symbol_yes);
+
+        if (expr_can_evaluate_to_mod(e))
+            p = pexpr_or(p, expr_calculate_pexpr_both(e));
+
+        p = pexpr_or(p, expr_calculate_pexpr_y(e));
+    }
+
+    return p;
+}
+
+/*
+ * get the value for the range
+ */
+static long sym_get_range_val(struct symbol *sym, int base)
+{
+    sym_calc_value(sym);
+    switch (sym->type) {
+    case S_INT:
+        base = 10;
+        break;
+    case S_HEX:
+        base = 16;
+        break;
+    default:
+        break;
+    }
+    return strtol(sym->curr.val, NULL, base);
+}
+
+/*
+ * count the number of all constraints
+ */
+unsigned int count_counstraints(void)
+{
+    unsigned int i, c = 0;
+    struct symbol *sym;
+    for_all_symbols(i, sym) {
+        if (sym->type == S_UNKNOWN)
+            continue;
+
+        c += sym->constraints->size;
+    }
+
+    return c;
+}
+
+/*
+ * add a constraint for a symbol
+ */
+void sym_add_constraint(struct symbol *sym, struct pexpr *constraint)
+{
+    if (!constraint)
+        return;
+
+    /* no need to add that */
+    if (constraint->type == PE_SYMBOL && constraint->left.fexpr == const_true)
+        return;
+
+    /* this should never happen */
+    if (constraint->type == PE_SYMBOL && constraint->left.fexpr == const_false)
+        perror("Adding const_false.");
+
+    pexpr_list_add(sym->constraints, constraint);
+
+    if (!pexpr_is_nnf(constraint))
+        pexpr_print("Not NNF:", constraint, -1);
+}
+
+/*
+ * add a constraint for a symbol, but check for duplicate constraints
+ */
+void sym_add_constraint_eq(struct symbol *sym, struct pexpr *constraint)
+{
+    if (!constraint)
+        return;
+
+    /* no need to add that */
+    if (constraint->type == PE_SYMBOL && constraint->left.fexpr == const_true)
+        return;
+
+    /* this should never happen */
+    if (constraint->type == PE_SYMBOL && constraint->left.fexpr == const_false)
+        perror("Adding const_false.");
+
+    /* check the constraints for the same symbol */
+    struct pexpr_node *node;
+    pexpr_list_for_each(node, sym->constraints)
+        if (pexpr_eq(constraint, node->elem))
+            return;
+
+    pexpr_list_add(sym->constraints, constraint);
+
+    if (!pexpr_is_nnf(constraint))
+        pexpr_print("Not NNF:", constraint, -1);
+}
diff --git a/scripts/kconfig/cf_constraints.h b/scripts/kconfig/cf_constraints.h
new file mode 100644
index 000000000000..dca89ca1640e
--- /dev/null
+++ b/scripts/kconfig/cf_constraints.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#ifndef CF_CONSTRAINTS_H
+#define CF_CONSTRAINTS_H
+
+/* build the constraints for each symbol */
+void get_constraints(void);
+
+/* count the number of all constraints */
+unsigned int count_counstraints(void);
+
+/* add a constraint for a symbol */
+void sym_add_constraint(struct symbol *sym, struct pexpr *constraint);
+
+void sym_add_constraint_fexpr(struct symbol *sym, struct fexpr *constraint);
+
+/* add a constraint for a symbol, but check for duplicate constraints */
+void sym_add_constraint_eq(struct symbol *sym, struct pexpr *constraint);
+
+#endif
-- 
2.33.0




^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 07/12] Add files for handling expressions
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
                   ` (5 preceding siblings ...)
  2021-10-20  9:41 ` [RFC 06/12] Add files for building constraints Thorsten Berger
@ 2021-10-20  9:43 ` Thorsten Berger
  2021-10-20  9:44 ` [RFC 08/12] Add files for RangeFix Thorsten Berger
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:43 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/cf_expr.c | 2146 +++++++++++++++++++++++++++++++++++++
 scripts/kconfig/cf_expr.h |  237 ++++
 2 files changed, 2383 insertions(+)
 create mode 100644 scripts/kconfig/cf_expr.c
 create mode 100644 scripts/kconfig/cf_expr.h

diff --git a/scripts/kconfig/cf_expr.c b/scripts/kconfig/cf_expr.c
new file mode 100644
index 000000000000..7ca0ff4bc6ad
--- /dev/null
+++ b/scripts/kconfig/cf_expr.c
@@ -0,0 +1,2146 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "configfix.h"
+
+static void create_fexpr_bool(struct symbol *sym);
+static void create_fexpr_nonbool(struct symbol *sym);
+static void create_fexpr_unknown(struct symbol *sym);
+static void create_fexpr_choice(struct symbol *sym);
+
+static void pexpr_print_util(struct pexpr *e, int prevtoken);
+
+static int trans_count;
+
+
+/*
+ *  create a fexpr
+ */
+struct fexpr * fexpr_create(int satval, enum fexpr_type type, char *name)
+{
+    struct fexpr *e = xcalloc(1, sizeof(*e));
+    e->satval = satval;
+    e->type = type;
+    e->name = str_new();
+    e->assumption = false;
+    str_append(&e->name, name);
+
+    return e;
+}
+
+/*
+ * create the fexpr for a symbol
+ */
+void sym_create_fexpr(struct symbol *sym)
+{
+    if (sym_is_choice(sym))
+        create_fexpr_choice(sym);
+    else if (sym_is_boolean(sym))
+        create_fexpr_bool(sym);
+    else if (sym_is_nonboolean(sym))
+        create_fexpr_nonbool(sym);
+    else
+        create_fexpr_unknown(sym);
+}
+
+/*
+ * create the fexpr for symbols with reverse dependencies
+ */
+static void create_fexpr_selected(struct symbol *sym)
+{
+    /* fexpr_sel_y */
+    struct fexpr *fexpr_sel_y = fexpr_create(sat_variable_nr++, FE_SELECT, sym->name);
+    str_append(&fexpr_sel_y->name, "_sel_y");
+    fexpr_sel_y->sym = sym;
+    fexpr_add_to_satmap(fexpr_sel_y);
+
+    sym->fexpr_sel_y = fexpr_sel_y;
+
+    /* fexpr_sel_m */
+    if (sym->type == S_BOOLEAN)
+        return;
+    struct fexpr *fexpr_sel_m = fexpr_create(sat_variable_nr++, FE_SELECT, sym->name);
+    str_append(&fexpr_sel_m->name, "_sel_m");
+    fexpr_sel_m->sym = sym;
+    fexpr_add_to_satmap(fexpr_sel_m);
+
+    sym->fexpr_sel_m = fexpr_sel_m;
+}
+
+/*
+ * create the fexpr for a boolean/tristate symbol
+ */
+static void create_fexpr_bool(struct symbol *sym)
+{
+    struct fexpr *fexpr_y = fexpr_create(sat_variable_nr++, FE_SYMBOL, sym->name);
+    fexpr_y->sym = sym;
+    fexpr_y->tri = yes;
+    fexpr_add_to_satmap(fexpr_y);
+
+    sym->fexpr_y = fexpr_y;
+
+    struct fexpr *fexpr_m;
+    if (sym->type == S_TRISTATE) {
+        fexpr_m = fexpr_create(sat_variable_nr++, FE_SYMBOL, sym->name);
+        str_append(&fexpr_m->name, "_MODULE");
+        fexpr_m->sym = sym;
+        fexpr_m->tri = mod;
+        fexpr_add_to_satmap(fexpr_m);
+    } else {
+        fexpr_m = const_false;
+    }
+
+    sym->fexpr_m = fexpr_m;
+
+    if (sym->rev_dep.expr)
+        create_fexpr_selected(sym);
+}
+
+/*
+ * create the fexpr for a non-boolean symbol
+ */
+static void create_fexpr_nonbool(struct symbol *sym)
+{
+    sym->fexpr_y = const_false;
+    sym->fexpr_m = const_false;
+    sym->nb_vals = fexpr_list_init();
+
+    /* default values */
+    char int_values[][2] = {"n", "0", "1"};
+    char hex_values[][4] = {"n", "0x0", "0x1"};
+    char string_values[][9] = {"n", "", "nonempty"};
+
+    int i;
+    for (i = 0; i < 3; i++) {
+        struct fexpr *e = fexpr_create(sat_variable_nr++, FE_NONBOOL, sym->name);
+        e->sym = sym;
+        str_append(&e->name, "=");
+        e->nb_val = str_new();
+
+        switch (sym->type) {
+        case S_INT:
+            str_append(&e->name, int_values[i]);
+            str_append(&e->nb_val, int_values[i]);
+            break;
+        case S_HEX:
+            str_append(&e->name, hex_values[i]);
+            str_append(&e->nb_val, hex_values[i]);
+            break;
+        case S_STRING:
+            str_append(&e->name, string_values[i]);
+            str_append(&e->nb_val, string_values[i]);
+            break;
+        default:
+            break;
+        }
+
+        fexpr_list_add(sym->nb_vals, e);
+        fexpr_add_to_satmap(e);
+    }
+}
+
+
+/*
+ * set fexpr_y and fexpr_m simply to False
+ */
+static void create_fexpr_unknown(struct symbol *sym)
+{
+    sym->fexpr_y = const_false;
+    sym->fexpr_m = const_false;
+}
+
+
+/*
+ * create the fexpr for a choice symbol
+ */
+static void create_fexpr_choice(struct symbol *sym)
+{
+    if (!sym_is_boolean(sym))
+        return;
+
+    struct property *prompt = sym_get_prompt(sym);
+    if (prompt == NULL) {
+        perror("Choice symbol should have a prompt.");
+        return;
+    }
+
+    char *name = strdup(prompt->text);
+
+    /* remove spaces */
+    char *write = name, *read = name;
+    do {
+        if (*read != ' ')
+            *write++ = *read;
+    } while (*read++);
+
+    struct fexpr *fexpr_y = fexpr_create(sat_variable_nr++, FE_CHOICE, "Choice_");
+    str_append(&fexpr_y->name, name);
+    fexpr_y->sym = sym;
+    fexpr_y->tri = yes;
+    fexpr_add_to_satmap(fexpr_y);
+
+    sym->fexpr_y = fexpr_y;
+
+    struct fexpr *fexpr_m;
+    if (sym->type == S_TRISTATE) {
+        fexpr_m = fexpr_create(sat_variable_nr++, FE_CHOICE, "Choice_");
+        str_append(&fexpr_m->name, name);
+        str_append(&fexpr_m->name, "_MODULE");
+        fexpr_m->sym = sym;
+        fexpr_m->tri = mod;
+        fexpr_add_to_satmap(fexpr_m);
+    } else {
+        fexpr_m = const_false;
+    }
+    sym->fexpr_m = fexpr_m;
+}
+
+/*
+ * evaluate an unequality between a non-Boolean symbol and a constant
+ */
+static struct pexpr * expr_eval_unequal_nonbool_const(struct symbol *sym, struct symbol *compval, enum expr_type type)
+{
+    if (!sym || !compval)
+        return pexf(const_false);
+
+    int base = 0;
+    switch (sym->type) {
+    case S_INT:
+        base = 10;
+        break;
+    case S_HEX:
+        base = 16;
+        break;
+    default:
+        break;
+    }
+
+    struct pexpr *c = pexf(const_false);
+    long val = strtol(compval->name, NULL, base);
+
+    struct fexpr_node *node;
+    struct fexpr *fe;
+    for (node = sym->nb_vals->head->next; node != NULL; node = node->next) {
+        fe = node->elem;
+        long symval = strtol(str_get(&fe->nb_val), NULL, base);
+
+        switch (type) {
+        case E_LTH:
+            if (symval < val)
+                c = pexpr_or(c, pexf(fe));
+            break;
+        case E_LEQ:
+            if (symval <= val)
+                c = pexpr_or(c, pexf(fe));
+            break;
+        case E_GTH:
+            if (symval > val)
+                c = pexpr_or(c, pexf(fe));
+            break;
+        case E_GEQ:
+            if (symval >= val)
+                c = pexpr_or(c, pexf(fe));
+            break;
+        default:
+            perror("Illegal unequal.");
+        }
+    }
+
+    return c;
+}
+
+/*
+ * evaluate an unequality between 2 Boolean symbols
+ */
+static struct pexpr * expr_eval_unequal_bool(struct symbol *left, struct symbol *right, enum expr_type type)
+{
+    if (!left || !right)
+        return pexf(const_false);
+
+    if (!sym_is_boolean(left) || !sym_is_boolean(right)) {
+        perror("Comparing 2 symbols that should be boolean.");
+        return pexf(const_false);
+    }
+
+    struct pexpr *c = pexf(const_false);
+    switch (type) {
+    case E_LTH:
+        c = pexpr_and(
+            pexpr_not(sym_get_fexpr_both(left)),
+            sym_get_fexpr_both(right));
+        if (left->type == S_TRISTATE)
+            c = pexpr_or(c,
+                pexpr_and
+                    (pexf(left->fexpr_m),
+                     pexf(right->fexpr_y)));
+        break;
+    case E_LEQ:
+        c = pexpr_and(pexf(left->fexpr_y), pexf(right->fexpr_y));
+        if (left->type == S_TRISTATE)
+            c = pexpr_or(c,
+                pexpr_and(
+                    pexf(left->fexpr_m),
+                    sym_get_fexpr_both(right)));
+        c = pexpr_or(c, pexpr_not(sym_get_fexpr_both(left)));
+        break;
+    case E_GTH:
+        c = pexpr_and(
+            sym_get_fexpr_both(left),
+            pexpr_not(sym_get_fexpr_both(right)));
+        if (right->type == S_TRISTATE)
+            c = pexpr_or(c,
+                pexpr_and
+                    (pexf(left->fexpr_y),
+                     pexf(right->fexpr_m)));
+        break;
+    case E_GEQ:
+        c = pexpr_and(pexf(left->fexpr_y), pexf(right->fexpr_y));
+        if (right->type == S_TRISTATE)
+            c = pexpr_or(c,
+                pexpr_and(
+                    sym_get_fexpr_both(left),
+                    pexf(right->fexpr_m)));
+        c = pexpr_or(c, pexpr_not(sym_get_fexpr_both(right)));
+        break;
+    default:
+        perror("Wrong type in expr_eval_unequal_bool.");
+    }
+
+    return c;
+}
+/*
+ * calculate, when expr will evaluate to yes or mod
+ */
+struct pexpr * expr_calculate_pexpr_both(struct expr *e)
+{
+    if (!e)
+        return pexf(const_false);
+
+    if (!expr_can_evaluate_to_mod(e))
+        return expr_calculate_pexpr_y(e);
+
+    switch (e->type) {
+    case E_SYMBOL:
+        return pexpr_or(expr_calculate_pexpr_m(e), expr_calculate_pexpr_y(e));
+    case E_AND:
+        return expr_calculate_pexpr_both_and(e->left.expr, e->right.expr);
+    case E_OR:
+        return expr_calculate_pexpr_both_or(e->left.expr, e->right.expr);
+    case E_NOT:
+        return pexpr_or(expr_calculate_pexpr_m(e), expr_calculate_pexpr_y(e));
+    case E_EQUAL:
+        return expr_calculate_pexpr_y_equals(e);
+    case E_UNEQUAL:
+        return expr_calculate_pexpr_y_unequals(e);
+    case E_LTH:
+    case E_LEQ:
+    case E_GTH:
+    case E_GEQ:
+        return expr_calculate_pexpr_y_comp(e);
+    default:
+        // TODO
+        perror("Unhandled type - expr_calculate_pexpr_both");
+        return NULL;
+    }
+}
+
+/*
+ * calculate, when expr will evaluate to yes
+ */
+struct pexpr * expr_calculate_pexpr_y(struct expr *e){
+    if (!e)
+        return NULL;
+
+    switch (e->type) {
+    case E_SYMBOL:
+        return pexf(e->left.sym->fexpr_y);
+    case E_AND:
+        return expr_calculate_pexpr_y_and(e->left.expr, e->right.expr);
+    case E_OR:
+        return expr_calculate_pexpr_y_or(e->left.expr, e->right.expr);
+    case E_NOT:
+        return expr_calculate_pexpr_y_not(e->left.expr);
+    case E_EQUAL:
+        return expr_calculate_pexpr_y_equals(e);
+    case E_UNEQUAL:
+        return expr_calculate_pexpr_y_unequals(e);
+    case E_LTH:
+    case E_LEQ:
+    case E_GTH:
+    case E_GEQ:
+        return expr_calculate_pexpr_y_comp(e);
+    default:
+        perror("Unhandled type - expr_calculate_pexpr_y");
+        return NULL;
+    }
+}
+
+/*
+ * calculate, when expr will evaluate to mod
+ */
+struct pexpr * expr_calculate_pexpr_m(struct expr *e){
+    if (!e)
+        return NULL;
+
+    if (!expr_can_evaluate_to_mod(e))
+        return pexf(const_false);
+
+    switch (e->type) {
+    case E_SYMBOL:
+        return pexf(e->left.sym->fexpr_m);
+    case E_AND:
+        return expr_calculate_pexpr_m_and(e->left.expr, e->right.expr);
+    case E_OR:
+        return expr_calculate_pexpr_m_or(e->left.expr, e->right.expr);
+    case E_NOT:
+        return expr_calculate_pexpr_m_not(e->left.expr);
+    default:
+        perror("Trying to evaluate to mod.");
+        return NULL;
+    }
+}
+
+/*
+ * calculate, when expr of type AND will evaluate to yes
+ * A && B
+ */
+struct pexpr * expr_calculate_pexpr_y_and(struct expr *a, struct expr *b)
+{
+    return pexpr_and(expr_calculate_pexpr_y(a), expr_calculate_pexpr_y(b));
+}
+
+/*
+ * calculate, when expr of type AND will evaluate to mod
+ * (A || A_m) && (B || B_m) && !(A && B)
+ */
+struct pexpr * expr_calculate_pexpr_m_and(struct expr *a, struct expr *b)
+{
+    struct pexpr *topright = pexpr_not(pexpr_and(expr_calculate_pexpr_y(a), expr_calculate_pexpr_y(b)));
+    struct pexpr *ll_left = pexpr_or(expr_calculate_pexpr_y(a), expr_calculate_pexpr_m(a));
+    struct pexpr *ll_right = pexpr_or(expr_calculate_pexpr_y(b), expr_calculate_pexpr_m(b));
+    struct pexpr *topleft = pexpr_and(ll_left, ll_right);
+
+    return pexpr_and(topleft, topright);
+}
+
+/*
+ * calculate, when expr of type AND will evaluate to mod or yes
+ * (A || A_m) && (B || B_m)
+ */
+struct pexpr * expr_calculate_pexpr_both_and(struct expr *a, struct expr *b)
+{
+    struct pexpr *left = pexpr_or(expr_calculate_pexpr_y(a), expr_calculate_pexpr_m(a));
+    struct pexpr *right = pexpr_or(expr_calculate_pexpr_y(b), expr_calculate_pexpr_m(b));
+    return pexpr_and(left, right);
+}
+
+/*
+ * calculate, when expr of type OR will evaluate to yes
+ * A || B
+ */
+struct pexpr * expr_calculate_pexpr_y_or(struct expr *a, struct expr *b)
+{
+    return pexpr_or(expr_calculate_pexpr_y(a), expr_calculate_pexpr_y(b));
+}
+
+/*
+ * calculate, when expr of type OR will evaluate to mod
+ * (A_m || B_m) && !A && !B
+ */
+struct pexpr * expr_calculate_pexpr_m_or(struct expr *a, struct expr *b)
+{
+    struct pexpr *topright = pexpr_not(expr_calculate_pexpr_y(b));
+    struct pexpr *lowerleft = pexpr_or(expr_calculate_pexpr_m(a), expr_calculate_pexpr_m(b));
+    struct pexpr *topleft = pexpr_and(lowerleft, pexpr_not(expr_calculate_pexpr_y(a)));
+
+    return pexpr_and(topleft, topright);
+}
+
+/*
+ * calculate, when expr of type OR will evaluate to mod or yes
+ * (A_m || A || B_m || B)
+ */
+struct pexpr * expr_calculate_pexpr_both_or(struct expr *a, struct expr *b)
+{
+    struct pexpr *left = pexpr_or(expr_calculate_pexpr_y(a), expr_calculate_pexpr_m(a));
+    struct pexpr *right = pexpr_or(expr_calculate_pexpr_y(b), expr_calculate_pexpr_m(b));
+    return pexpr_or(left, right);
+}
+
+/*
+ * calculate, when expr of type NOT will evaluate to yes
+ * !(A || A_m)
+ */
+struct pexpr * expr_calculate_pexpr_y_not(struct expr * e)
+{
+    return pexpr_not(pexpr_or(expr_calculate_pexpr_y(e), expr_calculate_pexpr_m(e)));
+}
+
+/*
+ * calculate, when expr of type NOT will evaluate to mod
+ * A_m
+ */
+struct pexpr * expr_calculate_pexpr_m_not(struct expr * e)
+{
+    return expr_calculate_pexpr_m(e);
+}
+
+static struct pexpr * equiv_pexpr(struct pexpr *a, struct pexpr *b)
+{
+    struct pexpr *yes = pexpr_and(a, b);
+    struct pexpr *not = pexpr_and(pexpr_not(a), pexpr_not(b));
+
+    return pexpr_or(yes, not);
+}
+
+/*
+ * create the fexpr of a non-boolean symbol for a specific value
+ */
+struct fexpr * sym_create_nonbool_fexpr(struct symbol *sym, char *value)
+{
+
+    if (!strcmp(value, "")) {
+        if (sym->type == S_STRING)
+            return sym->nb_vals->head->next->elem;
+        else
+            return sym->nb_vals->head->elem;
+    }
+
+    struct fexpr *e = sym_get_nonbool_fexpr(sym, value);
+
+    /* fexpr already exists */
+    if (e != NULL)
+        return e;
+
+    char *s = value;
+    if (sym->type == S_INT && !string_is_number(value)) {
+        struct symbol *tmp = sym_find(value);
+
+        if (tmp != NULL)
+            s = (char *) tmp->curr.val;
+    } else if (sym->type == S_HEX && !string_is_hex(value)) {
+        struct symbol *tmp = sym_find(value);
+
+        if (tmp != NULL)
+            s = (char *) tmp->curr.val;
+    } else if (sym->type == S_STRING) {
+        struct symbol *tmp = sym_find(value);
+
+        if (tmp != NULL)
+            s = (char *) tmp->curr.val;
+    }
+
+    if (!strcmp(s, "")) {
+        if (sym->type == S_STRING)
+            return sym->nb_vals->head->next->elem;
+        else
+            return sym->nb_vals->head->elem;
+    }
+
+    e = sym_get_nonbool_fexpr(sym, s);
+    if (e != NULL)
+        return e;
+
+    e = fexpr_create(sat_variable_nr++, FE_NONBOOL, sym->name);
+    e->sym = sym;
+    str_append(&e->name, "=");
+    str_append(&e->name, s);
+    e->nb_val = str_new();
+    str_append(&e->nb_val, s);
+
+    fexpr_list_add(sym->nb_vals, e);
+    fexpr_add_to_satmap(e);
+
+    return e;
+}
+
+/*
+ * return the fexpr of a non-boolean symbol for a specific value, NULL if non-existent
+ */
+struct fexpr * sym_get_nonbool_fexpr(struct symbol *sym, char *value)
+{
+    struct fexpr_node *e;
+    fexpr_list_for_each(e, sym->nb_vals) {
+        if (strcmp(str_get(&e->elem->nb_val), value) == 0)
+            return e->elem;
+    }
+
+    return NULL;
+}
+
+/*
+ * return the fexpr of a non-boolean symbol for a specific value, if it exists
+ * otherwise create it
+ */
+struct fexpr * sym_get_or_create_nonbool_fexpr(struct symbol *sym, char *value)
+{
+    struct fexpr *e = sym_get_nonbool_fexpr(sym, value);
+
+    if (e != NULL)
+        return e;
+    else
+        return sym_create_nonbool_fexpr(sym, value);
+}
+
+/*
+ * calculate, when expr of type EQUAL will evaluate to yes
+ */
+struct pexpr * expr_calculate_pexpr_y_equals(struct expr *e)
+{
+    /* comparing 2 tristate constants */
+    if (sym_is_tristate_constant(e->left.sym) && sym_is_tristate_constant(e->right.sym))
+        return e->left.sym == e->right.sym ? pexf(const_true) : pexf(const_false);
+
+    /* comparing 2 nonboolean constants */
+    if (sym_is_nonbool_constant(e->left.sym) && sym_is_nonbool_constant(e->right.sym))
+        return strcmp(e->left.sym->name, e->right.sym->name) == 0 ? pexf(const_true) : pexf(const_false);
+
+    /* comparing 2 boolean/tristate incl. yes/mod/no constants */
+    if (sym_is_bool_or_triconst(e->left.sym) && sym_is_bool_or_triconst(e->right.sym)) {
+        struct pexpr *yes = equiv_pexpr(pexf(e->left.sym->fexpr_y), pexf(e->right.sym->fexpr_y));
+        struct pexpr *mod = equiv_pexpr(pexf(e->left.sym->fexpr_m), pexf(e->right.sym->fexpr_m));
+
+        return pexpr_and(yes, mod);
+    }
+
+    /* comparing nonboolean with a constant */
+    if (sym_is_nonboolean(e->left.sym) && sym_is_nonbool_constant(e->right.sym)) {
+        return pexf(sym_get_or_create_nonbool_fexpr(e->left.sym, e->right.sym->name));
+    }
+    if (sym_is_nonbool_constant(e->left.sym) && sym_is_nonboolean(e->right.sym))
+        return pexf(sym_get_or_create_nonbool_fexpr(e->right.sym, e->left.sym->name));
+
+    /* comparing nonboolean with tristate constant, will never be true */
+    if (sym_is_nonboolean(e->left.sym) && sym_is_tristate_constant(e->right.sym))
+        return pexf(const_false);
+    if (sym_is_tristate_constant(e->left.sym) && sym_is_nonboolean(e->right.sym))
+        return pexf(const_false);
+
+    /* comparing 2 nonboolean symbols */
+    if (sym_is_nonboolean(e->left.sym) && sym_is_nonboolean(e->right.sym)) {
+        struct pexpr *c = pexf(const_false);
+        struct fexpr_node *node1, *node2;
+        struct fexpr *e1, *e2;
+        for (node1 = e->left.sym->nb_vals->head->next; node1 != NULL; node1 = node1->next) {
+            e1 = node1->elem;
+            for (node2 = e->right.sym->nb_vals->head->next; node2 != NULL; node2 = node2->next) {
+                e2 = node2->elem;
+                if (!strcmp(str_get(&e1->nb_val), str_get(&e2->nb_val))) {
+                    c = pexpr_or(c, pexpr_and(pexf(e1), pexf(e2)));
+                    break;
+                }
+            }
+        }
+        return c;
+    }
+
+    /* comparing boolean item with nonboolean constant, will never be true */
+    if (sym_is_tristate_constant(e->left.sym) && sym_is_nonbool_constant(e->right.sym))
+        return pexf(const_false);
+    if (sym_is_nonbool_constant(e->left.sym) && sym_is_tristate_constant(e->right.sym))
+        return pexf(const_false);
+
+    /* comparing symbol of type unknown with tristate constant */
+    if (e->left.sym->type == S_UNKNOWN && sym_is_tristate_constant(e->right.sym))
+        return pexf(const_false);
+    if (sym_is_tristate_constant(e->left.sym) && e->right.sym->type == S_UNKNOWN)
+        return pexf(const_false);
+
+    /* any other comparison is not supported and should not be executed */
+    perror("Unsupported equality.");
+    print_expr(":", e, 0);
+
+    return pexf(const_false);
+}
+
+/*
+ * transform an UNEQUAL into a Not(EQUAL)
+ */
+struct pexpr * expr_calculate_pexpr_y_unequals(struct expr *e)
+{
+    return pexpr_not(expr_calculate_pexpr_y_equals(e));
+}
+
+struct pexpr * expr_calculate_pexpr_y_comp(struct expr *e)
+{
+    if (!e)
+        return NULL;
+
+    switch (e->type) {
+    case E_LTH:
+    case E_LEQ:
+    case E_GTH:
+    case E_GEQ:
+        /* compare non-Boolean symbol with constant */
+        if (sym_is_nonboolean(e->left.sym) &&
+            e->right.sym->type == S_UNKNOWN &&
+            string_is_number(e->right.sym->name)
+        ) {
+            return expr_eval_unequal_nonbool_const(e->left.sym, e->right.sym, e->type);
+        }
+        if (sym_is_nonboolean(e->right.sym) &&
+            e->left.sym->type == S_UNKNOWN &&
+            string_is_number(e->left.sym->name)
+        ) {
+            return expr_eval_unequal_nonbool_const(e->right.sym, e->left.sym, e->type);
+        }
+
+        /* compare 2 Boolean symbols */
+        if (sym_is_boolean(e->left.sym) && sym_is_boolean(e->right.sym))
+            return expr_eval_unequal_bool(e->left.sym, e->right.sym, e->type);
+
+        return pexf(const_false);
+    default:
+        perror("Unhandled type - expr_calculate_pexpr_y_comp");
+        return NULL;
+    }
+}
+
+/*
+ * macro to create a pexpr of type AND
+ */
+struct pexpr * pexpr_and(struct pexpr *a, struct pexpr *b)
+{
+    /* simplifications:
+     * expr && False -> False
+     * expr && True  -> expr
+     * expr && expr  -> expr
+     */
+    if (a->type == PE_SYMBOL && a->left.fexpr == const_false)
+        return a;
+
+    if (b->type == PE_SYMBOL && b->left.fexpr == const_false)
+        return b;
+
+    if (a->type == PE_SYMBOL && a->left.fexpr == const_true)
+        return b;
+
+    if (b->type == PE_SYMBOL && b->left.fexpr == const_true)
+        return a;
+
+    /* A && A -> A */
+    if (pexpr_eq(a,b))
+        return a;
+
+    /* (A && B) && C -> A && B if B == C */
+    if (a->type == PE_AND && pexpr_eq(a->right.pexpr, b))
+        return a;
+    /* A && (B && C) -> B && C if A == B */
+    if (b->type == PE_AND && pexpr_eq(a, b->left.pexpr))
+        return b;
+
+    /* (A || B) && (C || D) -> A || (B && D) if A == C */
+    if (a->type == PE_OR && b->type == PE_OR && (
+        pexpr_eq(a->left.pexpr, b->left.pexpr)
+    ))
+        return pexpr_or(a->left.pexpr,
+                pexpr_and(a->right.pexpr, b->right.pexpr));
+    /* (A || B) && (C || D) -> B || (A && C) if B == D */
+    if (a->type == PE_OR && b->type == PE_OR && (
+        pexpr_eq(a->right.pexpr, b->right.pexpr)
+    ))
+        return pexpr_or(a->right.pexpr,
+                pexpr_and(a->left.pexpr, b->left.pexpr));
+    /* (A || B) && (C || D) -> A || (B && C) if A == D */
+    if (a->type == PE_OR && b->type == PE_OR && (
+        pexpr_eq(a->left.pexpr, b->right.pexpr)
+    ))
+        return pexpr_or(a->left.pexpr,
+                pexpr_and(a->right.pexpr, b->left.pexpr));
+    /* (A || B) && (C || D) -> B || (A && D) if B == C */
+    if (a->type == PE_OR && b->type == PE_OR && (
+        pexpr_eq(a->right.pexpr, b->left.pexpr)
+    ))
+        return pexpr_or(a->right.pexpr,
+                pexpr_and(a->left.pexpr, b->right.pexpr));
+
+    struct pexpr *e = xcalloc(1, sizeof(*e));
+    e->type = PE_AND;
+    e->left.pexpr = a;
+    e->right.pexpr = b;
+
+    return e;
+}
+
+/*
+ * macro to create a pexpr of type OR
+ */
+struct pexpr * pexpr_or(struct pexpr *a, struct pexpr *b)
+{
+    /* simplifications:
+     * expr || False -> expr
+     * expr || True  -> True
+     * expr || expr  -> expr
+     */
+    if (a->type == PE_SYMBOL && a->left.fexpr == const_false)
+        return b;
+
+    if (b->type == PE_SYMBOL && b->left.fexpr == const_false)
+        return a;
+
+    if (a->type == PE_SYMBOL && a->left.fexpr == const_true)
+        return a;
+
+    if (b->type == PE_SYMBOL && b->left.fexpr == const_true)
+        return b;
+
+    /* A || A -> A */
+    if (pexpr_eq(a,b))
+        return a;
+
+    /* A || (B && C) -> A if (A == B || A == C) */
+    if (b->type == PE_AND && (
+        pexpr_eq(a, b->left.pexpr) || pexpr_eq(a, b->right.pexpr)
+    ))
+        return a;
+    /* (A && B) || C -> C if (A == C || B == C) */
+    if (a->type == PE_AND && (
+        pexpr_eq(a->left.pexpr, b) || pexpr_eq(a->right.pexpr, b)
+    ))
+        return b;
+
+    /* -A || B -> True if A == B */
+    if (a->type == PE_NOT && pexpr_eq(a->left.pexpr, b))
+        return pexf(const_true);
+    /* A || -B -> True if A == B */
+    if (b->type == PE_NOT && pexpr_eq(a, b->left.pexpr))
+        return pexf(const_true);
+
+    /* (A && B) || (C && D) -> A && (B || D) if (A == C) */
+    if (a->type == PE_AND && b->type == PE_AND &&
+        pexpr_eq(a->left.pexpr, b->left.pexpr)
+    )
+        return pexpr_and(a->left.pexpr,
+                 pexpr_or(a->right.pexpr, b->right.pexpr));
+    /* (A && B) || (C && D) -> B && (A || C) if (B == D) */
+    if (a->type == PE_AND && b->type == PE_AND &&
+        pexpr_eq(a->right.pexpr, b->right.pexpr)
+    )
+        return pexpr_and(a->right.pexpr,
+                 pexpr_or(a->left.pexpr, b->left.pexpr));
+    /* (A && B) || (C && D) -> A && (B || C) if (A == D) */
+    if (a->type == PE_AND && b->type == PE_AND &&
+        pexpr_eq(a->left.pexpr, b->right.pexpr)
+    )
+        return pexpr_and(a->left.pexpr,
+                 pexpr_or(a->right.pexpr, b->left.pexpr));
+    /* (A && B) || (C && D) -> B && (A || D) if (B == C) */
+    if (a->type == PE_AND && b->type == PE_AND &&
+        pexpr_eq(a->right.pexpr, b->left.pexpr)
+    )
+        return pexpr_and(a->right.pexpr,
+                 pexpr_or(a->left.pexpr, b->right.pexpr));
+
+    /* (A && B) || (C || D) -> C || D if
+     * A == C || A == D || B == C || B == D */
+    if (a->type == PE_AND && b->type == PE_OR && (
+        pexpr_eq(a->left.pexpr, b->left.pexpr) ||
+        pexpr_eq(a->left.pexpr, b->right.pexpr) ||
+        pexpr_eq(a->right.pexpr, b->left.pexpr) ||
+        pexpr_eq(a->right.pexpr, b->right.pexpr)
+    ))
+        return b;
+    /* (C || D) || (A && B) -> C || D if
+     * A == C || A == D || B == C || B == D */
+    if (a->type == PE_OR && b->type == PE_AND && (
+        pexpr_eq(a->left.pexpr, b->left.pexpr) ||
+        pexpr_eq(a->left.pexpr, b->right.pexpr) ||
+        pexpr_eq(a->right.pexpr, b->left.pexpr) ||
+        pexpr_eq(a->right.pexpr, b->right.pexpr)
+    ))
+        return a;
+
+    struct pexpr *e = xcalloc(1, sizeof(*e));
+    e->type = PE_OR;
+    e->left.pexpr = a;
+    e->right.pexpr = b;
+
+    return e;
+}
+
+/*
+ * macro to create a pexpr of type NOT
+ */
+struct pexpr * pexpr_not(struct pexpr *a)
+{
+    if (a->type == PE_SYMBOL && a->left.fexpr == const_false)
+        return pexf(const_true);
+    if (a->type == PE_SYMBOL && a->left.fexpr == const_true)
+        return pexf(const_false);
+
+    /* eliminate double negation */
+    if (a->type == PE_NOT)
+        return a->left.pexpr;
+
+    /* De Morgan */
+    if (a->type == PE_AND) {
+        struct pexpr *e = xcalloc(1, sizeof(*e));
+        e->type = PE_OR;
+        e->left.pexpr = pexpr_not(a->left.pexpr);
+        e->right.pexpr = pexpr_not(a->right.pexpr);
+        return e;
+    }
+    if (a->type == PE_OR) {
+        struct pexpr *e = xcalloc(1, sizeof(*e));
+        e->type = PE_AND;
+        e->left.pexpr = pexpr_not(a->left.pexpr);
+        e->right.pexpr = pexpr_not(a->right.pexpr);
+        return e;
+    }
+
+    struct pexpr *e = xcalloc(1, sizeof(*e));
+    e->type = PE_NOT;
+    e->left.pexpr = a;
+    return e;
+}
+
+/*
+ * macro to construct a pexpr for "A implies B"
+ */
+struct pexpr * pexpr_implies(struct pexpr *a, struct pexpr *b)
+{
+    /* A => B -> True if A == B */
+    if (pexpr_eq(a, b))
+        return pexf(const_true);
+
+    /* (A => B && C) -> (A => C) if A == B */
+    if (b->type == PE_AND && pexpr_eq(a, b->left.pexpr))
+        return pexpr_implies(a, b->right.pexpr);
+    /* (A => B && C) -> (A => B) if A == C */
+    if (b->type == PE_AND && pexpr_eq(a, b->right.pexpr))
+        return pexpr_implies(a, b->left.pexpr);
+
+    /* (A => B || C) -> True if (A == B || A == C) */
+    if (b->type == PE_OR && (
+        pexpr_eq(a, b->left.pexpr) || pexpr_eq(a, b->right.pexpr)
+    ))
+        return pexf(const_true);
+
+    /* (A && B => C) -> True if (A == C || B == C) */
+    if (a->type == PE_AND && (
+        pexpr_eq(a->left.pexpr, b) || pexpr_eq(a->right.pexpr, b)
+    ))
+        return pexf(const_true);
+
+    return pexpr_or(pexpr_not(a), b);
+}
+
+/*
+ * check whether a pexpr is in CNF
+ */
+bool pexpr_is_cnf(struct pexpr *e)
+{
+    if (!e)
+        return false;
+
+    switch (e->type) {
+    case PE_SYMBOL:
+        return true;
+    case PE_AND:
+        return false;
+    case PE_OR:
+        return pexpr_is_cnf(e->left.pexpr) && pexpr_is_cnf(e->right.pexpr);
+    case PE_NOT:
+        return e->left.pexpr->type == PE_SYMBOL;
+    }
+
+    return false;
+}
+
+/*
+ * check whether a pexpr is in NNF
+ */
+bool pexpr_is_nnf(struct pexpr *e)
+{
+    if (!e)
+        return false;
+
+    switch (e->type) {
+    case PE_SYMBOL:
+        return true;
+    case PE_AND:
+    case PE_OR:
+        return pexpr_is_nnf(e->left.pexpr) && pexpr_is_nnf(e->right.pexpr);
+    case PE_NOT:
+        return e->left.pexpr->type == PE_SYMBOL;
+    }
+
+    return false;
+}
+
+/*
+ * return fexpr_both for a symbol
+ */
+struct pexpr * sym_get_fexpr_both(struct symbol *sym)
+{
+    return sym->type == S_TRISTATE ? pexpr_or(pexf(sym->fexpr_m), pexf(sym->fexpr_y)) : pexf(sym->fexpr_y);
+}
+
+/*
+ * return fexpr_sel_both for a symbol
+ */
+struct pexpr * sym_get_fexpr_sel_both(struct symbol *sym)
+{
+    if (!sym->rev_dep.expr)
+        return pexf(const_false);
+
+    return sym->type == S_TRISTATE ? pexpr_or(pexf(sym->fexpr_sel_m), pexf(sym->fexpr_sel_y)) : pexf(sym->fexpr_sel_y);
+}
+
+/*
+ * check, if the fexpr is a symbol, a True/False-constant, a literal symbolizing a non-boolean or a choice symbol
+ */
+bool fexpr_is_symbol(struct fexpr *e)
+{
+    return e->type == FE_SYMBOL || e->type == FE_FALSE || e->type == FE_TRUE || e->type == FE_NONBOOL || e->type == FE_CHOICE || e->type == FE_SELECT || e->type == FE_NPC;
+}
+
+/*
+ * check whether a pexpr is a symbol or a negated symbol
+ */
+bool pexpr_is_symbol(struct pexpr *e)
+{
+    return e->type == PE_SYMBOL || (e->type == PE_NOT && e->left.pexpr->type == PE_SYMBOL);
+}
+
+/*
+ * check whether the fexpr is a constant (true/false)
+ */
+bool fexpr_is_constant(struct fexpr *e)
+{
+    return e == const_true || e == const_false;
+}
+
+/*
+ * add a fexpr to the satmap
+ */
+void fexpr_add_to_satmap(struct fexpr *e)
+{
+    if (e->satval >= satmap_size) {
+        satmap = xrealloc(satmap, satmap_size * 2 * sizeof(*satmap));
+        satmap_size *= 2;
+    }
+
+    satmap[e->satval] = *e;
+}
+
+/*
+ * print a fexpr
+ */
+void fexpr_print(char *tag, struct fexpr *e)
+{
+    if (!e)
+        return;
+
+    printf("%s: %s\n", tag, str_get(&e->name));
+}
+
+/*
+ * write an fexpr into a string (format needed for testing)
+ */
+void fexpr_as_char(struct fexpr *e, struct gstr *s)
+{
+    if (!e)
+        return;
+
+    switch (e->type) {
+    case FE_SYMBOL:
+    case FE_CHOICE:
+    case FE_SELECT:
+    case FE_NPC:
+    case FE_NONBOOL:
+        str_append(s, "definedEx(");
+        str_append(s, str_get(&e->name));
+        str_append(s, ")");
+        return;
+    case FE_FALSE:
+        str_append(s, "0");
+        return;
+    case FE_TRUE:
+        str_append(s, "1");
+        return;
+    default:
+        return;
+    }
+}
+
+/*
+ * write a pexpr into a string
+ */
+void pexpr_as_char(struct pexpr *e, struct gstr *s, int parent)
+{
+    if (!e)
+        return;
+
+    switch (e->type) {
+    case PE_SYMBOL:
+        if (e->left.fexpr == const_false) {
+            str_append(s, "0");
+            return;
+        }
+        if (e->left.fexpr == const_true) {
+            str_append(s, "1");
+            return;
+        }
+        str_append(s, "definedEx(");
+        str_append(s, str_get(&e->left.fexpr->name));
+        str_append(s, ")");
+        return;
+    case PE_AND:
+        /* need this hack for the FeatureExpr parser */
+        if (parent != PE_AND)
+            str_append(s, "(");
+        pexpr_as_char(e->left.pexpr, s, PE_AND);
+        str_append(s, " && ");
+        pexpr_as_char(e->right.pexpr, s, PE_AND);
+        if (parent != PE_AND)
+            str_append(s, ")");
+        return;
+    case PE_OR:
+        if (parent != PE_OR)
+            str_append(s, "(");
+        pexpr_as_char(e->left.pexpr, s, PE_OR);
+        str_append(s, " || ");
+        pexpr_as_char(e->right.pexpr, s, PE_OR);
+        if (parent != PE_OR)
+            str_append(s, ")");
+        return;
+    case PE_NOT:
+        str_append(s, "!");
+        pexpr_as_char(e->left.pexpr, s, PE_NOT);
+        return;
+    }
+}
+
+/*
+ * write a pexpr into a string
+ */
+void pexpr_as_char_short(struct pexpr *e, struct gstr *s, int parent)
+{
+    if (!e)
+        return;
+
+    switch (e->type) {
+    case PE_SYMBOL:
+        str_append(s, str_get(&e->left.fexpr->name));
+        return;
+    case PE_AND:
+        /* need this hack for the FeatureExpr parser */
+        if (parent != PE_AND)
+            str_append(s, "(");
+        pexpr_as_char_short(e->left.pexpr, s, PE_AND);
+        str_append(s, " && ");
+        pexpr_as_char_short(e->right.pexpr, s, PE_AND);
+        if (parent != PE_AND)
+            str_append(s, ")");
+        return;
+    case PE_OR:
+        if (parent != PE_OR)
+            str_append(s, "(");
+        pexpr_as_char_short(e->left.pexpr, s, PE_OR);
+        str_append(s, " || ");
+        pexpr_as_char_short(e->right.pexpr, s, PE_OR);
+        if (parent != PE_OR)
+            str_append(s, ")");
+        return;
+    case PE_NOT:
+        str_append(s, "!");
+        pexpr_as_char_short(e->left.pexpr, s, PE_NOT);
+        return;
+    }
+}
+
+/*
+ * check whether a pexpr contains a specific fexpr
+ */
+bool pexpr_contains_fexpr(struct pexpr *e, struct fexpr *fe)
+{
+    if (!e)
+        return false;
+
+    switch (e->type) {
+    case PE_SYMBOL:
+        return e->left.fexpr->satval == fe->satval;
+    case PE_AND:
+    case PE_OR:
+        return pexpr_contains_fexpr(e->left.pexpr, fe) ||
+            pexpr_contains_fexpr(e->right.pexpr, fe);
+    case PE_NOT:
+        return e->left.pexpr->left.fexpr->satval == fe->satval;
+    }
+
+    return false;
+}
+
+/*
+ * init list of fexpr
+ */
+struct fexpr_list * fexpr_list_init()
+{
+    struct fexpr_list *list = xcalloc(1, sizeof(*list));
+    list->head = NULL;
+    list->tail = NULL;
+    list->size = 0;
+
+    return list;
+}
+
+/*
+ * init list of fexpr_list
+ */
+struct fexl_list * fexl_list_init()
+{
+    struct fexl_list *list = xcalloc(1, sizeof(*list));
+    list->head = NULL;
+    list->tail = NULL;
+    list->size = 0;
+
+    return list;
+}
+
+/*
+ * init list of pexpr
+ */
+struct pexpr_list * pexpr_list_init()
+{
+    struct pexpr_list *list = xcalloc(1, sizeof(*list));
+    list->head = NULL;
+    list->tail = NULL;
+    list->size = 0;
+
+    return list;
+}
+
+/*
+ * init list of symbol_fix
+ */
+struct sfix_list * sfix_list_init(void)
+{
+    struct sfix_list *list = xcalloc(1, sizeof(*list));
+    list->head = NULL;
+    list->tail = NULL;
+    list->size = 0;
+
+    return list;
+}
+
+/*
+ * init list of symbol_fix
+ */
+struct sfl_list * sfl_list_init(void)
+{
+    struct sfl_list *list = xcalloc(1, sizeof(*list));
+    list->head = NULL;
+    list->tail = NULL;
+    list->size = 0;
+
+    return list;
+}
+
+/*
+ * init list of symbol_dvalue
+ */
+struct sdv_list * sdv_list_init(void)
+{
+    struct sdv_list *list = xcalloc(1, sizeof(*list));
+    list->head = NULL;
+    list->tail = NULL;
+    list->size = 0;
+
+    return list;
+}
+
+/*
+ * init list of symbols
+ */
+struct sym_list * sym_list_init(void)
+{
+    struct sym_list *list = xcalloc(1, sizeof(*list));
+    list->head = NULL;
+    list->tail = NULL;
+    list->size = 0;
+
+    return list;
+}
+
+/*
+ * init list of default_maps
+ */
+struct defm_list * defm_list_init(void)
+{
+    struct defm_list *list = xcalloc(1, sizeof(*list));
+    list->head = NULL;
+    list->tail = NULL;
+    list->size = 0;
+
+    return list;
+}
+
+/*
+ * init list of properties
+ */
+struct prop_list *prop_list_init(void)
+{
+    struct prop_list *list = xcalloc(1, sizeof(*list));
+    list->head = NULL;
+    list->tail = NULL;
+    list->size = 0;
+
+    return list;
+}
+
+/*
+ * add element to tail of a fexpr_list
+ */
+void fexpr_list_add(struct fexpr_list *list, struct fexpr *fe)
+{
+    struct fexpr_node *node = xcalloc(1, sizeof(*node));
+    node->elem = fe;
+
+    if (list->size == 0) {
+        list->head = node;
+        list->tail = node;
+    } else {
+        node->prev = list->tail;
+        list->tail = node;
+        node->prev->next = node;
+    }
+
+    list->size++;
+}
+
+/*
+ * add element to tail of a fexl_list
+ */
+void fexl_list_add(struct fexl_list *list, struct fexpr_list *elem)
+{
+    struct fexl_node *node = xcalloc(1, sizeof(*node));
+    node->elem = elem;
+
+    if (list->size == 0) {
+        list->head = node;
+        list->tail = node;
+    } else {
+        node->prev = list->tail;
+        list->tail = node;
+        node->prev->next = node;
+    }
+
+    list->size++;
+}
+
+/*
+ * add element to tail of a pexpr_list
+ */
+void pexpr_list_add(struct pexpr_list *list, struct pexpr *e)
+{
+    struct pexpr_node *node = xcalloc(1, sizeof(*node));
+    node->elem = e;
+
+    if (list->size == 0) {
+        list->head = node;
+        list->tail = node;
+    } else {
+        node->prev = list->tail;
+        list->tail = node;
+        node->prev->next = node;
+    }
+
+    list->size++;
+}
+
+/*
+ * add element to tail of a sfix_list
+ */
+void sfix_list_add(struct sfix_list *list, struct symbol_fix *fix)
+{
+    struct sfix_node *node = xcalloc(1, sizeof(*node));
+    node->elem = fix;
+
+    if (list->size == 0) {
+        list->head = node;
+        list->tail = node;
+    } else {
+        node->prev = list->tail;
+        list->tail = node;
+        node->prev->next = node;
+    }
+
+    list->size++;
+}
+
+/*
+ * add element to tail of a sfl_list
+ */
+void sfl_list_add(struct sfl_list *list, struct sfix_list *elem)
+{
+    struct sfl_node *node = xcalloc(1, sizeof(*node));
+    node->elem = elem;
+
+    if (list->size == 0) {
+        list->head = node;
+        list->tail = node;
+    } else {
+        node->prev = list->tail;
+        list->tail = node;
+        node->prev->next = node;
+    }
+
+    list->size++;
+}
+
+/*
+ * add element to tail of a sdv_list
+ */
+void sdv_list_add(struct sdv_list *list, struct symbol_dvalue *sdv)
+{
+    struct sdv_node *node = xcalloc(1, sizeof(*node));
+    node->elem = sdv;
+
+    if (list->size == 0) {
+        list->head = node;
+        list->tail = node;
+    } else {
+        node->prev = list->tail;
+        list->tail = node;
+        node->prev->next = node;
+    }
+
+    list->size++;
+}
+
+/*
+ * add element to tail of a sym_list
+ */
+void sym_list_add(struct sym_list *list, struct symbol *sym)
+{
+    struct sym_node *node = xcalloc(1, sizeof(*node));
+    node->elem = sym;
+
+    if (list->size == 0) {
+        list->head = node;
+        list->tail = node;
+    } else {
+        node->prev = list->tail;
+        list->tail = node;
+        node->prev->next = node;
+    }
+
+    list->size++;
+}
+
+/*
+ * add element to tail of a defm_list
+ */
+void defm_list_add(struct defm_list *list, struct default_map *map)
+{
+    struct defm_node *node = xcalloc(1, sizeof(*node));
+    node->elem = map;
+
+    if (list->size == 0) {
+        list->head = node;
+        list->tail = node;
+    } else {
+        node->prev = list->tail;
+        list->tail = node;
+        node->prev->next = node;
+    }
+
+    list->size++;
+}
+
+/*
+ * add element to tail of a prop_list
+ */
+void prop_list_add(struct prop_list *list, struct property *prop)
+{
+    struct prop_node *node = xcalloc(1, sizeof(*node));
+    node->elem = prop;
+
+    if (list->size == 0) {
+        list->head = node;
+        list->tail = node;
+    } else {
+        node->prev = list->tail;
+        list->tail = node;
+        node->prev->next = node;
+    }
+
+    list->size++;
+}
+
+/*
+ * delete an element from a fexpr_list
+ */
+void fexpr_list_delete(struct fexpr_list *list, struct fexpr_node *node)
+{
+    if (list->size == 0 || node == NULL)
+        return;
+
+    if (node == list->head)
+        list->head = node->next;
+    else
+        node->prev->next = node->next;
+
+    if (node == list->tail)
+        list->tail = node->prev;
+    else
+        node->next->prev = node->prev;
+
+    list->size--;
+    free(node);
+}
+
+/*
+ * delete an element from a fexpr_list
+ */
+void sfix_list_delete(struct sfix_list *list, struct sfix_node *node)
+{
+    if (list->size == 0 || node == NULL)
+        return;
+
+    if (node == list->head)
+        list->head = node->next;
+    else
+        node->prev->next = node->next;
+
+    if (node == list->tail)
+        list->tail = node->prev;
+    else
+        node->next->prev = node->prev;
+
+    list->size--;
+    free(node);
+}
+
+/*
+ * delete an element from a fexpr_list
+ */
+void pexpr_list_delete(struct pexpr_list *list, struct pexpr_node *node)
+{
+    if (list->size == 0 || node == NULL)
+        return;
+
+    if (node == list->head)
+        list->head = node->next;
+    else
+        node->prev->next = node->next;
+
+    if (node == list->tail)
+        list->tail = node->prev;
+    else
+        node->next->prev = node->prev;
+
+    list->size--;
+    free(node);
+}
+
+/*
+ * delete an element from a fexl_list
+ */
+void fexl_list_delete(struct fexl_list *list, struct fexl_node *node)
+{
+    if (list->size == 0 || node == NULL)
+        return;
+
+    if (node == list->head)
+        list->head = node->next;
+    else
+        node->prev->next = node->next;
+
+    if (node == list->tail)
+        list->tail = node->prev;
+    else
+        node->next->prev = node->prev;
+
+    list->size--;
+    free(node);
+}
+
+/*
+ * delete the first occurence of elem in an fexl_list
+ */
+void fexl_list_delete_elem(struct fexl_list *list, struct fexpr_list *elem)
+{
+    struct fexl_node *node, *to_delete = NULL;
+    fexl_list_for_each(node, list) {
+        if (node->elem == elem) {
+            to_delete = node;
+            break;
+        }
+    }
+
+    if (to_delete != NULL)
+        fexl_list_delete(list, to_delete);
+}
+
+/*
+ * make a shallow copy of a fexpr_list
+ */
+struct fexpr_list * fexpr_list_copy(struct fexpr_list *list)
+{
+    struct fexpr_list *ret = fexpr_list_init();
+    struct fexpr_node *node;
+    fexpr_list_for_each(node, list)
+        fexpr_list_add(ret, node->elem);
+
+    return ret;
+}
+
+/*
+ * make a shallow copy of a fexl_list
+ */
+struct fexl_list * fexl_list_copy(struct fexl_list *list)
+{
+    struct fexl_list *ret = fexl_list_init();
+    struct fexl_node *node;
+    fexl_list_for_each(node, list)
+        fexl_list_add(ret, node->elem);
+
+    return ret;
+}
+
+/*
+ * make a shallow copy of a sdv_list
+ */
+struct sdv_list * sdv_list_copy(struct sdv_list *list)
+{
+    struct sdv_list *ret = sdv_list_init();
+    struct sdv_node *node;
+    sdv_list_for_each(node, list)
+        sdv_list_add(ret, node->elem);
+
+
+    return ret;
+}
+
+/*
+ * make a shallow copy of a sfix_list
+ */
+struct sfix_list * sfix_list_copy(struct sfix_list *list)
+{
+    struct sfix_list *ret = sfix_list_init();
+    struct sfix_node *node;
+    sfix_list_for_each(node, list)
+        sfix_list_add(ret, node->elem);
+
+    return ret;
+}
+
+/*
+ * print a fexpr_list
+ */
+void fexpr_list_print(char *title, struct fexpr_list *list)
+{
+    struct fexpr_node *node;
+    printf("%s: [", title);
+
+    fexpr_list_for_each(node, list) {
+        printf("%s", str_get(&node->elem->name));
+        if (node->next != NULL)
+            printf(", ");
+    }
+
+    printf("]\n");
+}
+
+/*
+ * print a fexl_list
+ */
+void fexl_list_print(char *title, struct fexl_list *list)
+{
+    struct fexl_node *node;
+    printf("%s:\n", title);
+
+    fexl_list_for_each(node, list)
+        fexpr_list_print(":", node->elem);
+}
+
+/*
+ * print a pexpr_list
+ */
+void pexpr_list_print(char *title, struct pexpr_list *list)
+{
+    struct pexpr_node *node;
+    printf("%s: [", title);
+
+    pexpr_list_for_each(node, list) {
+        pexpr_print_util(node->elem, -1);
+        if (node->next != NULL)
+            printf(", ");
+    }
+
+    printf("]\n");
+}
+
+/*
+ * free an fexpr_list
+ */
+void fexpr_list_free(struct fexpr_list *list)
+{
+    struct fexpr_node *node = list->head, *tmp;
+
+    while (node != NULL) {
+        tmp = node->next;
+        free(node);
+        node = tmp;
+    }
+
+    free(list);
+}
+
+/*
+ * free an fexl_list
+ */
+void fexl_list_free(struct fexl_list *list){
+    struct fexl_node *node = list->head, *tmp;
+
+    while (node != NULL) {
+        tmp = node->next;
+        free(node);
+        node = tmp;
+    }
+
+    free(list);
+}
+
+/*
+ * free a sdv_list
+ */
+void sdv_list_free(struct sdv_list *list)
+{
+    struct sdv_node *node = list->head, *tmp;
+
+    while (node != NULL) {
+        tmp = node->next;
+        free(node);
+        node = tmp;
+    }
+
+    free(list);
+}
+
+/*
+ * simplify a pexpr in-place
+ *     pexpr && False -> False
+ *     pexpr && True  -> pexpr
+ *     pexpr || False -> pexpr
+ *     pexpr || True  -> True
+ */
+static struct pexpr * pexpr_eliminate_yn(struct pexpr *e)
+{
+    struct pexpr *tmp;
+
+    if (e) switch (e->type) {
+    case PE_AND:
+        e->left.pexpr = pexpr_eliminate_yn(e->left.pexpr);
+        e->right.pexpr = pexpr_eliminate_yn(e->right.pexpr);
+        if (e->left.pexpr->type == PE_SYMBOL) {
+            if (e->left.pexpr->left.fexpr == const_false) {
+                pexpr_free(e->left.pexpr);
+                pexpr_free(e->right.pexpr);
+                e->type = PE_SYMBOL;
+                e->left.fexpr = const_false;
+                e->right.pexpr = NULL;
+                return e;
+            } else if (e->left.pexpr->left.fexpr == const_true) {
+                free(e->left.pexpr);
+                tmp = e->right.pexpr;
+                *e = *(e->right.pexpr);
+                free(tmp);
+                return e;
+            }
+        }
+        if (e->right.pexpr->type == PE_SYMBOL) {
+            if (e->right.pexpr->left.fexpr == const_false) {
+                pexpr_free(e->left.pexpr);
+                pexpr_free(e->right.pexpr);
+                e->type = PE_SYMBOL;
+                e->left.fexpr = const_false;
+                e->right.fexpr = NULL;
+                return e;
+            } else if (e->right.pexpr->left.fexpr == const_true) {
+                free(e->right.pexpr);
+                tmp = e->left.pexpr;
+                *e = *(e->left.pexpr);
+                free(tmp);
+                return e;
+            }
+        }
+        break;
+    case PE_OR:
+        e->left.pexpr = pexpr_eliminate_yn(e->left.pexpr);
+        e->right.pexpr = pexpr_eliminate_yn(e->right.pexpr);
+        if (e->left.pexpr->type == PE_SYMBOL) {
+            if (e->left.pexpr->left.fexpr == const_false) {
+                free(e->left.pexpr);
+                tmp = e->right.pexpr;
+                *e = *(e->right.pexpr);
+                free(tmp);
+                return e;
+            } else if (e->left.pexpr->left.fexpr == const_true) {
+                pexpr_free(e->left.pexpr);
+                pexpr_free(e->right.pexpr);
+                e->type = PE_SYMBOL;
+                e->left.fexpr = const_true;
+                e->right.pexpr = NULL;
+            }
+        }
+        if (e->right.pexpr->type == PE_SYMBOL) {
+            if (e->right.pexpr->left.fexpr == const_false) {
+                free(e->right.pexpr);
+                tmp = e->left.pexpr;
+                *e = *(e->left.pexpr);
+                free(tmp);
+                return e;
+            } else if (e->right.pexpr->left.fexpr == const_true) {
+                pexpr_free(e->left.pexpr);
+                pexpr_free(e->right.pexpr);
+                e->type = PE_SYMBOL;
+                e->left.fexpr = const_true;
+                e->right.pexpr = NULL;
+                return e;
+            }
+        }
+    default:
+        ;
+    }
+
+    return e;
+}
+
+/*
+ * copy a pexpr
+ */
+struct pexpr * pexpr_copy(const struct pexpr *org)
+{
+    struct pexpr *e;
+
+    if (!org)
+        return NULL;
+
+    e = xmalloc(sizeof(*org));
+    memcpy(e, org, sizeof(*org));
+    switch (org->type) {
+    case PE_SYMBOL:
+        e->left = org->left;
+        break;
+    case PE_AND:
+    case PE_OR:
+        e->left.pexpr = pexpr_copy(org->left.pexpr);
+        e->right.pexpr = pexpr_copy(org->right.pexpr);
+        break;
+    case PE_NOT:
+        e->left.pexpr = pexpr_copy(org->left.pexpr);
+        break;
+    }
+
+    return e;
+}
+
+/*
+ * free a pexpr
+ */
+void pexpr_free(struct pexpr *e)
+{
+    if (!e)
+        return;
+
+    switch (e->type) {
+    case PE_SYMBOL:
+        break;
+    case PE_AND:
+    case PE_OR:
+        pexpr_free(e->left.pexpr);
+        pexpr_free(e->right.pexpr);
+        break;
+    case PE_NOT:
+        pexpr_free(e->left.pexpr);
+        break;
+    }
+
+    free(e);
+}
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+/*
+ * pexpr_eliminate_eq() helper
+ */
+static void __pexpr_eliminate_eq(enum pexpr_type type, struct pexpr **ep1, struct pexpr **ep2)
+{
+    /* recurse down to the leaves */
+    if (e1->type == type) {
+        __pexpr_eliminate_eq(type, &e1->left.pexpr, &e2);
+        __pexpr_eliminate_eq(type, &e1->right.pexpr, &e2);
+        return;
+    }
+    if (e2->type == type) {
+        __pexpr_eliminate_eq(type, &e1, &e2->left.pexpr);
+        __pexpr_eliminate_eq(type, &e1, &e2->right.pexpr);
+        return;
+    }
+
+    /* e1 and e2 are leaves. Compare them. */
+    if (e1->type == PE_SYMBOL && e2->type == PE_SYMBOL &&
+        e1->left.fexpr->satval == e2->left.fexpr->satval &&
+        (e1->left.fexpr == const_true || e2->left.fexpr == const_false))
+        return;
+    if (!pexpr_eq(e1, e2))
+        return;
+
+    /* e1 and e2 are equal leaves. Prepare them for elimination. */
+    trans_count++;
+    pexpr_free(e1);
+    pexpr_free(e2);
+    switch (type) {
+    case PE_AND:
+        e1 = pexf(const_true);
+        e2 = pexf(const_true);
+        break;
+    case PE_OR:
+        e1 = pexf(const_false);
+        e2 = pexf(const_false);
+        break;
+    default:
+        ;
+    }
+}
+
+/*
+ * rewrite pexpr ep1 and ep2 to remove operands common to both
+ */
+static void pexpr_eliminate_eq(struct pexpr **ep1, struct pexpr **ep2)
+{
+    if (!e1 || !e2)
+        return;
+
+    switch (e1->type) {
+    case PE_AND:
+    case PE_OR:
+        __pexpr_eliminate_eq(e1->type, ep1, ep2);
+    default:
+        ;
+    }
+    if (e1->type != e2->type) switch (e2->type) {
+    case PE_AND:
+    case PE_OR:
+        __pexpr_eliminate_eq(e2->type, ep1, ep2);
+    default:
+        ;
+    }
+    e1 = pexpr_eliminate_yn(e1);
+    e2 = pexpr_eliminate_yn(e2);
+}
+#undef e1
+#undef e2
+
+/*
+ * check whether 2 pexpr are equal
+ */
+bool pexpr_eq(struct pexpr *e1, struct pexpr *e2)
+{
+    bool res;
+    int old_count;
+
+    if (!e1 || !e2)
+        return false;
+
+    if (e1->type != e2->type)
+        return false;
+
+    switch (e1->type) {
+    case PE_SYMBOL:
+        return e1->left.fexpr->satval == e2->left.fexpr->satval;
+    case PE_AND:
+    case PE_OR:
+        e1 = pexpr_copy(e1);
+        e2 = pexpr_copy(e2);
+        old_count = trans_count;
+        pexpr_eliminate_eq(&e1, &e2);
+        res = (e1->type == PE_SYMBOL && e2->type == PE_SYMBOL &&
+            e1->left.fexpr->satval == e2->left.fexpr->satval);
+        pexpr_free(e1);
+        pexpr_free(e2);
+        trans_count = old_count;
+        return res;
+    case PE_NOT:
+        return pexpr_eq(e1->left.pexpr, e2->left.pexpr);
+    }
+
+    return false;
+}
+
+/*
+ * print a pexpr
+ */
+static void pexpr_print_util(struct pexpr *e, int prevtoken)
+{
+    if (!e)
+        return;
+
+    switch (e->type) {
+    case PE_SYMBOL:
+        printf("%s", str_get(&e->left.fexpr->name));
+        break;
+    case PE_AND:
+        if (prevtoken != PE_AND && prevtoken != -1)
+            printf("(");
+        pexpr_print_util(e->left.pexpr, PE_AND);
+        printf(" && ");
+        pexpr_print_util(e->right.pexpr, PE_AND);
+        if (prevtoken != PE_AND && prevtoken != -1)
+            printf(")");
+        break;
+    case PE_OR:
+        if (prevtoken != PE_OR && prevtoken != -1)
+            printf("(");
+        pexpr_print_util(e->left.pexpr, PE_OR);
+        printf(" || ");
+        pexpr_print_util(e->right.pexpr, PE_OR);
+        if (prevtoken != PE_OR && prevtoken != -1)
+            printf(")");
+        break;
+    case PE_NOT:
+        printf("!");
+        pexpr_print_util(e->left.pexpr, PE_NOT);
+        break;
+    }
+}
+void pexpr_print(char *tag, struct pexpr *e, int prevtoken)
+{
+    printf("%s: ", tag);
+    pexpr_print_util(e, prevtoken);
+    printf("\n");
+}
+
+/*
+ * convert a fexpr to a pexpr
+ */
+struct pexpr * pexf(struct fexpr *fe)
+{
+    struct pexpr *pe = xcalloc(1, sizeof(*pe));
+    pe->type = PE_SYMBOL;
+    pe->left.fexpr = fe;
+    return pe;
+}
+
+static struct pexpr * pexpr_join_or(struct pexpr *e1, struct pexpr *e2)
+{
+    if (pexpr_eq(e1, e2))
+        return pexpr_copy(e1);
+    else
+        return NULL;
+}
+
+static struct pexpr * pexpr_join_and(struct pexpr *e1, struct pexpr *e2)
+{
+    if (pexpr_eq(e1, e2))
+        return pexpr_copy(e1);
+    else
+        return NULL;
+}
+
+/*
+ * pexpr_eliminate_dups() helper.
+ */
+static void pexpr_eliminate_dups1(enum pexpr_type type, struct pexpr **ep1, struct pexpr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+    struct pexpr *tmp;
+
+    /* recurse down to leaves */
+    if (e1->type == type) {
+        pexpr_eliminate_dups1(type, &e1->left.pexpr, &e2);
+        pexpr_eliminate_dups1(type, &e1->right.pexpr, &e2);
+        return;
+    }
+    if (e2->type == type) {
+        pexpr_eliminate_dups1(type, &e1, &e2->left.pexpr);
+        pexpr_eliminate_dups1(type, &e1, &e2->right.pexpr);
+        return;
+    }
+
+    /* e1 and e2 are leaves. Compare them. */
+
+    if (e1 == e2)
+        return;
+
+    switch (e1->type) {
+    case PE_AND:
+    case PE_OR:
+        pexpr_eliminate_dups1(e1->type, &e1, &e1);
+    default:
+        ;
+    }
+
+    switch (type) {
+    case PE_AND:
+        tmp = pexpr_join_and(e1, e2);
+        if (tmp) {
+            pexpr_free(e1);
+            pexpr_free(e2);
+            e1 = pexf(const_true);
+            e2 = tmp;
+            trans_count++;
+        }
+        break;
+    case PE_OR:
+        tmp = pexpr_join_or(e1, e2);
+        if (tmp) {
+            pexpr_free(e1);
+            pexpr_free(e2);
+            e1 = pexf(const_false);
+            e2 = tmp;
+            trans_count++;
+        }
+        break;
+    default:
+        ;
+    }
+
+#undef e1
+#undef e2
+}
+
+/*
+ * eliminate duplicate and redundant operands
+ */
+struct pexpr * pexpr_eliminate_dups(struct pexpr *e)
+{
+    if (!e)
+        return e;
+
+    int oldcount = trans_count;
+    while (true) {
+        trans_count = 0;
+        switch (e->type) {
+        case PE_AND:
+        case PE_OR:
+            pexpr_eliminate_dups1(e->type, &e, &e);
+        default:
+            ;
+        }
+        if (!trans_count)
+            /* no simplification done in this pass. We're done. */
+            break;
+        e = pexpr_eliminate_yn(e);
+    }
+    trans_count = oldcount;
+    return e;
+}
diff --git a/scripts/kconfig/cf_expr.h b/scripts/kconfig/cf_expr.h
new file mode 100644
index 000000000000..cc612866fed4
--- /dev/null
+++ b/scripts/kconfig/cf_expr.h
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#ifndef CF_EXPR_H
+#define CF_EXPR_H
+
+#define fexpr_list_for_each(node, list) \
+    for (node = list->head; node != NULL; node = node->next)
+
+#define fexl_list_for_each(node, list) \
+    fexpr_list_for_each(node, list)
+
+#define pexpr_list_for_each(node, list) \
+    fexpr_list_for_each(node, list)
+
+#define sdv_list_for_each(node, list) \
+    fexpr_list_for_each(node, list)
+
+#define sfix_list_for_each(node, list) \
+    fexpr_list_for_each(node, list)
+
+#define sfl_list_for_each(node, list) \
+    fexpr_list_for_each(node, list)
+
+#define sym_list_for_each(node, list) \
+    fexpr_list_for_each(node, list)
+
+#define defm_list_for_each(node, list) \
+    fexpr_list_for_each(node, list)
+
+#define prop_list_for_each(node, list) \
+    fexpr_list_for_each(node, list)
+
+/* create a fexpr */
+struct fexpr * fexpr_create(int satval, enum fexpr_type type, char *name);
+
+/* create the fexpr for a symbol */
+void sym_create_fexpr (struct symbol *sym);
+
+struct pexpr * expr_calculate_pexpr_both(struct expr *e);
+struct pexpr * expr_calculate_pexpr_y(struct expr *e);
+struct pexpr * expr_calculate_pexpr_m(struct expr *e);
+struct pexpr * expr_calculate_pexpr_y_and(struct expr *a, struct expr *b);
+struct pexpr * expr_calculate_pexpr_m_and(struct expr *a, struct expr *b);
+struct pexpr * expr_calculate_pexpr_both_and(struct expr *a, struct expr *b);
+struct pexpr * expr_calculate_pexpr_y_or(struct expr *a, struct expr *b);
+struct pexpr * expr_calculate_pexpr_m_or(struct expr *a, struct expr *b);
+struct pexpr * expr_calculate_pexpr_both_or(struct expr *a, struct expr *b);
+struct pexpr * expr_calculate_pexpr_y_not(struct expr * e);
+struct pexpr * expr_calculate_pexpr_m_not(struct expr *e);
+struct pexpr * expr_calculate_pexpr_y_equals(struct expr *e);
+struct pexpr * expr_calculate_pexpr_y_unequals(struct expr *e);
+struct pexpr * expr_calculate_pexpr_y_comp(struct expr *e);
+
+/* macro to create a pexpr of type AND */
+struct pexpr * pexpr_and(struct pexpr *a, struct pexpr *b);
+
+/* macro to create a pexpr of type OR */
+struct pexpr * pexpr_or(struct pexpr *a, struct pexpr *b);
+
+/* macro to create a pexpr of type NOT */
+struct pexpr * pexpr_not(struct pexpr *a);
+
+/* check whether a pexpr is in CNF */
+bool pexpr_is_cnf(struct pexpr *e);
+
+/* check whether a pexpr is in NNF */
+bool pexpr_is_nnf(struct pexpr *e);
+
+/* return fexpr_both for a symbol */
+struct pexpr * sym_get_fexpr_both(struct symbol *sym);
+
+/* return fexpr_sel_both for a symbol */
+struct pexpr * sym_get_fexpr_sel_both(struct symbol *sym);
+
+/* create the fexpr of a non-boolean symbol for a specific value */
+struct fexpr * sym_create_nonbool_fexpr(struct symbol *sym, char *value);
+
+/* return the fexpr of a non-boolean symbol for a specific value, NULL if non-existent */
+struct fexpr * sym_get_nonbool_fexpr(struct symbol *sym, char *value);
+
+/*
+ * return the fexpr of a non-boolean symbol for a specific value, if it exists
+ * otherwise create it
+ */
+struct fexpr * sym_get_or_create_nonbool_fexpr(struct symbol *sym, char *value);
+
+/* macro to construct a pexpr for "A implies B" */
+struct pexpr * pexpr_implies(struct pexpr *a, struct pexpr *b);
+
+/* check, if the fexpr is a symbol, a True/False-constant, a literal symbolising a non-boolean or a choice symbol */
+bool fexpr_is_symbol(struct fexpr *e);
+
+/* check whether a pexpr is a symbol or a negated symbol */
+bool pexpr_is_symbol(struct pexpr *e);
+
+/* check whether the fexpr is a constant (true/false) */
+bool fexpr_is_constant(struct fexpr *e);
+
+/* add a fexpr to the satmap */
+void fexpr_add_to_satmap(struct fexpr *e);
+
+/* print an fexpr */
+void fexpr_print(char *tag, struct fexpr *e);
+
+/* write an fexpr into a string (format needed for testing) */
+void fexpr_as_char(struct fexpr *e, struct gstr *s);
+
+/* write pn pexpr into a string */
+void pexpr_as_char_short(struct pexpr *e, struct gstr *s, int parent);
+
+/* write an fexpr into a string (format needed for testing) */
+void pexpr_as_char(struct pexpr *e, struct gstr *s, int parent);
+
+/* check whether a pexpr contains a specific fexpr */
+bool pexpr_contains_fexpr(struct pexpr *e, struct fexpr *fe);
+
+/* init list of fexpr */
+struct fexpr_list * fexpr_list_init(void);
+
+/* init list of fexpr_list */
+struct fexl_list * fexl_list_init(void);
+
+/* init list of pexpr */
+struct pexpr_list * pexpr_list_init(void);
+
+/* init list of symbol_fix */
+struct sfix_list * sfix_list_init(void);
+
+/* init list of sfix_list */
+struct sfl_list * sfl_list_init(void);
+
+/* init list of symbol_dvalue */
+struct sdv_list * sdv_list_init(void);
+
+/* init list of symbols */
+struct sym_list * sym_list_init(void);
+
+/* init list of default_maps */
+struct defm_list * defm_list_init(void);
+
+/* init list of properties */
+struct prop_list *prop_list_init(void);
+
+/* add element to tail of a fexpr_list */
+void fexpr_list_add(struct fexpr_list *list, struct fexpr *fe);
+
+/* add element to tail of a fexl_list */
+void fexl_list_add(struct fexl_list *list, struct fexpr_list *elem);
+
+/* add element to tail of a pexpr_list */
+void pexpr_list_add(struct pexpr_list *list, struct pexpr *e);
+
+/* add element to tail of a sfix_list */
+void sfix_list_add(struct sfix_list *list, struct symbol_fix *fix);
+
+/* add element to tail of a sfl_list */
+void sfl_list_add(struct sfl_list *list, struct sfix_list *elem);
+
+/* add element to tail of a sdv_list */
+void sdv_list_add(struct sdv_list *list, struct symbol_dvalue *sdv);
+
+/* add element to tail of a sym_list */
+void sym_list_add(struct sym_list *list, struct symbol *sym);
+
+/* add element to tail of a defm_list */
+void defm_list_add(struct defm_list *list, struct default_map *map);
+
+/* add element to tail of a prop_list */
+void prop_list_add(struct prop_list *list, struct property *prop);
+
+/* delete an element from a fexpr_list */
+void fexpr_list_delete(struct fexpr_list *list, struct fexpr_node *node);
+
+/* delete an element from a fexpr_list */
+void fexl_list_delete(struct fexl_list *list, struct fexl_node *node);
+
+/* delete the first occurence of elem in an fexl_list */
+void fexl_list_delete_elem(struct fexl_list *list, struct fexpr_list *elem);
+
+/* delete an element from a pexpr_list */
+void pexpr_list_delete(struct pexpr_list *list, struct pexpr_node *node);
+
+/* delete an element from a sfix_list */
+void sfix_list_delete(struct sfix_list *list, struct sfix_node *node);
+
+/* make a shallow copy of a fexpr_list */
+struct fexpr_list * fexpr_list_copy(struct fexpr_list *list);
+
+/* make a shallow copy of a fexpr_list */
+struct fexl_list * fexl_list_copy(struct fexl_list *list);
+
+/* make a shallow copy of a sdv_list */
+struct sdv_list * sdv_list_copy(struct sdv_list *list);
+
+/* make a shallow copy of a sfix_list */
+struct sfix_list * sfix_list_copy(struct sfix_list *list);
+
+/* print a fexpr_list */
+void fexpr_list_print(char *title, struct fexpr_list *list);
+
+/* print a fexl_list */
+void fexl_list_print(char *title, struct fexl_list *list);
+
+/* print a pexpr_list */
+void pexpr_list_print(char *title, struct pexpr_list *list);
+
+/* free an fexpr_list */
+void fexpr_list_free(struct fexpr_list *list);
+
+/* free an fexl_list */
+void fexl_list_free(struct fexl_list *list);
+
+/* free a sdv_list */
+void sdv_list_free(struct sdv_list *list);
+
+/* check whether 2 pexpr are equal */
+bool pexpr_eq(struct pexpr *e1, struct pexpr *e2);
+
+/* copy a pexpr */
+struct pexpr * pexpr_copy(const struct pexpr *org);
+
+/* free a pexpr */
+void pexpr_free(struct pexpr *e);
+
+/* print a pexpr  */
+void pexpr_print(char *tag, struct pexpr *e, int prevtoken);
+
+/* convert a fexpr to a pexpr */
+struct pexpr * pexf(struct fexpr *fe);
+
+/* eliminate duplicate and redundant operands */
+struct pexpr * pexpr_eliminate_dups(struct pexpr *e);
+
+#endif
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 08/12] Add files for RangeFix
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
                   ` (6 preceding siblings ...)
  2021-10-20  9:43 ` [RFC 07/12] Add files for handling expressions Thorsten Berger
@ 2021-10-20  9:44 ` Thorsten Berger
  2021-10-20  9:45 ` [RFC 09/12] Add files with utility functions Thorsten Berger
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:44 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/cf_rangefix.c | 1017 +++++++++++++++++++++++++++++++++
 scripts/kconfig/cf_rangefix.h |   18 +
 2 files changed, 1035 insertions(+)
 create mode 100644 scripts/kconfig/cf_rangefix.c
 create mode 100644 scripts/kconfig/cf_rangefix.h

diff --git a/scripts/kconfig/cf_rangefix.c b/scripts/kconfig/cf_rangefix.c
new file mode 100644
index 000000000000..9b5773188175
--- /dev/null
+++ b/scripts/kconfig/cf_rangefix.c
@@ -0,0 +1,1017 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "configfix.h"
+
+#define MAX_DIAGNOSES 3
+#define MAX_SECONDS 120
+#define PRINT_UNSAT_CORE true
+#define PRINT_DIAGNOSES false
+#define PRINT_DIAGNOSIS_FOUND true
+#define MINIMISE_DIAGNOSES false
+#define MINIMISE_UNSAT_CORE true
+
+static struct fexl_list *diagnoses;
+static struct sfl_list *diagnoses_symbol;
+
+static struct fexl_list * generate_diagnoses(PicoSAT *pico);
+
+static void add_fexpr_to_constraint_set(struct fexpr_list *C);
+static void set_assumptions(PicoSAT *pico, struct fexpr_list *c);
+static void fexpr_add_assumption(PicoSAT *pico, struct fexpr *e, int satval);
+static struct fexpr_list * get_unsat_core_soft(PicoSAT *pico);
+static struct fexpr_list * minimise_unsat_core(PicoSAT *pico, struct fexpr_list *C);
+
+
+static struct fexpr_list * get_difference(struct fexpr_list *C, struct fexpr_list *E0);
+static bool has_intersection(struct fexpr_list *e, struct fexpr_list *X);
+static struct fexpr_list * fexpr_list_union(struct fexpr_list *A, struct fexpr_list *B);
+static struct fexl_list * fexl_list_union(struct fexl_list *A, struct fexl_list *B);
+static bool is_subset_of(struct fexpr_list *A, struct fexpr_list *B);
+static void print_unsat_core(struct fexpr_list *list);
+static bool diagnosis_contains_fexpr(struct fexpr_list *diagnosis, struct fexpr *e);
+static bool diagnosis_contains_symbol(struct sfix_list *diagnosis, struct symbol *sym);
+
+static void print_diagnoses(struct fexl_list *diag);
+static void print_diagnoses_symbol(struct sfl_list *diag_sym);
+
+static struct sfl_list * convert_diagnoses(struct fexl_list *diagnoses);
+static struct sfix_list * convert_diagnosis(struct fexpr_list *diagnosis);
+static struct symbol_fix * symbol_fix_create(struct fexpr *e, enum symbolfix_type type, struct fexpr_list *diagnosis);
+static struct sfl_list * minimise_diagnoses(PicoSAT *pico, struct fexl_list *diagnoses);
+
+static tristate calculate_new_tri_val(struct fexpr *e, struct fexpr_list *diagnosis);
+static const char * calculate_new_string_value(struct fexpr *e, struct fexpr_list *diagnosis);
+
+/* count assumptions, only used for debugging */
+static unsigned int nr_of_assumptions = 0, nr_of_assumptions_true = 0;
+
+/* -------------------------------------- */
+
+struct sfl_list * rangefix_run(PicoSAT *pico)
+{
+    printd("Starting RangeFix...\n");
+    printd("Generating diagnoses...");
+    clock_t start, end;
+    double time;
+    start = clock();
+
+    /* generate the diagnoses */
+    diagnoses = generate_diagnoses(pico);
+
+    end = clock();
+    time = ((double) (end - start)) / CLOCKS_PER_SEC;
+    printd("Generating diagnoses...done. (%.6f secs.)\n", time);
+
+    if (PRINT_DIAGNOSES) {
+        printd("Diagnoses (only for debugging):\n");
+        print_diagnoses(diagnoses);
+        printd("\n");
+    }
+
+    /* convert diagnoses of fexpr to diagnoses of symbols */
+    if (MINIMISE_DIAGNOSES)
+        diagnoses_symbol = minimise_diagnoses(pico, diagnoses);
+    else
+        diagnoses_symbol = convert_diagnoses(diagnoses);
+
+    printd("\n");
+
+    return diagnoses_symbol;
+}
+
+/*
+ * generate the diagnoses
+ */
+static struct fexl_list * generate_diagnoses(PicoSAT *pico)
+{
+    struct fexpr_list *C = fexpr_list_init();
+    struct fexl_list *E = fexl_list_init();
+    struct fexl_list *R = fexl_list_init();
+    struct fexpr_list *X, *e, *x_set, *E1, *E2;
+    struct fexl_list *E_R_Union;
+
+    /* create constraint set C */
+    add_fexpr_to_constraint_set(C);
+
+    if (PRINT_UNSAT_CORE)
+        printd("\n");
+
+    /* init E with an empty diagnosis */
+    struct fexpr_list *empty_diagnosis = fexpr_list_init();
+    fexl_list_add(E, empty_diagnosis);
+
+    /* start the clock */
+    clock_t start_t, end_t;
+    double time_t;
+    start_t = clock();
+
+    while (E->size > 0) {
+        /* get random diagnosis */
+        struct fexpr_list *E0 = E->head->elem;
+
+        /* calculate C\E0 */
+        struct fexpr_list *c = get_difference(C, E0);
+
+        /* set assumptions */
+        nr_of_assumptions = 0;
+        nr_of_assumptions_true = 0;
+        set_assumptions(pico, c);
+
+        int res = picosat_sat(pico, -1);
+
+        if (res == PICOSAT_SATISFIABLE) {
+            if (PRINT_DIAGNOSIS_FOUND && CFDEBUG)
+                fexpr_list_print("DIAGNOSIS FOUND", E0);
+
+            fexl_list_delete(E, E->head);
+            if (E0->size > 0)
+                fexl_list_add(R, E0);
+            else
+                fexpr_list_free(E0);
+
+            fexpr_list_free(c);
+
+            if (R->size >= MAX_DIAGNOSES)
+                goto DIAGNOSES_FOUND;
+
+            continue;
+
+        } else if (res == PICOSAT_UNSATISFIABLE) {
+
+        } else if (res == PICOSAT_UNKNOWN) {
+            printd("UNKNOWN\n");
+        } else {
+            perror("Doh.");
+        }
+
+        /* check elapsed time */
+        end_t = clock();
+        time_t = ((double) (end_t - start_t)) / CLOCKS_PER_SEC;
+        if (time_t > (double) MAX_SECONDS)
+            goto DIAGNOSES_FOUND;
+
+        /* get unsat core from SAT solver */
+        X = get_unsat_core_soft(pico);
+
+        /* minimise the unsat core */
+        if (MINIMISE_UNSAT_CORE)
+            X = minimise_unsat_core(pico, X);
+
+        if (PRINT_UNSAT_CORE)
+            print_unsat_core(X);
+
+        struct fexl_node *node, *tmp;
+        for (node = E->head; node != NULL;) {
+            /* get partial diagnosis */
+            e = node->elem;
+
+            /* check, if there is an intersection between e and X
+             * if there is, go to the next partial diagnosis */
+            if (has_intersection(e, X)) {
+                node = node->next;
+                continue;
+            }
+
+            /* for each fexpr in the core */
+            struct fexpr_node *fnode;
+            fexpr_list_for_each(fnode, X) {
+                struct fexpr *x = fnode->elem;
+
+                /* create {x} */
+                x_set = fexpr_list_init();
+                fexpr_list_add(x_set, x);
+
+                /* create E' = e ∪ {x} */
+                E1 = fexpr_list_union(e, x_set);
+
+                /* create (E\e) ∪ R */
+                E_R_Union = fexl_list_copy(E);
+                fexl_list_delete_elem(E_R_Union, e);
+                E_R_Union = fexl_list_union(E_R_Union, R);
+
+                bool E2_subset_of_E1 = false;
+
+                /* E" ∈ (E\e) ∪ R */
+                struct fexl_node *lnode;
+                fexl_list_for_each(lnode, E_R_Union) {
+                    E2 = lnode->elem;
+
+                    /* E" ⊆ E' ? */
+                    if (is_subset_of(E2, E1)) {
+                        E2_subset_of_E1 = true;
+                        break;
+                    }
+                }
+
+                fexl_list_free(E_R_Union);
+
+                /* ∄ E" ⊆ E' */
+                if (!E2_subset_of_E1)
+                    fexl_list_add(E, E1);
+                else
+                    fexpr_list_free(E1);
+            }
+
+            fexpr_list_free(e);
+
+            tmp = node->next;
+            fexl_list_delete(E, node);
+            node = tmp;
+        }
+        fexpr_list_free(X);
+        fexpr_list_free(c);
+    }
+
+DIAGNOSES_FOUND:
+    fexpr_list_free(C);
+    fexl_list_free(E);
+
+    return R;
+}
+
+/*
+ * add the fexpr to the constraint set C
+ */
+static void add_fexpr_to_constraint_set(struct fexpr_list *C)
+{
+    unsigned int i, nr_sym = 0, nr_fexpr = 0;
+    struct symbol *sym;
+    for_all_symbols(i, sym) {
+        /* must be a proper symbol */
+        if (sym->type == S_UNKNOWN)
+            continue;
+
+        /* don't need the conflict symbols
+         * they are handled seperately */
+        if (sym_is_sdv(sdv_symbols, sym))
+            continue;
+
+        /* must have a prompt and a name */
+        if (!sym->name || !sym_has_prompt(sym))
+            continue;
+
+        nr_sym++;
+
+        if (sym->type == S_BOOLEAN) {
+            fexpr_list_add(C, sym->fexpr_y);
+            nr_fexpr++;
+        } else if (sym->type == S_TRISTATE) {
+            fexpr_list_add(C, sym->fexpr_y);
+            fexpr_list_add(C, sym->fexpr_m);
+            nr_fexpr += 2;
+        } else if (sym->type == S_INT || sym->type == S_HEX || sym->type == S_STRING) {
+            struct fexpr_node *node;
+            fexpr_list_for_each(node, sym->nb_vals) {
+                fexpr_list_add(C, node->elem);
+                nr_fexpr++;
+            }
+        } else {
+            perror("Error adding variables to constraint set C.");
+        }
+    }
+}
+
+/*
+ * check whether the fexpr symbolises the no-value-set fexpr for a non-boolean symbol
+ */
+static bool fexpr_is_novalue(struct fexpr *e)
+{
+    if (!sym_is_nonboolean(e->sym))
+        return false;
+
+    return e == e->sym->nb_vals->head->elem;
+}
+
+static void set_assumptions_sdv(PicoSAT *pico, struct sdv_list *arr)
+{
+    struct symbol_dvalue *sdv;
+    struct sdv_node *node;
+    struct symbol *sym;
+
+    sdv_list_for_each(node, arr) {
+        sdv = node->elem;
+        sym = sdv->sym;
+
+        int lit_y = sym->fexpr_y->satval;
+
+        if (sym->type == S_BOOLEAN) {
+            switch (sdv->tri) {
+            case yes:
+                picosat_assume(pico, lit_y);
+                sym->fexpr_y->assumption = true;
+                nr_of_assumptions_true++;
+                break;
+            case no:
+                picosat_assume(pico, -lit_y);
+                sym->fexpr_y->assumption = false;
+                break;
+            case mod:
+                perror("Should not happen.\n");
+            }
+            nr_of_assumptions++;
+        } else if (sym->type == S_TRISTATE) {
+            int lit_m = sym->fexpr_m->satval;
+            switch (sdv->tri) {
+            case yes:
+                picosat_assume(pico, lit_y);
+                sym->fexpr_y->assumption = true;
+                picosat_assume(pico, -lit_m);
+                sym->fexpr_m->assumption = false;
+                nr_of_assumptions_true++;
+                break;
+            case mod:
+                picosat_assume(pico, -lit_y);
+                sym->fexpr_y->assumption = false;
+                picosat_assume(pico, lit_m);
+                sym->fexpr_m->assumption = true;
+                nr_of_assumptions_true++;
+                break;
+            case no:
+                picosat_assume(pico, -lit_y);
+                sym->fexpr_y->assumption = false;
+                picosat_assume(pico, -lit_m);
+                sym->fexpr_y->assumption = false;
+            }
+            nr_of_assumptions += 2;
+        }
+    }
+}
+
+/*
+ * set the assumptions for the next run of Picosat
+ */
+static void set_assumptions(PicoSAT *pico, struct fexpr_list *c)
+{
+    struct fexpr_node *node;
+    fexpr_list_for_each(node, c)
+        fexpr_add_assumption(pico, node->elem, node->elem->satval);
+
+    /* set assumptions for the conflict-symbols */
+    set_assumptions_sdv(pico, sdv_symbols);
+}
+
+/*
+ * set the assumtption for a fexpr for the next run of Picosat
+ */
+static void fexpr_add_assumption(PicoSAT *pico, struct fexpr *e, int satval)
+{
+    struct symbol *sym = e->sym;
+
+    if (sym->type == S_BOOLEAN) {
+        int tri_val = sym_get_tristate_value(sym);
+
+        if (tri_val == yes) {
+            picosat_assume(pico, satval);
+            e->assumption = true;
+            nr_of_assumptions_true++;
+        } else {
+            picosat_assume(pico, -satval);
+            e->assumption = false;
+        }
+        nr_of_assumptions++;
+    }
+
+    if (sym->type == S_TRISTATE) {
+        int tri_val = sym_get_tristate_value(sym);
+
+        if (e->tri == yes) {
+            if (tri_val == yes) {
+                picosat_assume(pico, satval);
+                e->assumption = true;
+                nr_of_assumptions_true++;
+            } else {
+                picosat_assume(pico, -satval);
+                e->assumption = false;
+            }
+        } else if (e->tri == mod) {
+            if (tri_val == mod) {
+                picosat_assume(pico, satval);
+                e->assumption = true;
+                nr_of_assumptions_true++;
+            } else {
+                picosat_assume(pico, -satval);
+                e->assumption = false;
+            }
+        }
+        nr_of_assumptions++;
+    }
+
+    if (sym->type == S_INT || sym->type == S_HEX || sym->type == S_STRING) {
+
+        char *string_val = (char *) sym_get_string_value(sym);
+
+        if (sym->type == S_STRING && !strcmp(string_val, ""))
+            return;
+
+        /* check, if e symbolises the no-value-set fexpr */
+        if (fexpr_is_novalue(e)) {
+            if (!sym_nonbool_has_value_set(sym)) {
+                picosat_assume(pico, satval);
+                e->assumption = true;
+                nr_of_assumptions_true++;
+            } else {
+                picosat_assume(pico, -satval);
+                e->assumption = false;
+            }
+        }
+        /* check whena string-symbol has value "" */
+        else if (sym->type == S_STRING && !strcmp(string_val, "")) {
+            if (sym_nonbool_has_value_set(sym)) {
+                picosat_assume(pico, satval);
+                e->assumption = true;
+                nr_of_assumptions_true++;
+            } else {
+                picosat_assume(pico, -satval);
+                e->assumption = false;
+            }
+        }
+        else {
+            if (!strcmp(str_get(&e->nb_val), string_val)) {
+                picosat_assume(pico, satval);
+                e->assumption = true;
+                nr_of_assumptions_true++;
+            } else {
+                picosat_assume(pico, -satval);
+                e->assumption = false;
+            }
+        }
+        nr_of_assumptions++;
+    }
+}
+
+/*
+ * get the unsatisfiable soft constraints from the last run of Picosat
+ */
+static struct fexpr_list * get_unsat_core_soft(PicoSAT* pico)
+{
+    struct fexpr_list *ret = fexpr_list_init();
+    struct fexpr *e;
+
+    int *lit = malloc(sizeof(int));
+    const int *i = picosat_failed_assumptions(pico);
+    *lit = abs(*i++);
+
+    while (*lit != 0) {
+        e = &satmap[*lit];
+
+        if (!sym_is_sdv(sdv_symbols, e->sym))
+            fexpr_list_add(ret, e);
+
+        *lit = abs(*i++);
+    }
+
+    return ret;
+}
+
+/*
+ * minimise the unsat core C
+ */
+static struct fexpr_list * minimise_unsat_core(PicoSAT *pico, struct fexpr_list *C)
+{
+    /* no need to check further */
+    if (C->size == 1)
+        return C;
+
+    struct fexpr_list *c_set;
+    struct fexpr_node *node, *tmp;
+
+    for (node = C->head; node != NULL;) {
+        if (C->size == 1)
+            return C;
+
+        /* create C\c */
+        c_set = fexpr_list_init();
+        fexpr_list_add(c_set, node->elem);
+        struct fexpr_list *t = get_difference(C, c_set);
+
+        /* invoke PicoSAT */
+        set_assumptions(pico, t);
+
+        int res = picosat_sat(pico, -1);
+
+        tmp = node->next;
+
+        if (res == PICOSAT_UNSATISFIABLE)
+            fexpr_list_delete(C, node);
+
+        node = tmp;
+
+        fexpr_list_free(c_set);
+        fexpr_list_free(t);
+    }
+
+    return C;
+}
+
+
+/*
+ * Calculate C\E0
+ */
+static struct fexpr_list * get_difference(struct fexpr_list *C, struct fexpr_list *E0)
+{
+    struct fexpr_list *ret = fexpr_list_init();
+    struct fexpr_node *node1, *node2;
+    bool found;
+
+    fexpr_list_for_each(node1, C) {
+        found = false;
+        fexpr_list_for_each(node2, E0) {
+            if (node1->elem->satval == node2->elem->satval) {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            fexpr_list_add(ret, node1->elem);
+    }
+
+    return ret;
+}
+
+/*
+ * check, if there is an intersection between e and X
+ */
+static bool has_intersection(struct fexpr_list *e, struct fexpr_list *X)
+{
+    struct fexpr_node *node1, *node2;
+    fexpr_list_for_each(node1, e)
+        fexpr_list_for_each(node2, X)
+            if (node1->elem->satval == node2->elem->satval)
+                return true;
+
+    return false;
+}
+
+/*
+ * get the union of 2 fexpr_list
+ */
+static struct fexpr_list * fexpr_list_union(struct fexpr_list *A, struct fexpr_list *B)
+{
+    struct fexpr_list *ret = fexpr_list_copy(A);
+    struct fexpr_node *node1, *node2;
+    bool found;
+
+    fexpr_list_for_each(node2, B) {
+        found = false;
+        fexpr_list_for_each(node1, A) {
+            if (node2->elem->satval == node1->elem->satval) {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            fexpr_list_add(ret, node2->elem);
+    }
+
+    return ret;
+}
+
+/*
+ * get the union of 2 fexl_list
+ */
+static struct fexl_list * fexl_list_union(struct fexl_list *A, struct fexl_list *B)
+{
+    struct fexl_list *ret = fexl_list_copy(A);
+    struct fexl_node *node1, *node2;
+    bool found;
+
+    fexl_list_for_each(node2, B) {
+        found = false;
+        fexl_list_for_each(node1, A) {
+            if (node2->elem == node1->elem) {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            fexl_list_add(ret, node2->elem);
+    }
+
+    return ret;
+}
+
+/*
+ * check, whether A is a subset of B
+ */
+static bool is_subset_of(struct fexpr_list *A, struct fexpr_list *B)
+{
+    struct fexpr_node *node1, *node2;
+    bool found;
+
+    fexpr_list_for_each(node1, A) {
+        found = false;
+        fexpr_list_for_each(node2, B) {
+            if (node1->elem->satval == node2->elem->satval) {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            return false;
+    }
+
+    return true;
+}
+
+/*
+ * print an unsat core
+ */
+static void print_unsat_core(struct fexpr_list *list)
+{
+    struct fexpr_node *node;
+    printd("Unsat core: [");
+
+    fexpr_list_for_each(node, list) {
+        printd("%s", str_get(&node->elem->name));
+        printd(" <%s>", node->elem->assumption == true ? "T" : "F");
+        if (node->next != NULL)
+            printd(", ");
+    }
+
+    printd("]\n");
+}
+
+
+/*
+ * check if a diagnosis contains a fexpr
+ */
+static bool diagnosis_contains_fexpr(struct fexpr_list *diagnosis, struct fexpr *e)
+{
+    struct fexpr_node *node;
+
+    fexpr_list_for_each(node, diagnosis)
+        if (node->elem->satval == e->satval)
+            return true;
+
+    return false;
+}
+
+/*
+ * check if a diagnosis contains a symbol
+ */
+static bool diagnosis_contains_symbol(struct sfix_list *diagnosis, struct symbol *sym)
+{
+    struct sfix_node *node;
+
+    sfix_list_for_each(node, diagnosis)
+        if (sym == node->elem->sym)
+            return true;
+
+    return false;
+}
+
+/*
+ * print the diagnoses of type fexpr_list
+ */
+static void print_diagnoses(struct fexl_list *diag)
+{
+    struct fexl_node *lnode;
+    unsigned int i = 1;
+
+    fexl_list_for_each(lnode, diag) {
+        printd("%d: [", i++);
+        struct fexpr_node *node;
+        fexpr_list_for_each(node, lnode->elem) {
+            char *new_val = node->elem->assumption ? "false" : "true";
+            printd("%s => %s", str_get(&node->elem->name), new_val);
+            if (node->next != NULL)
+                printd(", ");
+        }
+        printd("]\n");
+    }
+}
+
+/*
+ * print a single diagnosis of type symbol_fix
+ */
+void print_diagnosis_symbol(struct sfix_list *diag_sym)
+{
+    struct symbol_fix *fix;
+    struct sfix_node *node;
+
+    printd("[");
+
+    sfix_list_for_each(node, diag_sym) {
+        fix = node->elem;
+
+        if (fix->type == SF_BOOLEAN) {
+            printd("%s => %s", fix->sym->name, tristate_get_char(fix->tri));
+        } else if (fix->type == SF_NONBOOLEAN) {
+            printd("%s => %s", fix->sym->name, str_get(&fix->nb_val));
+        } else {
+            perror("NB not yet implemented.");
+        }
+
+        if (node->next != NULL)
+            printd(", ");
+    }
+    printd("]\n");
+}
+
+/*
+ * print the diagnoses of type symbol_fix
+ */
+static void print_diagnoses_symbol(struct sfl_list *diag_sym)
+{
+    struct sfl_node *arr;
+    unsigned int i = 1;
+
+    sfl_list_for_each(arr, diag_sym) {
+        printd("%d: ", i++);
+        print_diagnosis_symbol(arr->elem);
+    }
+}
+
+/*
+ * convert a single diagnosis of fexpr into a diagnosis of symbols
+ */
+static struct sfix_list * convert_diagnosis(struct fexpr_list *diagnosis)
+{
+    struct sfix_list *diagnosis_symbol = sfix_list_init();
+    struct fexpr *e;
+    struct symbol_fix *fix;
+    struct symbol_dvalue *sdv;
+
+    /* set the values for the conflict symbols */
+    struct sdv_node *snode;
+    sdv_list_for_each(snode, sdv_symbols) {
+        sdv = snode->elem;
+        fix = xcalloc(1, sizeof(*fix));
+        fix->sym = sdv->sym;
+        fix->type = SF_BOOLEAN;
+        fix->tri = sdv->tri;
+        sfix_list_add(diagnosis_symbol, fix);
+    }
+
+    struct fexpr_node * fnode;
+    fexpr_list_for_each(fnode, diagnosis) {
+        e = fnode->elem;
+
+        /* diagnosis already contains symbol, so continue */
+        if (diagnosis_contains_symbol(diagnosis_symbol, e->sym))
+            continue;
+
+        enum symbolfix_type type;
+        if (sym_is_boolean(e->sym))
+            type = SF_BOOLEAN;
+        else if (sym_is_nonboolean(e->sym))
+            type = SF_NONBOOLEAN;
+        else
+            type = SF_DISALLOWED;
+        fix = symbol_fix_create(e, type, diagnosis);
+
+        sfix_list_add(diagnosis_symbol, fix);
+    }
+
+    return diagnosis_symbol;
+}
+
+/*
+ * convert the diagnoses of fexpr into diagnoses of symbols
+ * it is easier to handle symbols when applying fixes
+ */
+static struct sfl_list * convert_diagnoses(struct fexl_list *diag_arr)
+{
+    diagnoses_symbol = sfl_list_init();
+
+    struct fexl_node *lnode;
+    fexl_list_for_each(lnode, diag_arr) {
+        struct sfix_list *fix = convert_diagnosis(lnode->elem);
+        sfl_list_add(diagnoses_symbol, fix);
+    }
+
+    return diagnoses_symbol;
+}
+
+/*
+ * create a symbol_fix given a fexpr
+ */
+static struct symbol_fix * symbol_fix_create(struct fexpr *e, enum symbolfix_type type, struct fexpr_list *diagnosis)
+{
+    struct symbol_fix *fix = malloc(sizeof(struct symbol_fix));
+    fix->sym = e->sym;
+    fix->type = type;
+
+    switch(type) {
+    case SF_BOOLEAN:
+        fix->tri = calculate_new_tri_val(e, diagnosis);
+        break;
+    case SF_NONBOOLEAN:
+        fix->nb_val = str_new();
+        str_append(&fix->nb_val, calculate_new_string_value(e, diagnosis));
+        break;
+    default:
+        perror("Illegal symbolfix_type.\n");
+    }
+
+    return fix;
+}
+
+/*
+ * remove symbols from the diagnosis, which will be set automatically:
+ * 1. symbol gets selected
+ * 2. choice symbol gets enabled/disabled automatically
+ * 3. symbol uses a default value
+ */
+static struct sfl_list * minimise_diagnoses(PicoSAT *pico, struct fexl_list *diagnoses)
+{
+    clock_t start, end;
+    double time;
+
+    printd("Minimising diagnoses...");
+
+    start = clock();
+
+    struct fexpr_list *d;
+    struct sfix_list *diagnosis_symbol;
+    struct sfl_list *diagnoses_symbol = sfl_list_init();
+    struct fexpr *e;
+    int satval, deref = 0;
+    struct symbol_fix *fix;
+
+    /* create soft constraint set C */
+    struct fexpr_list *C = fexpr_list_init();
+    add_fexpr_to_constraint_set(C);
+
+    struct fexl_node *flnode;
+    fexl_list_for_each(flnode, diagnoses) {
+        d = flnode->elem;
+
+        /* set assumptions for those symbols that don't need to be changed */
+        set_assumptions(pico, get_difference(C, d));
+
+        /* flip the assumptions from the diagnosis */
+        struct fexpr_node *fnode;
+        fexpr_list_for_each(fnode, d) {
+            e = fnode->elem;
+            satval = e->assumption ? -(e->satval) : e->satval;
+            picosat_assume(pico, satval);
+        }
+
+        int res = picosat_sat(pico, -1);
+        if (res != PICOSAT_SATISFIABLE)
+            perror("Diagnosis not satisfiable (minimise).");
+
+        diagnosis_symbol = convert_diagnosis(d);
+
+        /* check if symbol gets selected */
+        struct sfix_node *snode;
+        for (snode = diagnosis_symbol->head; snode != NULL;) {
+            fix = snode->elem;
+
+            /* symbol is never selected, continue */
+            if (!fix->sym->fexpr_sel_y) {
+                snode = snode->next;
+                continue;
+            }
+
+            /* check, whether the symbol was selected anyway */
+            if (fix->sym->type == S_BOOLEAN && fix->tri == yes) {
+                deref = picosat_deref(pico, fix->sym->fexpr_sel_y->satval);
+            } else if (fix->sym->type == S_TRISTATE && fix->tri == yes) {
+                deref = picosat_deref(pico, fix->sym->fexpr_sel_y->satval);
+            } else if (fix->sym->type == S_TRISTATE && fix->tri == mod) {
+                deref = picosat_deref(pico, fix->sym->fexpr_sel_m->satval);
+            }
+
+            if (deref == 1) {
+                struct sfix_node *tmp = snode->next;
+                sfix_list_delete(diagnosis_symbol, snode);
+                snode = tmp;
+            } else {
+                deref = 0;
+                snode = snode->next;
+            }
+        }
+        sfl_list_add(diagnoses_symbol, diagnosis_symbol);
+    }
+
+    end = clock();
+    time = ((double) (end - start)) / CLOCKS_PER_SEC;
+
+    printd("done. (%.6f secs.)\n", time);
+
+    return diagnoses_symbol;
+}
+
+/*
+ * list the diagnoses and let user choose a diagnosis to be applied
+ */
+struct sfix_list * choose_fix(struct sfl_list *diag)
+{
+    printd("=== GENERATED DIAGNOSES ===\n");
+    printd("0: No changes wanted\n");
+    print_diagnoses_symbol(diag);
+
+    int choice;
+    printd("\n> Choose option: ");
+    scanf("%d", &choice);
+
+    /* no changes wanted */
+    if (choice == 0)
+        return NULL;
+
+    /* invalid choice */
+    if (choice > diag->size)
+        return NULL;
+
+    unsigned int counter;
+    struct sfl_node *node = diag->head;
+    for (counter = 1; counter < choice; counter++)
+        node = node->next;
+
+    return node->elem;
+}
+
+
+/*
+ * calculate the new value for a boolean symbol given a diagnosis and an fexpr
+ */
+static tristate calculate_new_tri_val(struct fexpr *e, struct fexpr_list *diagnosis)
+{
+    assert(sym_is_boolean(e->sym));
+
+    /* return the opposite of the last assumption for booleans */
+    if (e->sym->type == S_BOOLEAN)
+        return e->assumption ? no : yes;
+
+    /* new values for tristate must be deduced from the diagnosis */
+    if (e->sym->type == S_TRISTATE) {
+        /* fexpr_y */
+        if (e->tri == yes) {
+            if (e->assumption == true)
+                /*
+                 * if diagnosis contains fexpr_m, fexpr_m was false
+                 * => new value is mod
+                 */
+                return diagnosis_contains_fexpr(diagnosis, e->sym->fexpr_m) ? mod : no;
+            else if (e->assumption == false)
+                /*
+                 * if fexpr_y is set to true, the new value must be yes
+                 */
+                return yes;
+        }
+        /* fexpr_m */
+        if (e->tri == mod) {
+            if (e->assumption == true)
+                /*
+                 * if diagnosis contains fexpr_y, fexpr_y was false
+                 * => new value is yes
+                 */
+                return diagnosis_contains_fexpr(diagnosis, e->sym->fexpr_m) ? yes : no;
+            else if (e->assumption == false)
+                /*
+                 * if diagnosis contains fexpr_m, the new value must be mod
+                 */
+                return mod;
+        }
+        perror("Should not get here.\n");
+    }
+
+    perror("Error calculating new tristate value.\n");
+    return no;
+}
+
+/*
+ * calculate the new value for a non-boolean symbol given a diagnosis and an fexpr
+ */
+static const char * calculate_new_string_value(struct fexpr *e, struct fexpr_list *diagnosis)
+{
+    assert(sym_is_nonboolean(e->sym));
+
+    /* if assumption was false before, this is the new value because only 1 variable can be true */
+    if (e->assumption == false)
+        return str_get(&e->nb_val);
+
+    /* a diagnosis always contains 2 variables for the same non-boolean symbol
+    * one is set to true, the other to false
+    * otherwise you'd set 2 variables to true, which is not allowed */
+    struct fexpr_node *node;
+    struct fexpr *e2;
+    fexpr_list_for_each(node, diagnosis) {
+        e2 = node->elem;
+
+        /* not interested in other symbols or the same fexpr */
+        if (e->sym != e2->sym || e->satval == e2->satval)
+            continue;
+
+        return str_get(&e2->nb_val);
+    }
+
+    perror("Error calculating new string value.\n");
+    return "";
+}
diff --git a/scripts/kconfig/cf_rangefix.h b/scripts/kconfig/cf_rangefix.h
new file mode 100644
index 000000000000..0daf29cb70b9
--- /dev/null
+++ b/scripts/kconfig/cf_rangefix.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#ifndef CF_RANGEFIX_H
+#define CF_RANGEFIX_H
+
+/* initialize RangeFix and return the diagnoses */
+struct sfl_list * rangefix_run(PicoSAT *pico);
+
+/* ask user which fix to apply */
+struct sfix_list * choose_fix(struct sfl_list *diag);
+
+/* print a single diagnosis of type symbol_fix */
+void print_diagnosis_symbol(struct sfix_list *diag_sym);
+
+#endif
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 09/12] Add files with utility functions
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
                   ` (7 preceding siblings ...)
  2021-10-20  9:44 ` [RFC 08/12] Add files for RangeFix Thorsten Berger
@ 2021-10-20  9:45 ` Thorsten Berger
  2021-10-20  9:46 ` [RFC 10/12] Add tools Thorsten Berger
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:45 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/cf_satutils.c | 536 ++++++++++++++++++++++++++++++++++
 scripts/kconfig/cf_satutils.h |  30 ++
 scripts/kconfig/cf_utils.c    | 510 ++++++++++++++++++++++++++++++++
 scripts/kconfig/cf_utils.h    |  90 ++++++
 4 files changed, 1166 insertions(+)
 create mode 100644 scripts/kconfig/cf_satutils.c
 create mode 100644 scripts/kconfig/cf_satutils.h
 create mode 100644 scripts/kconfig/cf_utils.c
 create mode 100644 scripts/kconfig/cf_utils.h

diff --git a/scripts/kconfig/cf_satutils.c b/scripts/kconfig/cf_satutils.c
new file mode 100644
index 000000000000..84d8c46ad686
--- /dev/null
+++ b/scripts/kconfig/cf_satutils.c
@@ -0,0 +1,536 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "configfix.h"
+
+static void unfold_cnf_clause(struct pexpr *e);
+static void build_cnf_tseytin(struct pexpr *e);
+
+static void build_cnf_tseytin_top_and(struct pexpr *e);
+static void build_cnf_tseytin_top_or(struct pexpr *e);
+
+static void build_cnf_tseytin_tmp(struct pexpr *e, struct fexpr *t);
+static void build_cnf_tseytin_and(struct pexpr *e, struct fexpr *t);
+static void build_cnf_tseytin_or(struct pexpr *e, struct fexpr *t);
+static int pexpr_satval(struct pexpr *e);
+
+static PicoSAT *pico;
+
+/* -------------------------------------- */
+
+/*
+ * initialize PicoSAT
+ */
+PicoSAT * initialize_picosat(void)
+{
+    printd("\nInitializing PicoSAT...");
+    PicoSAT *pico = picosat_init();
+    picosat_enable_trace_generation(pico);
+    printd("done.\n");
+
+    return pico;
+}
+
+/*
+ * construct the CNF-clauses from the constraints
+ */
+void construct_cnf_clauses(PicoSAT *p)
+{
+    pico = p;
+    unsigned int i;
+    struct symbol *sym;
+
+    /* adding unit-clauses for constants */
+    sat_add_clause(2, pico, -(const_false->satval));
+    sat_add_clause(2, pico, const_true->satval);
+
+    for_all_symbols(i, sym) {
+        if (sym->type == S_UNKNOWN)
+            continue;
+
+        struct pexpr_node *node;
+        pexpr_list_for_each(node, sym->constraints) {
+            if (pexpr_is_cnf(node->elem))
+                unfold_cnf_clause(node->elem);
+            else
+                build_cnf_tseytin(node->elem);
+        }
+    }
+}
+
+/*
+ * helper function to add an expression to a CNF-clause
+ */
+static void unfold_cnf_clause_util(struct pexpr *e)
+{
+    switch (e->type) {
+    case PE_SYMBOL:
+        picosat_add(pico, e->left.fexpr->satval);
+        break;
+    case PE_OR:
+        unfold_cnf_clause_util(e->left.pexpr);
+        unfold_cnf_clause_util(e->right.pexpr);
+        break;
+    case PE_NOT:
+        picosat_add(pico, -(e->left.pexpr->left.fexpr->satval));
+        break;
+    default:
+        perror("Not in CNF, FE_EQUALS.");
+    }
+}
+
+/*
+ * extract the variables from a pexpr in CNF
+ */
+static void unfold_cnf_clause(struct pexpr *e)
+{
+    if (!pexpr_is_cnf(e))
+        return;
+
+    unfold_cnf_clause_util(e);
+
+    picosat_add(pico, 0);
+}
+
+/*
+ * build CNF-clauses for a pexpr not in CNF
+ */
+static void build_cnf_tseytin(struct pexpr *e)
+{
+    switch (e->type) {
+    case PE_AND:
+        build_cnf_tseytin_top_and(e);
+        break;
+    case PE_OR:
+        build_cnf_tseytin_top_or(e);
+        break;
+    default:
+        perror("Expression not a propositional logic formula. root.");
+    }
+}
+
+/*
+ * split up a pexpr of type AND as both sides must be satisfied
+ */
+static void build_cnf_tseytin_top_and(struct pexpr *e)
+{
+    if (pexpr_is_cnf(e->left.pexpr))
+        unfold_cnf_clause(e->left.pexpr);
+    else
+        build_cnf_tseytin(e->left.pexpr);
+
+    if (pexpr_is_cnf(e->right.pexpr))
+        unfold_cnf_clause(e->right.pexpr);
+    else
+        build_cnf_tseytin(e->right.pexpr);
+
+}
+
+static void build_cnf_tseytin_top_or(struct pexpr *e)
+{
+    struct fexpr *t1 = NULL, *t2 = NULL;
+    int a, b;
+
+    /* set left side */
+    if (pexpr_is_symbol(e->left.pexpr)) {
+        a = pexpr_satval(e->left.pexpr);
+    } else {
+        t1 = create_tmpsatvar();
+        a = t1->satval;
+    }
+
+    /* set right side */
+    if (pexpr_is_symbol(e->right.pexpr)) {
+        b = pexpr_satval(e->right.pexpr);
+    } else {
+        t2 = create_tmpsatvar();
+        b = t2->satval;
+    }
+
+    /* A v B */
+    sat_add_clause(3, pico, a, b);
+
+    /* traverse down the tree to build more constraints if needed */
+    if (!pexpr_is_symbol(e->left.pexpr)) {
+        if (t1 == NULL)
+            perror("t1 is NULL.");
+
+        build_cnf_tseytin_tmp(e->left.pexpr, t1);
+
+    }
+
+    if (!pexpr_is_symbol(e->right.pexpr)) {
+        if (t2 == NULL)
+            perror("t2 is NULL.");
+
+        build_cnf_tseytin_tmp(e->right.pexpr, t2);
+    }
+}
+
+/*
+ * build the sub-expressions
+ */
+static void build_cnf_tseytin_tmp(struct pexpr *e, struct fexpr *t)
+{
+    switch (e->type) {
+    case PE_AND:
+        build_cnf_tseytin_and(e, t);
+        break;
+    case PE_OR:
+        build_cnf_tseytin_or(e, t);
+        break;
+    default:
+        perror("Expression not a propositional logic formula. root.");
+    }
+}
+
+/*
+ * build the Tseytin sub-expressions for a pexpr of type AND
+ */
+static void build_cnf_tseytin_and(struct pexpr *e, struct fexpr *t)
+{
+    struct fexpr *t1 = NULL, *t2 = NULL;
+    int a, b, c;
+
+    /* set left side */
+    if (pexpr_is_symbol(e->left.pexpr)) {
+        a = pexpr_satval(e->left.pexpr);
+    } else {
+        t1 = create_tmpsatvar();
+        a = t1->satval;
+    }
+
+    /* set right side */
+    if (pexpr_is_symbol(e->right.pexpr)) {
+        b = pexpr_satval(e->right.pexpr);
+    } else {
+        t2 = create_tmpsatvar();
+        b = t2->satval;
+    }
+
+    c = t->satval;
+
+    /* -A v -B v C */
+    sat_add_clause(4, pico, -a, -b, c);
+    /* A v -C */
+    sat_add_clause(3, pico, a, -c);
+    /* B v -C */
+    sat_add_clause(3, pico, b, -c);
+
+    /* traverse down the tree to build more constraints if needed */
+    if (!pexpr_is_symbol(e->left.pexpr)) {
+        if (t1 == NULL)
+            perror("t1 is NULL.");
+
+        build_cnf_tseytin_tmp(e->left.pexpr, t1);
+    }
+    if (!pexpr_is_symbol(e->right.pexpr)) {
+        if (t2 == NULL)
+            perror("t2 is NULL.");
+
+        build_cnf_tseytin_tmp(e->right.pexpr, t2);
+    }
+}
+
+/*
+ * build the Tseytin sub-expressions for a pexpr of type
+ */
+static void build_cnf_tseytin_or(struct pexpr *e, struct fexpr *t)
+{
+    struct fexpr *t1 = NULL, *t2 = NULL;
+    int a, b, c;
+
+    /* set left side */
+    if (pexpr_is_symbol(e->left.pexpr)) {
+        a = pexpr_satval(e->left.pexpr);
+    } else {
+        t1 = create_tmpsatvar();
+        a = t1->satval;
+    }
+
+    /* set right side */
+    if (pexpr_is_symbol(e->right.pexpr)) {
+        b = pexpr_satval(e->right.pexpr);
+    } else {
+        t2 = create_tmpsatvar();
+        b = t2->satval;
+    }
+
+    c = t->satval;
+
+    /* A v B v -C */
+    sat_add_clause(4, pico, a, b, -c);
+    /* -A v C */;
+    sat_add_clause(3, pico, -a, c);
+    /* -B v C */
+    sat_add_clause(3, pico, -b, c);
+
+    /* traverse down the tree to build more constraints if needed */
+    if (!pexpr_is_symbol(e->left.pexpr)) {
+        if (t1 == NULL)
+            perror("t1 is NULL.");
+
+        build_cnf_tseytin_tmp(e->left.pexpr, t1);
+    }
+    if (!pexpr_is_symbol(e->right.pexpr)) {
+        if (t2 == NULL)
+            perror("t2 is NULL.");
+        build_cnf_tseytin_tmp(e->right.pexpr, t2);
+    }
+}
+
+/*
+ * add a clause to PicoSAT
+ * First argument must be the SAT solver
+ */
+void sat_add_clause(int num, ...)
+{
+    if (num <= 1)
+        return;
+
+    va_list valist;
+    int i, *lit;
+    PicoSAT *pico;
+
+
+    va_start(valist, num);
+
+    pico = va_arg(valist, PicoSAT *);
+
+    /* access all the arguments assigned to valist */
+    for (i = 1; i < num; i++) {
+        lit = xmalloc(sizeof(int));
+        *lit = va_arg(valist, int);
+        picosat_add(pico, *lit);
+    }
+    picosat_add(pico, 0);
+
+    va_end(valist);
+}
+
+/*
+ * return the SAT-variable for a pexpr that is a symbol
+ */
+static int pexpr_satval(struct pexpr *e)
+{
+    if (!pexpr_is_symbol(e)) {
+        perror("pexpr is not a symbol.");
+        return -1;
+    }
+
+    switch (e->type) {
+    case PE_SYMBOL:
+        return e->left.fexpr->satval;
+    case PE_NOT:
+        return -(e->left.pexpr->left.fexpr->satval);
+    default:
+        perror("Not a symbol.");
+    }
+
+    return -1;
+}
+
+/*
+ * start PicoSAT
+ */
+void picosat_solve(PicoSAT *pico)
+{
+    printd("Solving SAT-problem...");
+
+    clock_t start, end;
+    double time;
+    start = clock();
+
+    int res = picosat_sat(pico, -1);
+
+    end = clock();
+    time = ((double) (end - start)) / CLOCKS_PER_SEC;
+    printd("done. (%.6f secs.)\n\n", time);
+
+    if (res == PICOSAT_SATISFIABLE) {
+        printd("===> PROBLEM IS SATISFIABLE <===\n");
+
+    } else if (res == PICOSAT_UNSATISFIABLE) {
+        printd("===> PROBLEM IS UNSATISFIABLE <===\n");
+
+        /* print unsat core */
+        printd("\nPrinting unsatisfiable core:\n");
+        struct fexpr *e;
+
+        int *lit = malloc(sizeof(int));
+        const int *i = picosat_failed_assumptions(pico);
+        *lit = abs(*i++);
+
+        while (*lit != 0) {
+            e = &satmap[*lit];
+
+            printd("(%d) %s <%d>\n", *lit, str_get(&e->name), e->assumption);
+            *lit = abs(*i++);
+        }
+    }
+    else {
+        printd("Unknown if satisfiable.\n");
+    }
+}
+
+/*
+ * add assumption for a symbol to the SAT-solver
+ */
+void sym_add_assumption(PicoSAT *pico, struct symbol *sym)
+{
+    if (sym_is_boolean(sym)) {
+        int tri_val = sym_get_tristate_value(sym);
+        sym_add_assumption_tri(pico, sym, tri_val);
+        return;
+    }
+
+    if (sym_is_nonboolean(sym)) {
+        struct fexpr *e = sym->nb_vals->head->elem;
+
+        struct fexpr_node *node;
+
+        const char *string_val = sym_get_string_value(sym);
+
+        if (sym->type == S_STRING && !strcmp(string_val, ""))
+            return;
+
+        /* symbol does not have a value */
+        if (!sym_nonbool_has_value_set(sym)) {
+
+            /* set value for sym=n */
+            picosat_assume(pico, e->satval);
+            e->assumption = true;
+
+            struct fexpr_node *node;
+            for (node = sym->nb_vals->head->next; node != NULL; node = node->next) {
+                picosat_assume(pico, -(node->elem->satval));
+                node->elem->assumption = false;
+            }
+
+            return;
+        }
+
+        /* symbol does have a value set */
+
+        /* set value for sym=n */
+        picosat_assume(pico, -(e->satval));
+        e->assumption = false;
+
+        /* set value for all other fexpr */
+        fexpr_list_for_each(node, sym->nb_vals) {
+            if (node->prev == NULL)
+                continue;
+
+            if (strcmp(str_get(&node->elem->nb_val), string_val) == 0) {
+                picosat_assume(pico, node->elem->satval);
+                node->elem->assumption = true;
+            } else {
+                picosat_assume(pico, -(node->elem->satval));
+                node->elem->assumption = false;
+            }
+        }
+    }
+}
+
+/*
+ * add assumption for a boolean symbol to the SAT-solver
+ */
+void sym_add_assumption_tri(PicoSAT *pico, struct symbol *sym, tristate tri_val)
+{
+    if (sym->type == S_BOOLEAN) {
+        int a = sym->fexpr_y->satval;
+        switch (tri_val) {
+        case no:
+            picosat_assume(pico, -a);
+            sym->fexpr_y->assumption = false;
+            break;
+        case mod:
+            perror("Should not happen. Boolean symbol is set to mod.\n");
+            break;
+        case yes:
+
+            picosat_assume(pico, a);
+            sym->fexpr_y->assumption = true;
+            break;
+        }
+    }
+    if (sym->type == S_TRISTATE) {
+        int a = sym->fexpr_y->satval;
+        int a_m = sym->fexpr_m->satval;
+        switch (tri_val) {
+        case no:
+            picosat_assume(pico, -a);
+            picosat_assume(pico, -a_m);
+            sym->fexpr_y->assumption = false;
+            sym->fexpr_m->assumption = false;
+            break;
+        case mod:
+            picosat_assume(pico, -a);
+            picosat_assume(pico, a_m);
+            sym->fexpr_y->assumption = false;
+            sym->fexpr_m->assumption = true;
+            break;
+        case yes:
+            picosat_assume(pico, a);
+            picosat_assume(pico, -a_m);
+            sym->fexpr_y->assumption = true;
+            sym->fexpr_m->assumption = false;
+            break;
+        }
+    }
+}
+
+/*
+ * add assumptions for the symbols to be changed to the SAT solver
+ */
+void sym_add_assumption_sdv(PicoSAT *pico, struct sdv_list *list)
+{
+    struct symbol_dvalue *sdv;
+    struct sdv_node *node;
+    sdv_list_for_each(node, list) {
+        sdv = node->elem;
+
+        int lit_y = sdv->sym->fexpr_y->satval;
+
+        if (sdv->sym->type == S_BOOLEAN) {
+            switch (sdv->tri) {
+            case yes:
+                picosat_assume(pico, lit_y);
+                break;
+            case no:
+                picosat_assume(pico, -lit_y);
+                break;
+            case mod:
+                perror("Should not happen.\n");
+            }
+        } else if (sdv->sym->type == S_TRISTATE) {
+            int lit_m = sdv->sym->fexpr_m->satval;
+            switch (sdv->tri) {
+            case yes:
+                picosat_assume(pico, lit_y);
+                picosat_assume(pico, -lit_m);
+                break;
+            case mod:
+                picosat_assume(pico, -lit_y);
+                picosat_assume(pico, lit_m);
+                break;
+            case no:
+                picosat_assume(pico, -lit_y);
+                picosat_assume(pico, -lit_m);
+            }
+        }
+    }
+}
diff --git a/scripts/kconfig/cf_satutils.h b/scripts/kconfig/cf_satutils.h
new file mode 100644
index 000000000000..d5caf87e3427
--- /dev/null
+++ b/scripts/kconfig/cf_satutils.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#ifndef CF_SATUTILS_H
+#define CF_SATUTILS_H
+
+/* initialize PicoSAT */
+PicoSAT * initialize_picosat(void);
+
+/* construct the CNF-clauses from the constraints */
+void construct_cnf_clauses(PicoSAT *pico);
+
+/* add a clause to to PicoSAT */
+void sat_add_clause(int num, ...);
+
+/* start PicoSAT */
+void picosat_solve(PicoSAT *pico);
+
+/* add assumption for a symbol to the SAT-solver */
+void sym_add_assumption(PicoSAT *pico, struct symbol *sym);
+
+/* add assumption for a boolean symbol to the SAT-solver */
+void sym_add_assumption_tri(PicoSAT *pico, struct symbol *sym, tristate tri_val);
+
+/* add assumptions for the symbols to be changed to the SAT solver */
+void sym_add_assumption_sdv(PicoSAT *pico, struct sdv_list *list);
+
+#endif
diff --git a/scripts/kconfig/cf_utils.c b/scripts/kconfig/cf_utils.c
new file mode 100644
index 000000000000..36d7ab374f6d
--- /dev/null
+++ b/scripts/kconfig/cf_utils.c
@@ -0,0 +1,510 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "configfix.h"
+
+#define SATMAP_INIT_SIZE 2
+
+/*
+ * parse Kconfig-file and read .config
+ */
+void init_config(const char *Kconfig_file)
+{
+    conf_parse(Kconfig_file);
+    conf_read(NULL);
+}
+
+/*
+ * initialize satmap and cnf_clauses_map
+ */
+void init_data(void)
+{
+    /* create hashtable with all fexpr */
+    satmap = xcalloc(SATMAP_INIT_SIZE, sizeof(*satmap));
+    satmap_size = SATMAP_INIT_SIZE;
+
+    printd("done.\n");
+}
+
+/*
+ * bool-symbols have 1 variable (X), tristate-symbols have 2 variables (X, X_m)
+ */
+static void create_sat_variables(struct symbol *sym)
+{
+    sym->constraints = pexpr_list_init();
+    sym_create_fexpr(sym);
+}
+
+/*
+ * assign SAT-variables to all fexpr and create the sat_map
+ */
+void assign_sat_variables(void)
+{
+    unsigned int i;
+    struct symbol *sym;
+
+    printd("Creating SAT-variables...");
+
+    for_all_symbols(i, sym)
+        create_sat_variables(sym);
+
+    printd("done.\n");
+}
+
+/*
+ * create True/False constants
+ */
+void create_constants(void)
+{
+    printd("Creating constants...");
+
+    /* create TRUE and FALSE constants */
+    const_false = fexpr_create(sat_variable_nr++, FE_FALSE, "False");
+    fexpr_add_to_satmap(const_false);
+
+    const_true = fexpr_create(sat_variable_nr++, FE_TRUE, "True");
+    fexpr_add_to_satmap(const_true);
+
+    /* add fexpr of constants to tristate constants */
+    symbol_yes.fexpr_y = const_true;
+    symbol_yes.fexpr_m = const_false;
+
+    symbol_mod.fexpr_y = const_false;
+    symbol_mod.fexpr_m = const_true;
+
+    symbol_no.fexpr_y = const_false;
+    symbol_no.fexpr_m = const_false;
+
+    /* create symbols yes/mod/no as fexpr */
+    symbol_yes_fexpr = fexpr_create(0, FE_SYMBOL, "y");
+    symbol_yes_fexpr->sym = &symbol_yes;
+    symbol_yes_fexpr->tri = yes;
+
+    symbol_mod_fexpr = fexpr_create(0, FE_SYMBOL, "m");
+    symbol_mod_fexpr->sym = &symbol_mod;
+    symbol_mod_fexpr->tri = mod;
+
+    symbol_no_fexpr = fexpr_create(0, FE_SYMBOL, "n");
+    symbol_no_fexpr->sym = &symbol_no;
+    symbol_no_fexpr->tri = no;
+
+    printd("done.\n");
+}
+
+/*
+ * create a temporary SAT-variable
+ */
+struct fexpr * create_tmpsatvar(void)
+{
+    struct fexpr *t = fexpr_create(sat_variable_nr++, FE_TMPSATVAR, "");
+    str_append(&t->name, get_tmp_var_as_char(tmp_variable_nr++));
+    fexpr_add_to_satmap(t);
+
+    return t;
+}
+
+/*
+ * return a temporary SAT variable as string
+ */
+char * get_tmp_var_as_char(int i)
+{
+    char *val = malloc(sizeof(char) * 18);
+    snprintf(val, 18, "T_%d", i);
+    return val;
+}
+
+/*
+ * return a tristate value as a char *
+ */
+char * tristate_get_char(tristate val)
+{
+    switch (val) {
+    case yes:
+        return "yes";
+    case mod:
+        return "mod";
+    case no:
+        return "no";
+    default:
+        return "";
+    }
+}
+
+/*
+ *check whether an expr can evaluate to mod
+ */
+bool expr_can_evaluate_to_mod(struct expr *e)
+{
+    if (!e)
+        return false;
+
+    switch (e->type) {
+    case E_SYMBOL:
+        return e->left.sym == &symbol_mod || e->left.sym->type == S_TRISTATE ? true : false;
+    case E_AND:
+    case E_OR:
+        return expr_can_evaluate_to_mod(e->left.expr) || expr_can_evaluate_to_mod(e->right.expr);
+    case E_NOT:
+        return expr_can_evaluate_to_mod(e->left.expr);
+    default:
+        return false;
+    }
+}
+
+/*
+ * check whether an expr is a non-Boolean constant
+ */
+bool expr_is_nonbool_constant(struct expr *e)
+{
+    if (e->type != E_SYMBOL)
+        return false;
+    if (e->left.sym->type != S_UNKNOWN)
+        return false;
+
+    if (e->left.sym->flags & SYMBOL_CONST)
+        return true;
+
+    return string_is_number(e->left.sym->name) || string_is_hex(e->left.sym->name);
+}
+
+/*
+ * check whether a symbol is a non-Boolean constant
+ */
+bool sym_is_nonbool_constant(struct symbol *sym)
+{
+    if (sym->type != S_UNKNOWN)
+        return false;
+
+    if (sym->flags & SYMBOL_CONST)
+        return true;
+
+    return string_is_number(sym->name) || string_is_hex(sym->name);
+}
+
+/*
+ * print an expr
+ */
+static void print_expr_util(struct expr *e, int prevtoken)
+{
+    if (!e)
+        return;
+
+    switch (e->type) {
+    case E_SYMBOL:
+        if (sym_get_name(e->left.sym) != NULL)
+            printf("%s", sym_get_name(e->left.sym));
+        else
+            printf("left was null\n");
+        break;
+    case E_NOT:
+        printf("!");
+        print_expr_util(e->left.expr, E_NOT);
+        break;
+    case E_AND:
+        if (prevtoken != E_AND && prevtoken != 0)
+            printf("(");
+        print_expr_util(e->left.expr, E_AND);
+        printf(" && ");
+        print_expr_util(e->right.expr, E_AND);
+        if (prevtoken != E_AND && prevtoken != 0)
+            printf(")");
+        break;
+    case E_OR:
+        if (prevtoken != E_OR && prevtoken != 0)
+            printf("(");
+        print_expr_util(e->left.expr, E_OR);
+        printf(" || ");
+        print_expr_util(e->right.expr, E_OR);
+        if (prevtoken != E_OR && prevtoken != 0)
+            printf(")");
+        break;
+    case E_EQUAL:
+    case E_UNEQUAL:
+        if (e->left.sym->name)
+            printf("%s", e->left.sym->name);
+        else
+            printf("left was null\n");
+        printf("%s", e->type == E_EQUAL ? "=" : "!=");
+        printf("%s", e->right.sym->name);
+        break;
+    case E_LEQ:
+    case E_LTH:
+        if (e->left.sym->name)
+            printf("%s", e->left.sym->name);
+        else
+            printf("left was null\n");
+        printf("%s", e->type == E_LEQ ? "<=" : "<");
+        printf("%s", e->right.sym->name);
+        break;
+    case E_GEQ:
+    case E_GTH:
+        if (e->left.sym->name)
+            printf("%s", e->left.sym->name);
+        else
+            printf("left was null\n");
+        printf("%s", e->type == E_GEQ ? ">=" : ">");
+        printf("%s", e->right.sym->name);
+        break;
+    case E_RANGE:
+        printf("[");
+        printf("%s", e->left.sym->name);
+        printf(" ");
+        printf("%s", e->right.sym->name);
+        printf("]");
+        break;
+    default:
+        break;
+    }
+}
+void print_expr(char *tag, struct expr *e, int prevtoken)
+{
+    printf("%s ", tag);
+    print_expr_util(e, prevtoken);
+    printf("\n");
+}
+
+/*
+ * check, if the symbol is a tristate-constant
+ */
+bool sym_is_tristate_constant(struct symbol *sym) {
+    return sym == &symbol_yes || sym == &symbol_mod || sym == &symbol_no;
+}
+
+/*
+ * check, if a symbol is of type boolean or tristate
+ */
+bool sym_is_boolean(struct symbol *sym)
+{
+    return sym->type == S_BOOLEAN || sym->type == S_TRISTATE;
+}
+
+/*
+ * check, if a symbol is a boolean/tristate or a tristate constant
+ */
+bool sym_is_bool_or_triconst(struct symbol *sym)
+{
+    return sym_is_tristate_constant(sym) || sym_is_boolean(sym);
+}
+
+/*
+ * check, if a symbol is of type int, hex, or string
+ */
+bool sym_is_nonboolean(struct symbol *sym)
+{
+    return sym->type == S_INT || sym->type == S_HEX || sym->type == S_STRING;
+}
+
+/*
+ * check, if a symbol has a prompt
+ */
+bool sym_has_prompt(struct symbol *sym)
+{
+    struct property *prop;
+
+    for_all_prompts(sym, prop)
+        return true;
+
+    return false;
+}
+
+/*
+ * return the prompt of the symbol if there is one, NULL otherwise
+ */
+struct property * sym_get_prompt(struct symbol *sym)
+{
+    struct property *prop;
+
+    for_all_prompts(sym, prop)
+        return prop;
+
+    return NULL;
+}
+
+/*
+ * return the condition for the property, True if there is none
+ */
+struct pexpr * prop_get_condition(struct property *prop)
+{
+    if (prop == NULL)
+        return NULL;
+
+    /* if there is no condition, return True */
+    if (!prop->visible.expr)
+        return pexf(const_true);
+
+    return expr_calculate_pexpr_both(prop->visible.expr);
+}
+
+/*
+ * return the default property, NULL if none exists or can be satisfied
+ */
+struct property *sym_get_default_prop(struct symbol *sym)
+{
+    struct property *prop;
+
+    for_all_defaults(sym, prop) {
+        prop->visible.tri = expr_calc_value(prop->visible.expr);
+        if (prop->visible.tri != no)
+            return prop;
+    }
+    return NULL;
+}
+
+/*
+ * check whether a non-boolean symbol has a value set
+ */
+bool sym_nonbool_has_value_set(struct symbol *sym)
+{
+    if (!sym_is_nonboolean(sym))
+        return false;
+
+    const char *string_val = sym_get_string_value(sym);
+
+    if (strcmp(string_val, "") != 0)
+        return true;
+
+    /* a HEX/INT symbol cannot have value "" */
+    if (sym->type == S_HEX || sym->type == S_INT)
+        return false;
+
+    /* cannot have a value with unmet dependencies */
+    if (sym->dir_dep.expr && sym->dir_dep.tri == no)
+        return false;
+
+    /* visible prompt => value set */
+    struct property *prompt = sym_get_prompt(sym);
+    if (prompt != NULL && prompt->visible.tri != no)
+        return true;
+
+    /* invisible prompt => must get value from default value */
+    struct property *p = sym_get_default_prop(sym);
+    if (p == NULL)
+        return false;
+
+    if (!strcmp(sym_get_string_default(sym), ""))
+        return true;
+
+    return false;
+}
+
+/*
+ * return the name of the symbol or the prompt-text, if it is a choice symbol
+ */
+char * sym_get_name(struct symbol *sym)
+{
+    if (sym_is_choice(sym)) {
+        struct property *prompt = sym_get_prompt(sym);
+        if (prompt == NULL)
+            return "";
+
+        return strdup(prompt->text);
+    } else {
+        return sym->name;
+    }
+}
+
+/*
+ * check whether symbol is to be changed
+ */
+bool sym_is_sdv(struct sdv_list *list, struct symbol *sym)
+{
+    struct sdv_node *node;
+    sdv_list_for_each(node, list)
+        if (sym == node->elem->sym)
+            return true;
+
+    return false;
+}
+
+/*
+ * print a symbol's name
+ */
+void print_sym_name(struct symbol *sym)
+{
+    printf("Symbol: ");
+    if (sym_is_choice(sym)) {
+        struct property *prompt = sym_get_prompt(sym);
+        printf("(Choice) %s", prompt->text);
+    } else  {
+        printf("%s", sym->name);
+    }
+    printf("\n");
+}
+
+/*
+ * print all constraints for a symbol
+ */
+void print_sym_constraint(struct symbol* sym)
+{
+    struct pexpr_node *node;
+    pexpr_list_for_each(node, sym->constraints)
+        pexpr_print("::", node->elem, -1);
+}
+
+/*
+ * print a default map
+ */
+void print_default_map(struct defm_list *map)
+{
+    struct default_map *entry;
+    struct defm_node *node;
+
+    defm_list_for_each(node, map) {
+        entry = node->elem;
+        struct gstr s = str_new();
+        str_append(&s, "\t");
+        str_append(&s, str_get(&entry->val->name));
+        str_append(&s, " ->");
+        pexpr_print(strdup(str_get(&s)), entry->e, -1);
+        str_free(&s);
+    }
+}
+
+/*
+ * check whether a string is a number
+ */
+bool string_is_number(char *s)
+{
+    int len = strlen(s);
+    int i = 0;
+    while (i < len) {
+        if (!isdigit(s[i]))
+            return false;
+        i++;
+    }
+
+    return true;
+}
+
+/*
+ * check whether a string is a hexadecimal number
+ */
+bool string_is_hex(char *s)
+{
+    int len = strlen(s);
+    int i = 2;
+    if (len >= 3 && s[0] == '0' && s[1] == 'x') {
+        while (i < len) {
+            if (!isxdigit(s[i]))
+                return false;
+            i++;
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
diff --git a/scripts/kconfig/cf_utils.h b/scripts/kconfig/cf_utils.h
new file mode 100644
index 000000000000..91f9bbf26191
--- /dev/null
+++ b/scripts/kconfig/cf_utils.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#ifndef CF_UTILS_H
+#define CF_UTILS_H
+
+/* parse Kconfig-file and read .config */
+void init_config (const char *Kconfig_file);
+
+/* initialize satmap and cnf_clauses */
+void init_data(void);
+
+/* assign SAT-variables to all fexpr and create the sat_map */
+void assign_sat_variables(void);
+
+/* create True/False constants */
+void create_constants(void);
+
+/* create a temporary SAT-variable */
+struct fexpr * create_tmpsatvar(void);
+
+/* return a temporary SAT variable as string */
+char * get_tmp_var_as_char(int i);
+
+/* return a tristate value as a char * */
+char * tristate_get_char(tristate val);
+
+/* check whether an expr can evaluate to mod */
+bool expr_can_evaluate_to_mod(struct expr *e);
+
+/* check whether an expr is a non-Boolean constant */
+bool expr_is_nonbool_constant(struct expr *e);
+
+/* check whether a symbol is a non-Boolean constant */
+bool sym_is_nonbool_constant(struct symbol *sym);
+
+/* print an expr */
+void print_expr(char *tag, struct expr *e, int prevtoken);
+
+/* check, if the symbol is a tristate-constant */
+bool sym_is_tristate_constant(struct symbol *sym);
+
+/* check, if a symbol is of type boolean or tristate */
+bool sym_is_boolean(struct symbol *sym);
+
+/* check, if a symbol is a boolean/tristate or a tristate constant */
+bool sym_is_bool_or_triconst(struct symbol *sym);
+
+/* check, if a symbol is of type int, hex, or string */
+bool sym_is_nonboolean(struct symbol *sym);
+
+/* check, if a symbol has a prompt */
+bool sym_has_prompt(struct symbol *sym);
+
+/* return the prompt of the symbol, if there is one */
+struct property * sym_get_prompt(struct symbol *sym);
+
+/* return the condition for the property, True if there is none */
+struct pexpr * prop_get_condition(struct property *prop);
+
+/* return the default property, NULL if none exists or can be satisfied */
+struct property *sym_get_default_prop(struct symbol *sym);
+
+/* check whether a non-boolean symbol has a value set */
+bool sym_nonbool_has_value_set(struct symbol *sym);
+
+/* return the name of the symbol */
+char * sym_get_name(struct symbol *sym);
+
+/* check whether symbol is to be changed */
+bool sym_is_sdv(struct sdv_list *list, struct symbol *sym);
+
+/* print a symbol's name */
+void print_sym_name(struct symbol *sym);
+
+/* print all constraints for a symbol */
+void print_sym_constraint(struct symbol *sym);
+
+/* print a default map */
+void print_default_map(struct defm_list *map);
+
+/* check whether a string is a number */
+bool string_is_number(char *s);
+
+/* check whether a string is a hexadecimal number */
+bool string_is_hex(char *s);
+
+#endif
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 10/12] Add tools
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
                   ` (8 preceding siblings ...)
  2021-10-20  9:45 ` [RFC 09/12] Add files with utility functions Thorsten Berger
@ 2021-10-20  9:46 ` Thorsten Berger
  2021-10-20  9:48 ` [RFC 11/12] Add xconfig-modifications Thorsten Berger
  2021-10-20  9:49 ` [RFC 12/12] Simplify dependencies for MODULE_SIG_KEY_TYPE_RSA & MODULE_SIG_KEY_TYPE_ECDSA Thorsten Berger
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:46 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/cfconfig.c    | 176 ++++++++++++++
 scripts/kconfig/cfoutconfig.c | 128 +++++++++++
 scripts/kconfig/configfix.c   | 420 ++++++++++++++++++++++++++++++++++
 scripts/kconfig/configfix.h   |  41 ++++
 4 files changed, 765 insertions(+)
 create mode 100644 scripts/kconfig/cfconfig.c
 create mode 100644 scripts/kconfig/cfoutconfig.c
 create mode 100644 scripts/kconfig/configfix.c
 create mode 100644 scripts/kconfig/configfix.h

diff --git a/scripts/kconfig/cfconfig.c b/scripts/kconfig/cfconfig.c
new file mode 100644
index 000000000000..105bdf5d3f4e
--- /dev/null
+++ b/scripts/kconfig/cfconfig.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "configfix.h"
+
+static struct symbol * read_symbol_from_stdin(void);
+static struct symbol_dvalue * sym_create_sdv(struct symbol *sym, char *input);
+static void handle_fixes(struct sfl_list *diag);
+
+/* -------------------------------------- */
+
+int main(int argc, char *argv[])
+{
+    CFDEBUG = true;
+
+    if (argc > 1 && !strcmp(argv[1], "-s")) {
+        printd("\nHello configfix!\n\n");
+
+        run_satconf_cli(argv[2]);
+        return EXIT_SUCCESS;
+    }
+
+    printd("\nCLI for configfix!\n");
+
+    init_config(argv[1]);
+
+    struct sfl_list *diagnoses;
+    struct sdv_list *symbols;
+
+    while(1) {
+        /* create the array */
+        symbols = sdv_list_init();
+
+        /* ask for user input */
+        struct symbol *sym = read_symbol_from_stdin();
+
+        printd("Found symbol %s, type %s\n\n", sym->name, sym_type_name(sym->type));
+        printd("Current value: %s\n", sym_get_string_value(sym));
+        printd("Desired value: ");
+
+        char input[100];
+        fgets(input, 100, stdin);
+        strtok(input, "\n");
+
+        struct symbol_dvalue *sdv = sym_create_sdv(sym, input);
+        sdv_list_add(symbols, sdv);
+
+        diagnoses = run_satconf(symbols);
+        handle_fixes(diagnoses);
+    }
+
+    return EXIT_SUCCESS;
+}
+
+/*
+ * read a symbol name from stdin
+ */
+static struct symbol * read_symbol_from_stdin(void)
+{
+    char input[100];
+    struct symbol *sym = NULL;
+
+    printd("\n");
+    while (sym == NULL) {
+        printd("Enter symbol name: ");
+        fgets(input, 100, stdin);
+        strtok(input, "\n");
+        sym = sym_find(input);
+    }
+
+    return sym;
+}
+
+/*
+ * create a symbol_dvalue struct containing the symbol and the desired value
+ */
+static struct symbol_dvalue * sym_create_sdv(struct symbol *sym, char *input)
+{
+    struct symbol_dvalue *sdv = malloc(sizeof(struct symbol_dvalue));
+    sdv->sym = sym;
+    sdv->type = sym_is_boolean(sym) ? SDV_BOOLEAN : SDV_NONBOOLEAN;
+
+    if (sym_is_boolean(sym)) {
+        if (strcmp(input, "y") == 0)
+            sdv->tri = yes;
+        else if (strcmp(input, "m") == 0)
+            sdv->tri = mod;
+        else if (strcmp(input, "n") == 0)
+            sdv->tri = no;
+        else
+            perror("Not a valid tristate value.");
+
+        /* sanitize input for booleans */
+        if (sym->type == S_BOOLEAN && sdv->tri == mod)
+            sdv->tri = yes;
+    } else if (sym_is_nonboolean(sym)) {
+        sdv->nb_val = str_new();
+        str_append(&sdv->nb_val, input);
+    }
+
+    return sdv;
+}
+
+/*
+ * print the diagnoses of type symbol_fix
+ */
+static void print_diagnoses_symbol(struct sfl_list *diag_sym)
+{
+    struct sfl_node *arr;
+    unsigned int i = 1;
+
+    sfl_list_for_each(arr, diag_sym) {
+        printd(" %d: ", i++);
+        print_diagnosis_symbol(arr->elem);
+    }
+}
+
+static void apply_all_adiagnoses(struct sfl_list *diag) {
+    printd("Applying all diagnoses now...\n");
+
+    unsigned int counter = 1;
+    struct sfl_node *node;
+    sfl_list_for_each(node, diag) {
+        printd("\nDiagnosis %d:\n", counter++);
+        apply_fix(node->elem);
+
+        printd("\nResetting config.\n");
+        conf_read(NULL);
+    }
+}
+
+/*
+ * print all void print_fixes()
+ */
+static void handle_fixes(struct sfl_list *diag)
+{
+    printd("=== GENERATED DIAGNOSES ===\n");
+    printd("-1: No changes wanted\n");
+    printd(" 0: Apply all diagnoses\n");
+    print_diagnoses_symbol(diag);
+
+    int choice;
+    printd("\n> Choose option: ");
+    scanf("%d", &choice);
+
+    if (choice == -1 || choice > diag->size)
+        return;
+
+    if (choice == 0) {
+        apply_all_adiagnoses(diag);
+        return;
+    }
+
+    unsigned int counter;
+    struct sfl_node *node = diag->head;
+    for (counter = 1; counter < choice; counter++)
+        node = node->next;
+
+    apply_fix(node->elem);
+
+    printd("\nResetting config.\n");
+    conf_read(NULL);
+}
diff --git a/scripts/kconfig/cfoutconfig.c b/scripts/kconfig/cfoutconfig.c
new file mode 100644
index 000000000000..4164e25e66aa
--- /dev/null
+++ b/scripts/kconfig/cfoutconfig.c
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "configfix.h"
+
+#define OUTFILE_CONSTRAINTS "./scripts/kconfig/cfout_constraints.txt"
+#define OUTFILE_DIMACS "./scripts/kconfig/cfout_constraints.dimacs"
+
+static void write_constraints_to_file(void);
+static void write_dimacs_to_file(PicoSAT *pico);
+
+/* -------------------------------------- */
+
+int main(int argc, char *argv[])
+{
+    clock_t start, end;
+    double time;
+
+    printf("\nCreating constraints and CNF clauses...");
+    /* measure time for constructing constraints and clauses */
+    start = clock();
+
+    /* parse Kconfig-file and read .config */
+    init_config(argv[1]);
+
+    /* initialize satmap and cnf_clauses */
+    init_data();
+
+    /* creating constants */
+    create_constants();
+
+    /* assign SAT variables & create sat_map */
+    assign_sat_variables();
+
+    /* get the constraints */
+    get_constraints();
+
+    end = clock();
+    time = ((double) (end - start)) / CLOCKS_PER_SEC;
+
+    printd("done. (%.6f secs.)\n", time);
+
+    /* start PicoSAT */
+    PicoSAT *pico = picosat_init();
+    picosat_enable_trace_generation(pico);
+    printd("Building CNF-clauses...");
+    start = clock();
+
+    /* construct the CNF clauses */
+    construct_cnf_clauses(pico);
+
+    end = clock();
+    time = ((double) (end - start)) / CLOCKS_PER_SEC;
+    printf("done. (%.6f secs.)\n", time);
+
+    printf("\n");
+
+    /* write constraints into file */
+    start = clock();
+    printf("Writing constraints...");
+    write_constraints_to_file();
+    end = clock();
+    time = ((double) (end - start)) / CLOCKS_PER_SEC;
+    printf("done. (%.6f secs.)\n", time);
+
+    /* write SAT problem in DIMACS into file */
+    start = clock();
+    printf("Writing SAT problem in DIMACS...");
+    write_dimacs_to_file(pico);
+    end = clock();
+    time = ((double) (end - start)) / CLOCKS_PER_SEC;
+    printf("done. (%.6f secs.)\n", time);
+
+    printf("\nConstraints have been written into %s\n", OUTFILE_CONSTRAINTS);
+    printf("DIMACS-output has been written into %s\n", OUTFILE_DIMACS);
+
+    return 0;
+}
+
+static void write_constraints_to_file(void)
+{
+    FILE *fd = fopen(OUTFILE_CONSTRAINTS, "w");
+    unsigned int i;
+    struct symbol *sym;
+
+    for_all_symbols(i, sym) {
+        if (sym->type == S_UNKNOWN) continue;
+
+        struct pexpr_node *node;
+        pexpr_list_for_each(node, sym->constraints) {
+            struct gstr s = str_new();
+            pexpr_as_char(node->elem, &s, 0);
+            fprintf(fd, "%s\n", str_get(&s));
+            str_free(&s);
+        }
+    }
+    fclose(fd);
+}
+
+static void add_comment(FILE *fd, struct fexpr *e)
+{
+    fprintf(fd, "c %d %s\n", e->satval, str_get(&e->name));
+}
+
+static void write_dimacs_to_file(PicoSAT *pico)
+{
+    FILE *fd = fopen(OUTFILE_DIMACS, "w");
+
+    unsigned int i;
+    for (i = 1; i < sat_variable_nr; i++)
+        add_comment(fd, &satmap[i]);
+
+    picosat_print(pico, fd);
+    fclose(fd);
+}
diff --git a/scripts/kconfig/configfix.c b/scripts/kconfig/configfix.c
new file mode 100644
index 000000000000..e226541e10f9
--- /dev/null
+++ b/scripts/kconfig/configfix.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "configfix.h"
+
+unsigned int sat_variable_nr = 1;
+unsigned int tmp_variable_nr = 1;
+
+struct fexpr *satmap;
+size_t satmap_size;
+
+struct sdv_list *sdv_symbols; /* array with conflict-symbols */
+
+bool CFDEBUG = false;
+bool stop_rangefix = false;
+
+struct fexpr *const_false; /* constant False */
+struct fexpr *const_true; /* constant True */
+struct fexpr *symbol_yes_fexpr; /* symbol_yes as fexpr */
+struct fexpr *symbol_mod_fexpr; /* symbol_mod as fexpr */
+struct fexpr *symbol_no_fexpr; /* symbol_no_as fexpr */
+
+static PicoSAT *pico;
+static bool init_done = false;
+static struct sym_list *conflict_syms;
+
+static bool sdv_within_range(struct sdv_list *symbols);
+
+/* -------------------------------------- */
+
+int run_satconf_cli(const char *Kconfig_file)
+{
+    clock_t start, end;
+    double time;
+
+    if (!init_done) {
+        printd("Init...");
+        /* measure time for constructing constraints and clauses */
+        start = clock();
+
+        /* parse Kconfig-file and read .config */
+        init_config(Kconfig_file);
+
+        /* initialize satmap and cnf_clauses */
+        init_data();
+
+        /* creating constants */
+        create_constants();
+
+        /* assign SAT variables & create sat_map */
+        assign_sat_variables();
+
+        /* get the constraints */
+        get_constraints();
+
+        /* print all symbols and its constraints */
+        //         print_all_symbols();
+
+        end = clock();
+        time = ((double)(end - start)) / CLOCKS_PER_SEC;
+
+        printd("done. (%.6f secs.)\n", time);
+
+        init_done = true;
+    }
+
+    /* start PicoSAT */
+    PicoSAT *pico = initialize_picosat();
+    printd("Building CNF-clauses...");
+    start = clock();
+
+    /* construct the CNF clauses */
+    construct_cnf_clauses(pico);
+
+    end = clock();
+    time = ((double)(end - start)) / CLOCKS_PER_SEC;
+
+    printd("done. (%.6f secs.)\n", time);
+
+    /* add assumptions for all other symbols */
+    printd("Adding assumptions...");
+    start = clock();
+
+    unsigned int i;
+    struct symbol *sym;
+    for_all_symbols(i, sym) {
+        if (sym->type == S_UNKNOWN)
+            continue;
+
+        if (!sym->name || !sym_has_prompt(sym))
+            continue;
+
+        sym_add_assumption(pico, sym);
+
+    }
+
+    end = clock();
+    time = ((double)(end - start)) / CLOCKS_PER_SEC;
+
+    printd("done. (%.6f secs.)\n", time);
+
+    picosat_solve(pico);
+
+    printd("\n===> STATISTICS <===\n");
+    printd("Constraints  : %d\n", count_counstraints());
+    printd("CNF-clauses  : %d\n", picosat_added_original_clauses(pico));
+    printd("SAT-variables: %d\n", picosat_variables(pico));
+    printd("Temp vars    : %d\n", tmp_variable_nr - 1);
+    printd("PicoSAT time : %.6f secs.\n", picosat_seconds(pico));
+
+    return EXIT_SUCCESS;
+}
+
+/*
+ * called from satdvconfig
+ */
+struct sfl_list *run_satconf(struct sdv_list *symbols)
+{
+    clock_t start, end;
+    double time;
+
+    /* check whether all values can be applied -> no need to run */
+    if (sdv_within_range(symbols)) {
+        printd("\nAll symbols are already within range.\n\n");
+        return sfl_list_init();
+    }
+
+    if (!init_done) {
+        printd("\n");
+        printd("Init...");
+
+        /* measure time for constructing constraints and clauses */
+        start = clock();
+
+        /* initialize satmap and cnf_clauses */
+        init_data();
+
+        /* creating constants */
+        create_constants();
+
+        /* assign SAT variables & create sat_map */
+        assign_sat_variables();
+
+        /* get the constraints */
+        get_constraints();
+
+        end = clock();
+        time = ((double)(end - start)) / CLOCKS_PER_SEC;
+
+        printd("done. (%.6f secs.)\n", time);
+
+        /* start PicoSAT */
+        pico = initialize_picosat();
+        printd("Building CNF-clauses...");
+        start = clock();
+
+        /* construct the CNF clauses */
+        construct_cnf_clauses(pico);
+
+        end = clock();
+        time = ((double)(end - start)) / CLOCKS_PER_SEC;
+
+        printd("done. (%.6f secs.)\n", time);
+
+        printd("CNF-clauses added: %d\n",
+               picosat_added_original_clauses(pico));
+
+        init_done = true;
+    }
+
+    /* copy array with symbols to change */
+    sdv_symbols = sdv_list_copy(symbols);
+
+    /* add assumptions for conflict-symbols */
+    sym_add_assumption_sdv(pico, sdv_symbols);
+
+    /* add assumptions for all other symbols */
+    struct symbol *sym;
+    unsigned int i;
+    for_all_symbols(i, sym) {
+        if (sym->type == S_UNKNOWN)
+            continue;
+
+        if (!sym_is_sdv(sdv_symbols, sym))
+            sym_add_assumption(pico, sym);
+    }
+
+    /* store the conflict symbols */
+    conflict_syms = sym_list_init();
+    struct sdv_node *node;
+    sdv_list_for_each(node, sdv_symbols)
+        sym_list_add(conflict_syms, node->elem->sym);
+
+    printd("Solving SAT-problem...");
+    start = clock();
+
+    int res = picosat_sat(pico, -1);
+
+    end = clock();
+    time = ((double)(end - start)) / CLOCKS_PER_SEC;
+    printd("done. (%.6f secs.)\n\n", time);
+
+    struct sfl_list *ret;
+    if (res == PICOSAT_SATISFIABLE) {
+        printd("===> PROBLEM IS SATISFIABLE <===\n");
+
+        ret = sfl_list_init();
+
+    } else if (res == PICOSAT_UNSATISFIABLE) {
+        printd("===> PROBLEM IS UNSATISFIABLE <===\n");
+        printd("\n");
+
+        ret = rangefix_run(pico);
+    } else {
+        printd("Unknown if satisfiable.\n");
+
+        ret = sfl_list_init();
+    }
+
+    sdv_list_free(sdv_symbols);
+
+    return ret;
+}
+
+/*
+ * check whether a symbol is a conflict symbol
+ */
+static bool sym_is_conflict_sym(struct symbol *sym)
+{
+    struct sym_node *node;
+    sym_list_for_each(node,
+              conflict_syms) if (sym == node->elem) return true;
+
+    return false;
+}
+
+/*
+ * check whether all conflict symbols are set to their target values
+ */
+static bool syms_have_target_value(struct sfix_list *list)
+{
+    struct symbol_fix *fix;
+    struct sfix_node *node;
+
+    sfix_list_for_each(node, list) {
+        fix = node->elem;
+
+        if (!sym_is_conflict_sym(fix->sym))
+            continue;
+
+        sym_calc_value(fix->sym);
+
+        if (sym_is_boolean(fix->sym)) {
+            if (fix->tri != sym_get_tristate_value(fix->sym))
+                return false;
+        } else {
+            if (strcmp(str_get(&fix->nb_val),
+                   sym_get_string_value(fix->sym)) != 0)
+                return false;
+        }
+    }
+
+    return true;
+}
+
+/*
+ *
+ * apply the fixes from a diagnosis
+ */
+int apply_fix(struct sfix_list *fix)
+{
+    struct symbol_fix *sfix;
+    struct sfix_node *node, *next;
+    unsigned int no_symbols_set = 0, iterations = 0, manually_changed = 0;
+
+    struct sfix_list *tmp = sfix_list_copy(fix);
+
+    printd("Trying to apply fixes now...\n");
+
+    while (no_symbols_set < fix->size && !syms_have_target_value(fix)) {
+        if (iterations > fix->size * 2) {
+            printd("\nCould not apply all values :-(.\n");
+            return manually_changed;
+        }
+
+        for (node = tmp->head; node != NULL;) {
+            sfix = node->elem;
+
+            /* update symbol's current value */
+            sym_calc_value(sfix->sym);
+
+            /* value already set? */
+            if (sfix->type == SF_BOOLEAN) {
+                if (sfix->tri == sym_get_tristate_value(sfix->sym)) {
+                    next = node->next;
+                    sfix_list_delete(tmp, node);
+                    node = next;
+                    no_symbols_set++;
+                    continue;
+                }
+            } else if (sfix->type == SF_NONBOOLEAN) {
+                if (strcmp(str_get(&sfix->nb_val),
+                       sym_get_string_value(sfix->sym)) == 0) {
+                    next = node->next;
+                    sfix_list_delete(tmp, node);
+                    node = next;
+                    no_symbols_set++;
+                    continue;
+                }
+            } else {
+                perror("Error applying fix. Value set for disallowed.");
+            }
+
+            /* could not set value, try next */
+            if (sfix->type == SF_BOOLEAN) {
+                if (!sym_set_tristate_value(sfix->sym,
+                                sfix->tri)) {
+                    node = node->next;
+                    continue;
+                }
+            } else if (sfix->type == SF_NONBOOLEAN) {
+                if (!sym_set_string_value(
+                        sfix->sym,
+                        str_get(&sfix->nb_val))) {
+                    node = node->next;
+                    continue;
+                }
+            } else {
+                perror("Error applying fix. Value set for disallowed.");
+            }
+
+            /* could set value, remove from tmp */
+            manually_changed++;
+            if (sfix->type == SF_BOOLEAN) {
+                printd("%s set to %s.\n",
+                       sym_get_name(sfix->sym),
+                       tristate_get_char(sfix->tri));
+            } else if (sfix->type == SF_NONBOOLEAN) {
+                printd("%s set to %s.\n",
+                       sym_get_name(sfix->sym),
+                       str_get(&sfix->nb_val));
+            }
+
+            next = node->next;
+            sfix_list_delete(tmp, node);
+            node = next;
+            no_symbols_set++;
+        }
+
+        iterations++;
+    }
+
+    printd("Fixes successfully applied.\n");
+
+    return manually_changed;
+}
+
+/*
+ * stop RangeFix after the next iteration
+ */
+void interrupt_rangefix(void)
+{
+    stop_rangefix = true;
+}
+
+/*
+ * check whether all symbols are already within range
+ */
+static bool sdv_within_range(struct sdv_list *symbols)
+{
+    struct symbol_dvalue *sdv;
+    struct sdv_node *node;
+
+    sdv_list_for_each(node, symbols) {
+        sdv = node->elem;
+
+        assert(sym_is_boolean(sdv->sym));
+
+        if (sdv->tri == sym_get_tristate_value(sdv->sym))
+            continue;
+
+        if (!sym_tristate_within_range(sdv->sym, sdv->tri))
+            return false;
+    }
+
+    return true;
+}
+
+struct sfix_list *select_solution(struct sfl_list *solutions, int index)
+{
+    struct sfl_node *node = solutions->head;
+    unsigned int counter;
+    for (counter = 0; counter < index; counter++)
+        node = node->next;
+
+    return node->elem;
+}
+
+struct symbol_fix *select_symbol(struct sfix_list *solution, int index)
+{
+    struct sfix_node *node = solution->head;
+    unsigned int counter;
+    for (counter = 0; counter < index; counter++)
+        node = node->next;
+
+    return node->elem;
+}
diff --git a/scripts/kconfig/configfix.h b/scripts/kconfig/configfix.h
new file mode 100644
index 000000000000..0abaf433f41c
--- /dev/null
+++ b/scripts/kconfig/configfix.h
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Patrick Franz <deltaone@debian.org>
+ */
+
+#ifndef CONFIGFIX_H
+#define CONFIGFIX_H
+
+/* make functions accessible from xconfig */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* include internal definitions */
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+/* include own definitions */
+#include "cf_defs.h"
+
+/* include other header files needed */
+#include "picosat.h"
+#include "cf_constraints.h"
+#include "cf_expr.h"
+#include "cf_rangefix.h"
+#include "cf_satutils.h"
+#include "cf_utils.h"
+
+/* external functions */
+struct sfl_list *run_satconf(struct sdv_list *symbols);
+int apply_fix(struct sfix_list *fix);
+int run_satconf_cli(const char *Kconfig_file);
+void interrupt_rangefix(void);
+struct sfix_list *select_solution(struct sfl_list *solutions, int index);
+struct symbol_fix *select_symbol(struct sfix_list *solution, int index);
+
+/* make functions accessible from xconfig */
+#ifdef __cplusplus
+}
+#endif
+#endif
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 11/12] Add xconfig-modifications
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
                   ` (9 preceding siblings ...)
  2021-10-20  9:46 ` [RFC 10/12] Add tools Thorsten Berger
@ 2021-10-20  9:48 ` Thorsten Berger
  2021-10-20  9:49 ` [RFC 12/12] Simplify dependencies for MODULE_SIG_KEY_TYPE_RSA & MODULE_SIG_KEY_TYPE_ECDSA Thorsten Berger
  11 siblings, 0 replies; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:48 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 scripts/kconfig/qconf.cc | 1003 +++++++++++++++++++++++++++++---------
 scripts/kconfig/qconf.h  |  179 ++++++-
 2 files changed, 929 insertions(+), 253 deletions(-)

diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 78087b2d9ac6..a86cd09a1096 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -17,6 +17,10 @@
 #include <QMenuBar>
 #include <QMessageBox>
 #include <QToolBar>
+#include <QListWidget>
+#include <QComboBox>
+#include <QTableWidget>
+#include <QHBoxLayout>
 
 #include <stdlib.h>
 
@@ -24,7 +28,14 @@
 #include "qconf.h"
 
 #include "images.h"
+#include <iostream>
 
+#include <QAbstractItemView>
+#include <QMimeData>
+#include <QBrush>
+#include <QColor>
+#include <future>
+#include <memory>
 
 static QApplication *configApp;
 static ConfigSettings *configSettings;
@@ -82,6 +93,14 @@ QIcon ConfigItem::choiceNoIcon;
 QIcon ConfigItem::menuIcon;
 QIcon ConfigItem::menubackIcon;
 
+/*
+ * set the new data
+ * TODO check the value
+ */
+void ConfigItem::okRename(int col)
+{
+}
+
 /*
  * update the displayed of a menu entry
  */
@@ -122,7 +141,6 @@ void ConfigItem::updateMenu(void)
         goto set_prompt;
     case P_COMMENT:
         setIcon(promptColIdx, QIcon());
-        prompt = "*** " + prompt + " ***";
         goto set_prompt;
     default:
         ;
@@ -140,6 +158,9 @@ void ConfigItem::updateMenu(void)
 
         if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
             setIcon(promptColIdx, QIcon());
+            setText(noColIdx, QString());
+            setText(modColIdx, QString());
+            setText(yesColIdx, QString());
             break;
         }
         expr = sym_get_tristate_value(sym);
@@ -149,10 +170,12 @@ void ConfigItem::updateMenu(void)
                 setIcon(promptColIdx, choiceYesIcon);
             else
                 setIcon(promptColIdx, symbolYesIcon);
+            setText(yesColIdx, "Y");
             ch = 'Y';
             break;
         case mod:
             setIcon(promptColIdx, symbolModIcon);
+            setText(modColIdx, "M");
             ch = 'M';
             break;
         default:
@@ -160,16 +183,31 @@ void ConfigItem::updateMenu(void)
                 setIcon(promptColIdx, choiceNoIcon);
             else
                 setIcon(promptColIdx, symbolNoIcon);
+            setText(noColIdx, "N");
             ch = 'N';
             break;
         }
+        if (expr != no)
+            setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
+        if (expr != mod)
+            setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
+        if (expr != yes)
+            setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
 
         setText(dataColIdx, QChar(ch));
         break;
     case S_INT:
     case S_HEX:
     case S_STRING:
-        setText(dataColIdx, sym_get_string_value(sym));
+        const char* data;
+
+        data = sym_get_string_value(sym);
+
+        setText(dataColIdx, data);
+        if (type == S_STRING)
+            prompt = QString("%1: %2").arg(prompt).arg(data);
+        else
+            prompt = QString("(%2) %1").arg(prompt).arg(data);
         break;
     }
     if (!sym_has_value(sym) && visible)
@@ -210,17 +248,6 @@ void ConfigItem::init(void)
         if (list->mode != fullMode)
             setExpanded(true);
         sym_calc_value(menu->sym);
-
-        if (menu->sym) {
-            enum symbol_type type = menu->sym->type;
-
-            // Allow to edit "int", "hex", and "string" in-place in
-            // the data column. Unfortunately, you cannot specify
-            // the flags per column. Set ItemIsEditable for all
-            // columns here, and check the column in createEditor().
-            if (type == S_INT || type == S_HEX || type == S_STRING)
-                setFlags(flags() | Qt::ItemIsEditable);
-        }
     }
     updateMenu();
 }
@@ -241,65 +268,46 @@ ConfigItem::~ConfigItem(void)
     }
 }
 
-QWidget *ConfigItemDelegate::createEditor(QWidget *parent,
-                      const QStyleOptionViewItem &option,
-                      const QModelIndex &index) const
+ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
+    : Parent(parent)
 {
-    ConfigItem *item;
-
-    // Only the data column is editable
-    if (index.column() != dataColIdx)
-        return nullptr;
-
-    // You cannot edit invisible menus
-    item = static_cast<ConfigItem *>(index.internalPointer());
-    if (!item || !item->menu || !menu_is_visible(item->menu))
-        return nullptr;
-
-    return QStyledItemDelegate::createEditor(parent, option, index);
+    connect(this, SIGNAL(editingFinished()), SLOT(hide()));
 }
 
-void ConfigItemDelegate::setModelData(QWidget *editor,
-                      QAbstractItemModel *model,
-                      const QModelIndex &index) const
+void ConfigLineEdit::show(ConfigItem* i)
 {
-    QLineEdit *lineEdit;
-    ConfigItem *item;
-    struct symbol *sym;
-    bool success;
-
-    lineEdit = qobject_cast<QLineEdit *>(editor);
-    // If this is not a QLineEdit, use the parent's default.
-    // (does this happen?)
-    if (!lineEdit)
-        goto parent;
-
-    item = static_cast<ConfigItem *>(index.internalPointer());
-    if (!item || !item->menu)
-        goto parent;
-
-    sym = item->menu->sym;
-    if (!sym)
-        goto parent;
+    item = i;
+    if (sym_get_string_value(item->menu->sym))
+        setText(sym_get_string_value(item->menu->sym));
+    else
+        setText(QString());
+    Parent::show();
+    setFocus();
+}
 
-    success = sym_set_string_value(sym, lineEdit->text().toUtf8().data());
-    if (success) {
-        ConfigList::updateListForAll();
-    } else {
-        QMessageBox::information(editor, "qconf",
-            "Cannot set the data (maybe due to out of range).\n"
-            "Setting the old value.");
-        lineEdit->setText(sym_get_string_value(sym));
+void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
+{
+    switch (e->key()) {
+    case Qt::Key_Escape:
+        break;
+    case Qt::Key_Return:
+    case Qt::Key_Enter:
+        sym_set_string_value(item->menu->sym, text().toLatin1());
+        parent()->updateList();
+        break;
+    default:
+        Parent::keyPressEvent(e);
+        return;
     }
-
-parent:
-    QStyledItemDelegate::setModelData(editor, model, index);
+    e->accept();
+    parent()->list->setFocus();
+    hide();
 }
 
-ConfigList::ConfigList(QWidget *parent, const char *name)
-    : QTreeWidget(parent),
+ConfigList::ConfigList(ConfigView* p, const char *name)
+    : Parent(p),
       updateAll(false),
-      showName(false), mode(singleMode), optMode(normalOpt),
+      showName(false), showRange(false), showData(false), mode(singleMode), optMode(normalOpt),
       rootEntry(0), headerPopup(0)
 {
     setObjectName(name);
@@ -309,34 +317,26 @@ ConfigList::ConfigList(QWidget *parent, const char *name)
     setVerticalScrollMode(ScrollPerPixel);
     setHorizontalScrollMode(ScrollPerPixel);
 
-    setHeaderLabels(QStringList() << "Option" << "Name" << "Value");
+    setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
 
-    connect(this, &ConfigList::itemSelectionChanged,
-        this, &ConfigList::updateSelection);
+    connect(this, SIGNAL(itemSelectionChanged(void)),
+        SLOT(updateSelection(void)));
 
     if (name) {
         configSettings->beginGroup(name);
         showName = configSettings->value("/showName", false).toBool();
+        showRange = configSettings->value("/showRange", false).toBool();
+        showData = configSettings->value("/showData", false).toBool();
         optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
         configSettings->endGroup();
-        connect(configApp, &QApplication::aboutToQuit,
-            this, &ConfigList::saveSettings);
+        connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
     }
 
     showColumn(promptColIdx);
 
-    setItemDelegate(new ConfigItemDelegate(this));
-
-    allLists.append(this);
-
     reinit();
 }
 
-ConfigList::~ConfigList()
-{
-    allLists.removeOne(this);
-}
-
 bool ConfigList::menuSkip(struct menu *menu)
 {
     if (optMode == normalOpt && menu_is_visible(menu))
@@ -350,10 +350,21 @@ bool ConfigList::menuSkip(struct menu *menu)
 
 void ConfigList::reinit(void)
 {
+    hideColumn(dataColIdx);
+    hideColumn(yesColIdx);
+    hideColumn(modColIdx);
+    hideColumn(noColIdx);
     hideColumn(nameColIdx);
 
     if (showName)
         showColumn(nameColIdx);
+    if (showRange) {
+        showColumn(noColIdx);
+        showColumn(modColIdx);
+        showColumn(yesColIdx);
+    }
+    if (showData)
+        showColumn(dataColIdx);
 
     updateListAll();
 }
@@ -375,6 +386,8 @@ void ConfigList::saveSettings(void)
     if (!objectName().isEmpty()) {
         configSettings->beginGroup(objectName());
         configSettings->setValue("/showName", showName);
+        configSettings->setValue("/showRange", showRange);
+        configSettings->setValue("/showData", showData);
         configSettings->setValue("/optionMode", (int)optMode);
         configSettings->endGroup();
     }
@@ -400,6 +413,7 @@ void ConfigList::updateSelection(void)
     if (selectedItems().count() == 0)
         return;
 
+    emit selectedChanged(selectedItems());
     ConfigItem* item = (ConfigItem*)selectedItems().first();
     if (!item)
         return;
@@ -460,28 +474,6 @@ update:
     resizeColumnToContents(0);
 }
 
-void ConfigList::updateListForAll()
-{
-    QListIterator<ConfigList *> it(allLists);
-
-    while (it.hasNext()) {
-        ConfigList *list = it.next();
-
-        list->updateList();
-    }
-}
-
-void ConfigList::updateListAllForAll()
-{
-    QListIterator<ConfigList *> it(allLists);
-
-    while (it.hasNext()) {
-        ConfigList *list = it.next();
-
-        list->updateList();
-    }
-}
-
 void ConfigList::setValue(ConfigItem* item, tristate val)
 {
     struct symbol* sym;
@@ -502,7 +494,7 @@ void ConfigList::setValue(ConfigItem* item, tristate val)
             return;
         if (oldval == no && item->menu->list)
             item->setExpanded(true);
-        ConfigList::updateListForAll();
+        parent()->updateList();
         break;
     }
 }
@@ -536,9 +528,13 @@ void ConfigList::changeValue(ConfigItem* item)
                 item->setExpanded(true);
         }
         if (oldexpr != newexpr)
-            ConfigList::updateListForAll();
+            parent()->updateList();
+            emit UpdateConflictsViewColorization();
         break;
-    default:
+    case S_INT:
+    case S_HEX:
+    case S_STRING:
+        parent()->lineEdit->show(item);
         break;
     }
 }
@@ -821,6 +817,15 @@ void ConfigList::mouseReleaseEvent(QMouseEvent* e)
             }
         }
         break;
+    case noColIdx:
+        setValue(item, no);
+        break;
+    case modColIdx:
+        setValue(item, mod);
+        break;
+    case yesColIdx:
+        setValue(item, yes);
+        break;
     case dataColIdx:
         changeValue(item);
         break;
@@ -890,32 +895,107 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
         headerPopup = new QMenu(this);
         action = new QAction("Show Name", this);
         action->setCheckable(true);
-        connect(action, &QAction::toggled,
-            this, &ConfigList::setShowName);
-        connect(this, &ConfigList::showNameChanged,
-            action, &QAction::setChecked);
+        connect(action, SIGNAL(toggled(bool)),
+            parent(), SLOT(setShowName(bool)));
+        connect(parent(), SIGNAL(showNameChanged(bool)),
+            action, SLOT(setChecked(bool)));
         action->setChecked(showName);
         headerPopup->addAction(action);
+
+        action = new QAction("Show Range", this);
+        action->setCheckable(true);
+        connect(action, SIGNAL(toggled(bool)),
+            parent(), SLOT(setShowRange(bool)));
+        connect(parent(), SIGNAL(showRangeChanged(bool)),
+            action, SLOT(setChecked(bool)));
+        action->setChecked(showRange);
+        headerPopup->addAction(action);
+
+        action = new QAction("Show Data", this);
+        action->setCheckable(true);
+        connect(action, SIGNAL(toggled(bool)),
+            parent(), SLOT(setShowData(bool)));
+        connect(parent(), SIGNAL(showDataChanged(bool)),
+            action, SLOT(setChecked(bool)));
+        action->setChecked(showData);
+        headerPopup->addAction(action);
     }
 
     headerPopup->exec(e->globalPos());
     e->accept();
 }
 
-void ConfigList::setShowName(bool on)
+ConfigView*ConfigView::viewList;
+QAction *ConfigList::showNormalAction;
+QAction *ConfigList::showAllAction;
+QAction *ConfigList::showPromptAction;
+QAction *ConfigList::addSymbolsFromContextMenu;
+
+ConfigView::ConfigView(QWidget* parent, const char *name)
+    : Parent(parent)
 {
-    if (showName == on)
-        return;
+    setObjectName(name);
+    QVBoxLayout *verticalLayout = new QVBoxLayout(this);
+    verticalLayout->setContentsMargins(0, 0, 0, 0);
 
-    showName = on;
-    reinit();
-    emit showNameChanged(on);
+    list = new ConfigList(this);
+    list->setSelectionMode(QAbstractItemView::ExtendedSelection);
+    list->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(list, SIGNAL(customContextMenuRequested(const QPoint &)),
+        this, SLOT(ShowContextMenu(const QPoint &)));
+    verticalLayout->addWidget(list);
+    lineEdit = new ConfigLineEdit(this);
+    lineEdit->hide();
+    verticalLayout->addWidget(lineEdit);
+
+    this->nextView = viewList;
+    viewList = this;
 }
+void ConfigView::ShowContextMenu(const QPoint& pos){
+   QMenu contextMenu(tr("Context menu"), this);
 
-QList<ConfigList *> ConfigList::allLists;
-QAction *ConfigList::showNormalAction;
-QAction *ConfigList::showAllAction;
-QAction *ConfigList::showPromptAction;
+   contextMenu.addAction(ConfigList::addSymbolsFromContextMenu);
+   contextMenu.exec(mapToGlobal(pos));
+}
+
+ConfigView::~ConfigView(void)
+{
+    ConfigView** vp;
+
+    for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
+        if (*vp == this) {
+            *vp = nextView;
+            break;
+        }
+    }
+}
+
+void ConfigView::setShowName(bool b)
+{
+    if (list->showName != b) {
+        list->showName = b;
+        list->reinit();
+        emit showNameChanged(b);
+    }
+}
+
+void ConfigView::setShowRange(bool b)
+{
+    if (list->showRange != b) {
+        list->showRange = b;
+        list->reinit();
+        emit showRangeChanged(b);
+    }
+}
+
+void ConfigView::setShowData(bool b)
+{
+    if (list->showData != b) {
+        list->showData = b;
+        list->reinit();
+        emit showDataChanged(b);
+    }
+}
 
 void ConfigList::setAllOpen(bool open)
 {
@@ -928,6 +1008,415 @@ void ConfigList::setAllOpen(bool open)
     }
 }
 
+void ConfigView::updateList()
+{
+    ConfigView* v;
+
+    for (v = viewList; v; v = v->nextView)
+        v->list->updateList();
+}
+
+void ConfigView::updateListAll(void)
+{
+    ConfigView* v;
+
+    for (v = viewList; v; v = v->nextView)
+        v->list->updateListAll();
+}
+
+ConflictsView::ConflictsView(QWidget* parent, const char *name)
+    : Parent(parent)
+{
+    currentSelectedMenu = nullptr;
+    setObjectName(name);
+    QHBoxLayout *horizontalLayout = new QHBoxLayout(this);
+    QVBoxLayout *verticalLayout = new QVBoxLayout();
+    verticalLayout->setContentsMargins(0, 0, 0, 0);
+    conflictsToolBar = new QToolBar("ConflictTools", this);
+
+    // toolbar buttons [n] [m] [y] [calculate fixes] [remove]
+    QAction *addSymbol = new QAction("Add Symbol");
+    QAction *setConfigSymbolAsNo = new QAction("N");
+    QAction *setConfigSymbolAsModule = new QAction("M");
+    QAction *setConfigSymbolAsYes = new QAction("Y");
+    fixConflictsAction_ = new QAction("Calculate Fixes");
+    QAction *removeSymbol = new QAction("Remove Symbol");
+
+    // If you change the order of buttons here, change the code where
+    // module button was disabled if symbol is boolean, selecting module
+    // button depends on a specific index in list of action
+    fixConflictsAction_->setCheckable(false);
+    conflictsToolBar->addAction(addSymbol);
+    conflictsToolBar->addAction(setConfigSymbolAsNo);
+    conflictsToolBar->addAction(setConfigSymbolAsModule);
+    conflictsToolBar->addAction(setConfigSymbolAsYes);
+    conflictsToolBar->addAction(fixConflictsAction_);
+    conflictsToolBar->addAction(removeSymbol);
+
+    verticalLayout->addWidget(conflictsToolBar);
+
+    connect(addSymbol, SIGNAL(triggered(bool)), SLOT(addSymbol()));
+    connect(setConfigSymbolAsNo, SIGNAL(triggered(bool)), SLOT(changeToNo()));
+    connect(setConfigSymbolAsModule, SIGNAL(triggered(bool)), SLOT(changeToModule()));
+    connect(setConfigSymbolAsYes, SIGNAL(triggered(bool)), SLOT(changeToYes()));
+    connect(removeSymbol, SIGNAL(triggered(bool)), SLOT(removeSymbol()));
+    connect(this, SIGNAL(resultsReady()), SLOT(updateResults()));
+    // connect clicking 'calculate fixes' to 'change all symbol values to fix all conflicts'
+    // no longer used anymore for now.
+    connect(fixConflictsAction_, SIGNAL(triggered(bool)), SLOT(calculateFixes()));
+
+    conflictsTable = (QTableWidget*) new droppableView(this);
+    conflictsTable->setRowCount(0);
+    conflictsTable->setColumnCount(3);
+    conflictsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+    conflictsTable->setHorizontalHeaderLabels(QStringList()  << "Option" << "Wanted value" << "Current value" );
+    verticalLayout->addWidget(conflictsTable);
+
+    conflictsTable->setDragDropMode(QAbstractItemView::DropOnly);
+    setAcceptDrops(true);
+
+    connect(conflictsTable, SIGNAL(cellClicked(int, int)), SLOT(cellClicked(int,int)));
+    horizontalLayout->addLayout(verticalLayout);
+
+    // populate the solution view on the right hand side:
+    QVBoxLayout *solutionLayout = new QVBoxLayout();
+    solutionLayout->setContentsMargins(0, 0, 0, 0);
+    solutionSelector = new QComboBox();
+    connect(solutionSelector, QOverload<int>::of(&QComboBox::currentIndexChanged),
+        [=](int index){ changeSolutionTable(index); });
+    solutionTable = new QTableWidget();
+    solutionTable->setRowCount(0);
+    solutionTable->setColumnCount(2);
+    solutionTable->setHorizontalHeaderLabels(QStringList()  << "Symbol" << "New Value" );
+
+    applyFixButton = new QPushButton("Apply Selected solution");
+    connect(applyFixButton, SIGNAL(clicked(bool)), SLOT(applyFixButtonClick()));
+
+    numSolutionLabel = new QLabel("Solutions:");
+    solutionLayout->addWidget(numSolutionLabel);
+    solutionLayout->addWidget(solutionSelector);
+    solutionLayout->addWidget(solutionTable);
+    solutionLayout->addWidget(applyFixButton);
+
+    horizontalLayout->addLayout(solutionLayout);
+
+}
+void QTableWidget::dropEvent(QDropEvent *event)
+{
+}
+
+void ConflictsView::changeToNo()
+{
+    QItemSelectionModel *select = conflictsTable->selectionModel();
+
+    if (select->hasSelection()) {
+        QModelIndexList rows = select->selectedRows();
+
+        for (int i = 0;i < rows.count(); i++) {
+            conflictsTable->item(rows[i].row(),1)->setText("NO");
+        }
+    }
+}
+
+void ConflictsView::applyFixButtonClick()
+{
+    signed int solution_number = solutionSelector->currentIndex();
+
+    if (solution_number == -1 || solution_output == NULL) {
+        return;
+    }
+
+    struct sfix_list * selected_solution = select_solution(solution_output, solution_number);
+
+    apply_fix(selected_solution);
+    ConfigView::updateListAll();
+}
+
+void ConflictsView::changeToYes()
+{
+    QItemSelectionModel *select = conflictsTable->selectionModel();
+
+    if (select->hasSelection()) {
+        QModelIndexList rows = select->selectedRows();
+
+        for (int i = 0;i < rows.count(); i++) {
+            conflictsTable->item(rows[i].row(),1)->setText("YES");
+        }
+    }
+
+}
+void ConflictsView::changeToModule()
+{
+    QItemSelectionModel *select = conflictsTable->selectionModel();
+
+    if (select->hasSelection()) {
+        QModelIndexList rows = select->selectedRows();
+
+        for (int i = 0;i < rows.count(); i++) {
+            conflictsTable->item(rows[i].row(),1)->setText("MODULE");
+        }
+    }
+
+}
+
+void ConflictsView::menuChanged1(struct menu *m)
+{
+    currentSelectedMenu = m;
+}
+
+void ConflictsView::addSymbol()
+{
+    addSymbol(currentSelectedMenu);
+}
+
+void ConflictsView::selectedChanged(QList<QTreeWidgetItem *> selection)
+{
+    currentSelection = selection;
+
+}
+
+void ConflictsView::addSymbol(struct menu *m)
+{
+    if (m != nullptr) {
+        if (m->sym != nullptr) {
+            struct symbol *sym = m->sym;
+            tristate currentval = sym_get_tristate_value(sym);
+            // if symbol is not added yet:
+            QAbstractItemModel* tableModel = conflictsTable->model();
+            QModelIndexList matches = tableModel->match(tableModel->index(0,0), Qt::DisplayRole, sym->name );
+
+            if (matches.isEmpty()) {
+                conflictsTable->insertRow(conflictsTable->rowCount());
+                conflictsTable->setItem(conflictsTable->rowCount()-1,0,new QTableWidgetItem(sym->name));
+                conflictsTable->setItem(conflictsTable->rowCount()-1,1,new QTableWidgetItem(tristate_value_to_string(currentval)));
+                conflictsTable->setItem(conflictsTable->rowCount()-1,2,new QTableWidgetItem(tristate_value_to_string(currentval)));
+            } else {
+                conflictsTable->item(matches[0].row(),2)->setText(tristate_value_to_string(currentval));
+            }
+        }
+    }
+}
+
+void ConflictsView::addSymbolFromContextMenu()
+{
+    struct menu *menu;
+
+    if (currentSelection.count() == 0)
+        return;
+
+    for (auto el: currentSelection) {
+        ConfigItem* item = (ConfigItem*)el;
+
+        if (!item) {
+            continue;
+        }
+
+        menu = item->menu;
+        addSymbol(menu);
+    }
+}
+
+void ConflictsView::removeSymbol()
+{
+    QItemSelectionModel *select = conflictsTable->selectionModel();
+    QAbstractItemModel *itemModel = select->model();
+
+    if (select->hasSelection()) {
+        QModelIndexList rows = select->selectedRows();
+        itemModel->removeRows(rows[0].row(),rows.size());
+    }
+}
+
+void ConflictsView::cellClicked(int row, int column)
+{
+    auto itemText = conflictsTable->item(row,0)->text().toUtf8().data();
+
+
+    struct symbol* sym = sym_find(itemText);
+    if (sym == NULL) {
+        return;
+    }
+    struct property* prop = sym->prop;
+    struct menu* men = prop->menu;
+    // uncommenting following like somehow disables click signal of 'apply selected solution'
+    if (sym->type == symbol_type::S_BOOLEAN) {
+        conflictsToolBar->actions()[2]->setDisabled(true);
+    } else {
+        conflictsToolBar->actions()[2]->setDisabled(false);
+    }
+    emit(conflictSelected(men));
+}
+
+void ConflictsView::changeSolutionTable(int solution_number)
+{
+    if(solution_output == nullptr || solution_number < 0) {
+        return;
+    }
+
+    struct sfix_list* selected_solution = select_solution(solution_output, solution_number);
+    current_solution_number = solution_number;
+    solutionTable->setRowCount(0);
+
+    for (unsigned int i = 0; i <selected_solution->size; i++) {
+        solutionTable->insertRow(solutionTable->rowCount());
+
+        struct symbol_fix* cur_symbol = select_symbol(selected_solution,i);
+        QTableWidgetItem* symbol_name = new QTableWidgetItem(cur_symbol->sym->name);
+
+        solutionTable->setItem(solutionTable->rowCount()-1,0,symbol_name);
+
+        if (cur_symbol->type == symbolfix_type::SF_BOOLEAN) {
+            QTableWidgetItem* symbol_value =
+               new QTableWidgetItem(
+                 tristate_value_to_string(cur_symbol->tri));
+            solutionTable->setItem(
+                  solutionTable->rowCount() - 1,
+                  1,
+                  symbol_value);
+        } else if (cur_symbol->type == symbolfix_type::SF_NONBOOLEAN) {
+            QTableWidgetItem* symbol_value =
+               new QTableWidgetItem(cur_symbol->nb_val.s);
+            solutionTable->setItem(
+                  solutionTable->rowCount() - 1,
+                  1,
+                  symbol_value);
+        } else {
+            QTableWidgetItem* symbol_value =
+               new QTableWidgetItem(cur_symbol->disallowed.s);
+            solutionTable->setItem(
+                  solutionTable->rowCount() - 1,
+                  1,
+                  symbol_value);
+        }
+    }
+    UpdateConflictsViewColorization();
+}
+
+void ConflictsView::UpdateConflictsViewColorization(void)
+{
+    auto green = QColor(0, 170, 0);
+    auto red = QColor(255, 0, 0);
+    auto grey = QColor(180, 180, 180);
+
+    if (solutionTable->rowCount() == 0 || current_solution_number < 0)
+        return;
+
+    for (int i = 0; i < solutionTable->rowCount(); i++) {
+        QTableWidgetItem *symbol = solutionTable->item(i, 0);
+        struct sfix_list * selected_solution =
+           select_solution(solution_output, current_solution_number);
+        struct symbol_fix* cur_symbol = select_symbol(selected_solution,i);
+
+        // Red: symbol is editable but value is not from solution
+        // Green: symbol is editable and value is from solution
+        // Grey: symbol is not editable and value is not target value
+        // Green: symbol is not editable and value is target value
+        auto editable = sym_string_within_range(cur_symbol->sym,
+              tristate_value_to_string(cur_symbol->tri).toStdString().c_str());
+        auto _symbol = solutionTable->item(i,0)->text().toUtf8().data();
+        struct symbol* sym_ = sym_find(_symbol);
+
+        tristate current_value_of_symbol = sym_get_tristate_value(sym_);
+        tristate target_value_of_symbol = string_value_to_tristate(solutionTable->item(i,1)->text());
+        bool symbol_value_same_as_target = current_value_of_symbol == target_value_of_symbol;
+
+        if (editable && !symbol_value_same_as_target) {
+            symbol->setForeground(red);
+        } else if (editable && symbol_value_same_as_target) {
+            symbol->setForeground(green);
+        } else if (!editable && !symbol_value_same_as_target) {
+            symbol->setForeground(grey);
+        } else if (!editable && symbol_value_same_as_target) {
+            symbol->setForeground(green);
+        }
+    }
+}
+
+void ConflictsView::runSatConfAsync()
+{
+    // loop through the rows in conflicts table adding each row into the array:
+    struct symbol_dvalue* p = nullptr;
+
+    p = static_cast<struct symbol_dvalue*>(calloc(conflictsTable->rowCount(),sizeof(struct symbol_dvalue)));
+
+    if (!p)
+        return;
+
+    struct sdv_list *wanted_symbols = sdv_list_init();
+
+    for (int i = 0; i < conflictsTable->rowCount(); i++) {
+
+        struct symbol_dvalue *tmp = (p+i);
+        auto _symbol = conflictsTable->item(i,0)->text().toUtf8().data();
+        struct symbol* sym = sym_find(_symbol);
+
+        tmp->sym = sym;
+        tmp->type = static_cast<symboldv_type>(sym->type == symbol_type::S_BOOLEAN?0:1);
+        tmp->tri = string_value_to_tristate(conflictsTable->item(i,1)->text());
+        sdv_list_add(wanted_symbols,tmp);
+    }
+
+    fixConflictsAction_->setText("Cancel");
+    struct sfl_list *ret = run_satconf(wanted_symbols);
+    solution_output = ret;
+
+    free(p);
+
+    emit resultsReady();
+    {
+        std::lock_guard<std::mutex> lk{satconf_mutex};
+        satconf_cancelled = true;
+    }
+
+    satconf_cancellation_cv.notify_one();
+}
+
+void ConflictsView::updateResults(void)
+{
+    fixConflictsAction_->setText("Calculate Fixes");
+
+    if (!(solution_output == nullptr || solution_output->size == 0)) {
+        solutionSelector->clear();
+
+        for (unsigned int i = 0; i < solution_output->size; i++) {
+            solutionSelector->addItem(QString::number(i+1));
+        }
+
+        numSolutionLabel->setText(QString("Solutions: (%1) found").arg(solution_output->size));
+        changeSolutionTable(0);
+    }
+
+    if (runSatConfAsyncThread->joinable()) {
+        runSatConfAsyncThread->join();
+        delete runSatConfAsyncThread;
+        runSatConfAsyncThread  = nullptr;
+    }
+}
+
+void ConflictsView::calculateFixes(void)
+{
+    if (conflictsTable->rowCount() == 0)
+        return;
+
+    if (runSatConfAsyncThread == nullptr) {
+        std::unique_lock<std::mutex> lk{satconf_mutex};
+
+        numSolutionLabel->setText(QString("Solutions: "));
+        solutionSelector->clear();
+        solutionTable->setRowCount(0);
+        satconf_cancelled = false;
+        runSatConfAsyncThread = new std::thread(&ConflictsView::runSatConfAsync,this);
+    } else {
+        interrupt_rangefix();
+        std::unique_lock<std::mutex> lk{satconf_mutex};
+        satconf_cancellation_cv.wait(lk,[this] {
+            return satconf_cancelled == true;
+        });
+    }
+
+}
+
 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
     : Parent(parent), sym(0), _menu(0)
 {
@@ -938,18 +1427,15 @@ ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
         configSettings->beginGroup(objectName());
         setShowDebug(configSettings->value("/showDebug", false).toBool());
         configSettings->endGroup();
-        connect(configApp, &QApplication::aboutToQuit,
-            this, &ConfigInfoView::saveSettings);
+        connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
     }
 
     contextMenu = createStandardContextMenu();
     QAction *action = new QAction("Show Debug Info", contextMenu);
 
     action->setCheckable(true);
-    connect(action, &QAction::toggled,
-        this, &ConfigInfoView::setShowDebug);
-    connect(this, &ConfigInfoView::showDebugChanged,
-        action, &QAction::setChecked);
+    connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+    connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setChecked(bool)));
     action->setChecked(showDebug());
     contextMenu->addSeparator();
     contextMenu->addAction(action);
@@ -1236,26 +1722,27 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
     layout2->setSpacing(6);
     layout2->addWidget(new QLabel("Find:", this));
     editField = new QLineEdit(this);
-    connect(editField, &QLineEdit::returnPressed,
-        this, &ConfigSearchWindow::search);
+    connect(editField, SIGNAL(returnPressed()), SLOT(search()));
     layout2->addWidget(editField);
     searchButton = new QPushButton("Search", this);
     searchButton->setAutoDefault(false);
-    connect(searchButton, &QPushButton::clicked,
-        this, &ConfigSearchWindow::search);
+    connect(searchButton, SIGNAL(clicked()), SLOT(search()));
     layout2->addWidget(searchButton);
     layout1->addLayout(layout2);
 
     split = new QSplitter(this);
     split->setOrientation(Qt::Vertical);
-    list = new ConfigList(split, "search");
-    list->mode = listMode;
+    list = new ConfigView(split, "search");
+    list->list->mode = listMode;
     info = new ConfigInfoView(split, "search");
-    connect(list, &ConfigList::menuChanged,
-        info, &ConfigInfoView::setInfo);
-    connect(list, &ConfigList::menuChanged,
-        parent, &ConfigMainWindow::setMenuLink);
-
+    connect(list->list, SIGNAL(menuChanged(struct menu *)),
+        info, SLOT(setInfo(struct menu *)));
+    connect(list->list, SIGNAL(menuChanged(struct menu *)),
+        parent, SLOT(setMenuLink(struct menu *)));
+    connect(list->list, SIGNAL(menuChanged(struct menu *)),
+        parent, SLOT(conflictSelected(struct menu *)));
+
+    connect(list->list,SIGNAL(UpdateConflictsViewColorization()),SLOT(UpdateConflictsViewColorizationFowarder()));
     layout1->addWidget(split);
 
     QVariant x, y;
@@ -1274,10 +1761,12 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
     if (ok)
         split->setSizes(sizes);
     configSettings->endGroup();
-    connect(configApp, &QApplication::aboutToQuit,
-        this, &ConfigSearchWindow::saveSettings);
+    connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
 }
 
+void ConfigSearchWindow::UpdateConflictsViewColorizationFowarder(void){
+    emit UpdateConflictsViewColorization();
+}
 void ConfigSearchWindow::saveSettings(void)
 {
     if (!objectName().isEmpty()) {
@@ -1298,7 +1787,7 @@ void ConfigSearchWindow::search(void)
     ConfigItem *lastItem = NULL;
 
     free(result);
-    list->clear();
+    list->list->clear();
     info->clear();
 
     result = sym_re_search(editField->text().toLatin1());
@@ -1306,7 +1795,7 @@ void ConfigSearchWindow::search(void)
         return;
     for (p = result; *p; p++) {
         for_all_prompts((*p), prop)
-            lastItem = new ConfigItem(list, lastItem, prop->menu,
+            lastItem = new ConfigItem(list->list, lastItem, prop->menu,
                           menu_is_visible(prop->menu));
     }
 }
@@ -1354,44 +1843,59 @@ ConfigMainWindow::ConfigMainWindow(void)
     split1->setOrientation(Qt::Horizontal);
     split1->setChildrenCollapsible(false);
 
-    menuList = new ConfigList(widget, "menu");
+    menuView = new ConfigView(widget, "menu");
+    menuList = menuView->list;
 
     split2 = new QSplitter(widget);
     split2->setChildrenCollapsible(false);
     split2->setOrientation(Qt::Vertical);
 
     // create config tree
-    configList = new ConfigList(widget, "config");
+    configView = new ConfigView(widget, "config");
+    configList = configView->list;
 
     helpText = new ConfigInfoView(widget, "help");
 
     layout->addWidget(split2);
     split2->addWidget(split1);
-    split1->addWidget(configList);
-    split1->addWidget(menuList);
+    split1->addWidget(configView);
+    split1->addWidget(menuView);
     split2->addWidget(helpText);
 
+    split3 = new QSplitter(split2);
+    split3->setOrientation(Qt::Vertical);
+    conflictsView = new ConflictsView(split3, "help");
+    /* conflictsSelected signal in conflictsview triggers when a conflict is selected
+         in the view. this line connects that event to conflictselected event in mainwindow
+         which updates the selection to match (in the configlist) the symbol that was selected.
+    */
+    connect(conflictsView,SIGNAL(conflictSelected(struct menu *)),SLOT(conflictSelected(struct menu *)));
+    connect(conflictsView,SIGNAL(refreshMenu()),SLOT(refreshMenu()));
+    connect(menuList,SIGNAL(UpdateConflictsViewColorization()),conflictsView,SLOT(UpdateConflictsViewColorization()));
+    connect(configList,SIGNAL(UpdateConflictsViewColorization()),conflictsView,SLOT(UpdateConflictsViewColorization()));
     setTabOrder(configList, helpText);
+
     configList->setFocus();
 
+    // menu = menuBar();
+    toolBar = new QToolBar("Tools", this);
+    addToolBar(toolBar);
+
+
     backAction = new QAction(QPixmap(xpm_back), "Back", this);
-    connect(backAction, &QAction::triggered,
-        this, &ConfigMainWindow::goBack);
+    connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
 
     QAction *quitAction = new QAction("&Quit", this);
     quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
-    connect(quitAction, &QAction::triggered,
-        this, &ConfigMainWindow::close);
+    connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
 
     QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
     loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
-    connect(loadAction, &QAction::triggered,
-        this, &ConfigMainWindow::loadConfig);
+    connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
 
     saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
     saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
-    connect(saveAction, &QAction::triggered,
-        this, &ConfigMainWindow::saveConfig);
+    connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
 
     conf_set_changed_callback(conf_changed);
 
@@ -1400,37 +1904,39 @@ ConfigMainWindow::ConfigMainWindow(void)
     configname = xstrdup(conf_get_configname());
 
     QAction *saveAsAction = new QAction("Save &As...", this);
-    connect(saveAsAction, &QAction::triggered,
-        this, &ConfigMainWindow::saveConfigAs);
+      connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
     QAction *searchAction = new QAction("&Find", this);
     searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
-    connect(searchAction, &QAction::triggered,
-        this, &ConfigMainWindow::searchConfig);
+      connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
     singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
     singleViewAction->setCheckable(true);
-    connect(singleViewAction, &QAction::triggered,
-        this, &ConfigMainWindow::showSingleView);
+      connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
     splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
     splitViewAction->setCheckable(true);
-    connect(splitViewAction, &QAction::triggered,
-        this, &ConfigMainWindow::showSplitView);
+      connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
     fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
     fullViewAction->setCheckable(true);
-    connect(fullViewAction, &QAction::triggered,
-        this, &ConfigMainWindow::showFullView);
+      connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
+
+
 
     QAction *showNameAction = new QAction("Show Name", this);
       showNameAction->setCheckable(true);
-    connect(showNameAction, &QAction::toggled,
-        configList, &ConfigList::setShowName);
-    showNameAction->setChecked(configList->showName);
+      connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
+      showNameAction->setChecked(configView->showName());
+    QAction *showRangeAction = new QAction("Show Range", this);
+      showRangeAction->setCheckable(true);
+      connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
+    QAction *showDataAction = new QAction("Show Data", this);
+      showDataAction->setCheckable(true);
+      connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
 
     QActionGroup *optGroup = new QActionGroup(this);
     optGroup->setExclusive(true);
-    connect(optGroup, &QActionGroup::triggered,
-        configList, &ConfigList::setOptionMode);
-    connect(optGroup, &QActionGroup::triggered,
-        menuList, &ConfigList::setOptionMode);
+    connect(optGroup, SIGNAL(triggered(QAction*)), configList,
+        SLOT(setOptionMode(QAction *)));
+    connect(optGroup, SIGNAL(triggered(QAction *)), menuList,
+        SLOT(setOptionMode(QAction *)));
 
     ConfigList::showNormalAction = new QAction("Show Normal Options", optGroup);
     ConfigList::showNormalAction->setCheckable(true);
@@ -1438,19 +1944,18 @@ ConfigMainWindow::ConfigMainWindow(void)
     ConfigList::showAllAction->setCheckable(true);
     ConfigList::showPromptAction = new QAction("Show Prompt Options", optGroup);
     ConfigList::showPromptAction->setCheckable(true);
+    ConfigList::addSymbolsFromContextMenu = new QAction("Add symbol from context menu");
+    connect(ConfigList::addSymbolsFromContextMenu, SIGNAL(triggered()),conflictsView, SLOT(addSymbolFromContextMenu()));
 
     QAction *showDebugAction = new QAction("Show Debug Info", this);
       showDebugAction->setCheckable(true);
-    connect(showDebugAction, &QAction::toggled,
-        helpText, &ConfigInfoView::setShowDebug);
+      connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
       showDebugAction->setChecked(helpText->showDebug());
 
     QAction *showIntroAction = new QAction("Introduction", this);
-    connect(showIntroAction, &QAction::triggered,
-        this, &ConfigMainWindow::showIntro);
+      connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
     QAction *showAboutAction = new QAction("About", this);
-    connect(showAboutAction, &QAction::triggered,
-        this, &ConfigMainWindow::showAbout);
+      connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
 
     // init tool bar
     QToolBar *toolBar = addToolBar("Tools");
@@ -1462,6 +1967,7 @@ ConfigMainWindow::ConfigMainWindow(void)
     toolBar->addAction(singleViewAction);
     toolBar->addAction(splitViewAction);
     toolBar->addAction(fullViewAction);
+    toolBar->addSeparator();
 
     // create file menu
     QMenu *menu = menuBar()->addMenu("&File");
@@ -1478,6 +1984,8 @@ ConfigMainWindow::ConfigMainWindow(void)
     // create options menu
     menu = menuBar()->addMenu("&Option");
     menu->addAction(showNameAction);
+    menu->addAction(showRangeAction);
+    menu->addAction(showDataAction);
     menu->addSeparator();
     menu->addActions(optGroup->actions());
     menu->addSeparator();
@@ -1488,30 +1996,37 @@ ConfigMainWindow::ConfigMainWindow(void)
     menu->addAction(showIntroAction);
     menu->addAction(showAboutAction);
 
-    connect(helpText, &ConfigInfoView::anchorClicked,
-        helpText, &ConfigInfoView::clicked);
-
-    connect(configList, &ConfigList::menuChanged,
-        helpText, &ConfigInfoView::setInfo);
-    connect(configList, &ConfigList::menuSelected,
-        this, &ConfigMainWindow::changeMenu);
-    connect(configList, &ConfigList::itemSelected,
-        this, &ConfigMainWindow::changeItens);
-    connect(configList, &ConfigList::parentSelected,
-        this, &ConfigMainWindow::goBack);
-    connect(menuList, &ConfigList::menuChanged,
-        helpText, &ConfigInfoView::setInfo);
-    connect(menuList, &ConfigList::menuSelected,
-        this, &ConfigMainWindow::changeMenu);
-
-    connect(configList, &ConfigList::gotFocus,
-        helpText, &ConfigInfoView::setInfo);
-    connect(menuList, &ConfigList::gotFocus,
-        helpText, &ConfigInfoView::setInfo);
-    connect(menuList, &ConfigList::gotFocus,
-        this, &ConfigMainWindow::listFocusChanged);
-    connect(helpText, &ConfigInfoView::menuSelected,
-        this, &ConfigMainWindow::setMenuLink);
+    connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
+         helpText, SLOT (clicked (const QUrl &)) );
+
+    connect(configList, SIGNAL(menuChanged(struct menu *)),
+        helpText, SLOT(setInfo(struct menu *)));
+    connect(configList, SIGNAL(menuSelected(struct menu *)),
+        SLOT(changeMenu(struct menu *)));
+    connect(configList, SIGNAL(itemSelected(struct menu *)),
+        SLOT(changeItens(struct menu *)));
+    connect(configList, SIGNAL(parentSelected()),
+        SLOT(goBack()));
+    connect(menuList, SIGNAL(menuChanged(struct menu *)),
+        helpText, SLOT(setInfo(struct menu *)));
+    connect(menuList, SIGNAL(menuSelected(struct menu *)),
+        SLOT(changeMenu(struct menu *)));
+
+    //pass the list of selected items in configList to conflictsView so that
+    //when right click 'add symbols to conflict' is clicked it will be added
+    //to the list
+    connect(configList, SIGNAL(selectedChanged(QList<QTreeWidgetItem*>)),
+        conflictsView, SLOT(selectedChanged(QList<QTreeWidgetItem*>)));
+    connect(configList, SIGNAL(menuChanged(struct menu *)),
+        conflictsView, SLOT(menuChanged1(struct menu *)));
+    connect(configList, SIGNAL(gotFocus(struct menu *)),
+        helpText, SLOT(setInfo(struct menu *)));
+    connect(menuList, SIGNAL(gotFocus(struct menu *)),
+        helpText, SLOT(setInfo(struct menu *)));
+    connect(menuList, SIGNAL(gotFocus(struct menu *)),
+        SLOT(listFocusChanged(void)));
+    connect(helpText, SIGNAL(menuSelected(struct menu *)),
+        SLOT(setMenuLink(struct menu *)));
 
     QString listMode = configSettings->value("/listMode", "symbol").toString();
     if (listMode == "single")
@@ -1550,7 +2065,7 @@ void ConfigMainWindow::loadConfig(void)
     free(configname);
     configname = xstrdup(name);
 
-    ConfigList::updateListAllForAll();
+    ConfigView::updateListAll();
 }
 
 bool ConfigMainWindow::saveConfig(void)
@@ -1588,8 +2103,10 @@ void ConfigMainWindow::saveConfigAs(void)
 
 void ConfigMainWindow::searchConfig(void)
 {
-    if (!searchWindow)
+    if (!searchWindow){
         searchWindow = new ConfigSearchWindow(this);
+        connect(searchWindow,SIGNAL(UpdateConflictsViewColorization()),conflictsView,SLOT(UpdateConflictsViewColorization()));
+    }
     searchWindow->show();
 }
 
@@ -1685,7 +2202,7 @@ void ConfigMainWindow::showSingleView(void)
 
     backAction->setEnabled(true);
 
-    menuList->hide();
+    menuView->hide();
     menuList->setRootMenu(0);
     configList->mode = singleMode;
     if (configList->rootEntry == &rootmenu)
@@ -1716,10 +2233,17 @@ void ConfigMainWindow::showSplitView(void)
     menuList->mode = symbolMode;
     menuList->setRootMenu(&rootmenu);
     menuList->setAllOpen(true);
-    menuList->show();
+    menuView->show();
     menuList->setFocus();
 }
 
+void ConfigMainWindow::conflictSelected(struct menu * men)
+{
+    configList->clearSelection();
+    menuList->clearSelection();
+    emit(setMenuLink(men));
+}
+
 void ConfigMainWindow::showFullView(void)
 {
     singleViewAction->setEnabled(true);
@@ -1731,7 +2255,7 @@ void ConfigMainWindow::showFullView(void)
 
     backAction->setEnabled(false);
 
-    menuList->hide();
+    menuView->hide();
     menuList->setRootMenu(0);
     configList->mode = fullMode;
     if (configList->rootEntry == &rootmenu)
@@ -1773,26 +2297,17 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
 
 void ConfigMainWindow::showIntro(void)
 {
-    static const QString str =
-        "Welcome to the qconf graphical configuration tool.\n"
-        "\n"
-        "For bool and tristate options, a blank box indicates the "
-        "feature is disabled, a check indicates it is enabled, and a "
-        "dot indicates that it is to be compiled as a module. Clicking "
-        "on the box will cycle through the three states. For int, hex, "
-        "and string options, double-clicking or pressing F2 on the "
-        "Value cell will allow you to edit the value.\n"
-        "\n"
-        "If you do not see an option (e.g., a device driver) that you "
-        "believe should be present, try turning on Show All Options "
-        "under the Options menu. Enabling Show Debug Info will help you"
-        "figure out what other options must be enabled to support the "
-        "option you are interested in, and hyperlinks will navigate to "
-        "them.\n"
-        "\n"
-        "Toggling Show Debug Info under the Options menu will show the "
-        "dependencies, which you can then match by examining other "
-        "options.\n";
+    static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
+        "For each option, a blank box indicates the feature is disabled, a check\n"
+        "indicates it is enabled, and a dot indicates that it is to be compiled\n"
+        "as a module.  Clicking on the box will cycle through the three states.\n\n"
+        "If you do not see an option (e.g., a device driver) that you believe\n"
+        "should be present, try turning on Show All Options under the Options menu.\n"
+        "Although there is no cross reference yet to help you figure out what other\n"
+        "options must be enabled to support the option you are interested in, you can\n"
+        "still view the help of a grayed-out option.\n\n"
+        "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
+        "which you can then match by examining other options.\n\n";
 
     QMessageBox::information(this, "qconf", str);
 }
@@ -1800,13 +2315,10 @@ void ConfigMainWindow::showIntro(void)
 void ConfigMainWindow::showAbout(void)
 {
     static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
-        "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n"
-        "\n"
-        "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"
-        "\n"
-        "Qt Version: ";
+        "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
+        "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
 
-    QMessageBox::information(this, "qconf", str + qVersion());
+    QMessageBox::information(this, "qconf", str);
 }
 
 void ConfigMainWindow::saveSettings(void)
@@ -1844,6 +2356,10 @@ void ConfigMainWindow::conf_changed(void)
     if (saveAction)
         saveAction->setEnabled(conf_get_changed());
 }
+void ConfigMainWindow::refreshMenu(void)
+{
+    configList->updateListAll();
+}
 
 void fixup_rootmenu(struct menu *menu)
 {
@@ -1875,6 +2391,7 @@ int main(int ac, char** av)
     const char *name;
 
     progname = av[0];
+    configApp = new QApplication(ac, av);
     if (ac > 1 && av[1][0] == '-') {
         switch (av[1][1]) {
         case 's':
@@ -1895,8 +2412,6 @@ int main(int ac, char** av)
     conf_read(NULL);
     //zconfdump(stdout);
 
-    configApp = new QApplication(ac, av);
-
     configSettings = new ConfigSettings();
     configSettings->beginGroup("/kconfig/qconf");
     v = new ConfigMainWindow();
@@ -1914,3 +2429,33 @@ int main(int ac, char** av)
 
     return 0;
 }
+
+void droppableView::dropEvent(QDropEvent *event)
+{
+    event->acceptProposedAction();
+}
+
+QString tristate_value_to_string(tristate val)
+{
+    switch (val) {
+    case yes:
+        return QString::fromStdString("YES");
+    case mod:
+        return QString::fromStdString("MODULE");
+    case no:
+        return QString::fromStdString("NO");
+    default:
+        return QString::fromStdString("");
+    }
+}
+tristate string_value_to_tristate(QString s)
+{
+    if (s == "YES")
+        return tristate::yes;
+    else if (s == "MODULE")
+        return tristate::mod;
+    else if (s == "NO")
+        return tristate::no;
+    else
+        return tristate::no;
+}
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index 78b0a1dfcd53..3b0b398ebfe6 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -11,14 +11,25 @@
 #include <QPushButton>
 #include <QSettings>
 #include <QSplitter>
-#include <QStyledItemDelegate>
 #include <QTextBrowser>
 #include <QTreeWidget>
+#include <QListWidget>
+#include <QTableWidget>
+#include <QList>
+#include <QComboBox>
+#include <QLabel>
+#include <qstring.h>
+#include <thread>
+#include <condition_variable>
 
 #include "expr.h"
 
+#include "configfix.h"
+
+class ConfigView;
 class ConfigList;
 class ConfigItem;
+class ConfigLineEdit;
 class ConfigMainWindow;
 
 class ConfigSettings : public QSettings {
@@ -29,7 +40,7 @@ class ConfigSettings : public QSettings {
 };
 
 enum colIdx {
-    promptColIdx, nameColIdx, dataColIdx
+    promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx
 };
 enum listMode {
     singleMode, menuMode, symbolMode, fullMode, listMode
@@ -38,14 +49,31 @@ enum optionMode {
     normalOpt = 0, allOpt, promptOpt
 };
 
+enum symbolStatus {
+    UNSATISFIED, SATISFIED
+};
+
+typedef struct {
+    QString symbol;
+    QString change_needed;
+    enum symbolStatus status;
+    tristate change_requested;
+} Constraint;
+
+QString tristate_value_to_string(tristate val);
+tristate string_value_to_tristate(QString s);
+
 class ConfigList : public QTreeWidget {
     Q_OBJECT
     typedef class QTreeWidget Parent;
 public:
-    ConfigList(QWidget *parent, const char *name = 0);
-    ~ConfigList();
+    ConfigList(ConfigView* p, const char *name = 0);
     void reinit(void);
     ConfigItem* findConfigItem(struct menu *);
+    ConfigView* parent(void) const
+    {
+        return (ConfigView*)Parent::parent();
+    }
     void setSelected(QTreeWidgetItem *item, bool enable) {
         for (int i = 0; i < selectedItems().size(); i++)
             selectedItems().at(i)->setSelected(false);
@@ -71,7 +99,6 @@ public slots:
     void updateSelection(void);
     void saveSettings(void);
     void setOptionMode(QAction *action);
-    void setShowName(bool on);
 
 signals:
     void menuChanged(struct menu *menu);
@@ -79,7 +106,8 @@ public slots:
     void itemSelected(struct menu *menu);
     void parentSelected(void);
     void gotFocus(struct menu *);
-    void showNameChanged(bool on);
+    void selectedChanged(QList<QTreeWidgetItem*> selection);
+    void UpdateConflictsViewColorization();
 
 public:
     void updateListAll(void)
@@ -98,7 +126,7 @@ public slots:
 
     bool updateAll;
 
-    bool showName;
+    bool showName, showRange, showData;
     enum listMode mode;
     enum optionMode optMode;
     struct menu *rootEntry;
@@ -106,11 +134,7 @@ public slots:
     QPalette inactivedColorGroup;
     QMenu* headerPopup;
 
-    static QList<ConfigList *> allLists;
-    static void updateListForAll();
-    static void updateListAllForAll();
-
-    static QAction *showNormalAction, *showAllAction, *showPromptAction;
+    static QAction *showNormalAction, *showAllAction, *showPromptAction, *addSymbolsFromContextMenu;
 };
 
 class ConfigItem : public QTreeWidgetItem {
@@ -133,6 +157,7 @@ class ConfigItem : public QTreeWidgetItem {
     }
     ~ConfigItem(void);
     void init(void);
+    void okRename(int col);
     void updateMenu(void);
     void testUpdateMenu(bool v);
     ConfigList* listView() const
@@ -169,18 +194,104 @@ class ConfigItem : public QTreeWidgetItem {
     static QIcon menuIcon, menubackIcon;
 };
 
-class ConfigItemDelegate : public QStyledItemDelegate
-{
-private:
-    struct menu *menu;
+class ConfigLineEdit : public QLineEdit {
+    Q_OBJECT
+    typedef class QLineEdit Parent;
+public:
+    ConfigLineEdit(ConfigView* parent);
+    ConfigView* parent(void) const
+    {
+        return (ConfigView*)Parent::parent();
+    }
+    void show(ConfigItem *i);
+    void keyPressEvent(QKeyEvent *e);
+
+public:
+    ConfigItem *item;
+};
+
+class ConfigView : public QWidget {
+    Q_OBJECT
+    typedef class QWidget Parent;
 public:
-    ConfigItemDelegate(QObject *parent = nullptr)
-        : QStyledItemDelegate(parent) {}
-    QWidget *createEditor(QWidget *parent,
-                  const QStyleOptionViewItem &option,
-                  const QModelIndex &index) const override;
-    void setModelData(QWidget *editor, QAbstractItemModel *model,
-              const QModelIndex &index) const override;
+    ConfigView(QWidget* parent, const char *name = 0);
+    ~ConfigView(void);
+    static void updateList();
+    static void updateListAll(void);
+
+    bool showName(void) const { return list->showName; }
+    bool showRange(void) const { return list->showRange; }
+    bool showData(void) const { return list->showData; }
+public slots:
+    void setShowName(bool);
+    void setShowRange(bool);
+    void setShowData(bool);
+
+    void ShowContextMenu(const QPoint& p);
+signals:
+    void showNameChanged(bool);
+    void showRangeChanged(bool);
+    void showDataChanged(bool);
+public:
+    ConfigList* list;
+    ConfigLineEdit* lineEdit;
+
+    static ConfigView* viewList;
+    ConfigView* nextView;
+
+    static QAction *showNormalAction;
+    static QAction *showAllAction;
+    static QAction *showPromptAction;
+    static QAction *addSymbolsFromContextMenu;
+};
+class ConflictsView : public QWidget {
+    ConfigLineEdit* lineEdit;
+    Q_OBJECT
+    typedef class QWidget Parent;
+public:
+    ConflictsView(QWidget* parent, const char *name = 0);
+    void addSymbol(struct menu * m);
+    int current_solution_number = -1;
+
+public slots:
+    void cellClicked(int, int);
+    void addSymbol();
+    void addSymbolFromContextMenu();
+    void removeSymbol();
+    void menuChanged1(struct menu *);
+    void changeToNo();
+    void changeToYes();
+    void changeToModule();
+    void selectedChanged(QList<QTreeWidgetItem*> selection);
+    void applyFixButtonClick();
+    void UpdateConflictsViewColorization();
+    void updateResults();
+    void changeSolutionTable(int solution_number);
+    void calculateFixes();
+signals:
+    void showNameChanged(bool);
+    void showRangeChanged(bool);
+    void showDataChanged(bool);
+    void conflictSelected(struct menu *);
+    void refreshMenu();
+    void resultsReady();
+public:
+    QTableWidget* conflictsTable;
+    QList<Constraint> constraints;
+    QComboBox* solutionSelector{nullptr};
+    QTableWidget* solutionTable{nullptr};
+    QPushButton* applyFixButton{nullptr};
+    struct sfl_list * solution_output{nullptr};
+    QToolBar *conflictsToolBar;
+    struct menu * currentSelectedMenu ;
+    QLabel* numSolutionLabel{nullptr};
+    QList<QTreeWidgetItem*> currentSelection;
+    QAction *fixConflictsAction_{nullptr};
+    void runSatConfAsync();
+    std::thread* runSatConfAsyncThread{nullptr};
+    std::mutex satconf_mutex;
+    std::condition_variable satconf_cancellation_cv;
+    bool satconf_cancelled{false};
 };
 
 class ConfigInfoView : public QTextBrowser {
@@ -223,17 +334,21 @@ class ConfigSearchWindow : public QDialog {
 public slots:
     void saveSettings(void);
     void search(void);
+    void UpdateConflictsViewColorizationFowarder();
+signals:
+    void UpdateConflictsViewColorization();
 
 protected:
     QLineEdit* editField;
     QPushButton* searchButton;
     QSplitter* split;
-    ConfigList *list;
+    ConfigView* list;
     ConfigInfoView* info;
 
     struct symbol **result;
 };
 
+
 class ConfigMainWindow : public QMainWindow {
     Q_OBJECT
 
@@ -258,18 +373,34 @@ public slots:
     void showIntro(void);
     void showAbout(void);
     void saveSettings(void);
+    void conflictSelected(struct menu *);
+    void refreshMenu();
 
 protected:
     void closeEvent(QCloseEvent *e);
 
     ConfigSearchWindow *searchWindow;
+    ConfigView *menuView;
     ConfigList *menuList;
+    ConfigView *configView;
     ConfigList *configList;
     ConfigInfoView *helpText;
+    ConflictsView *conflictsView;
+    QToolBar *toolBar;
+    QToolBar *conflictsToolBar;
     QAction *backAction;
     QAction *singleViewAction;
     QAction *splitViewAction;
     QAction *fullViewAction;
     QSplitter *split1;
     QSplitter *split2;
+    QSplitter *split3;
+};
+
+class droppableView : public QTableWidget
+{
+public:
+    droppableView(QWidget *parent = nullptr) {}
+protected:
+    void dropEvent(QDropEvent *event);
 };
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 12/12] Simplify dependencies for MODULE_SIG_KEY_TYPE_RSA & MODULE_SIG_KEY_TYPE_ECDSA
  2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
                   ` (10 preceding siblings ...)
  2021-10-20  9:48 ` [RFC 11/12] Add xconfig-modifications Thorsten Berger
@ 2021-10-20  9:49 ` Thorsten Berger
  2021-10-28  2:48   ` Masahiro Yamada
  11 siblings, 1 reply; 15+ messages in thread
From: Thorsten Berger @ 2021-10-20  9:49 UTC (permalink / raw)
  To: linux-kbuild
  Cc: Luis R. Rodriguez, deltaone, phayax, Eugene Groshev, Sarah Nadi,
	Mel Gorman, Luis R. Rodriguez

Co-developed-by: Patrick Franz <deltaone@debian.org>
Signed-off-by: Patrick Franz <deltaone@debian.org>
Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
Suggested-by: Sarah Nadi <nadi@ualberta.ca>
Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>

---
 certs/Kconfig | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/certs/Kconfig b/certs/Kconfig
index ae7f2e876a31..f69c92e5bc30 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -17,6 +17,7 @@ config MODULE_SIG_KEY
 
 choice
     prompt "Type of module signing key to be generated"
+    depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
     default MODULE_SIG_KEY_TYPE_RSA
     help
      The type of module signing key type to generate. This option
@@ -24,14 +25,12 @@ choice
 
 config MODULE_SIG_KEY_TYPE_RSA
     bool "RSA"
-    depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
     help
      Use an RSA key for module signing.
 
 config MODULE_SIG_KEY_TYPE_ECDSA
     bool "ECDSA"
     select CRYPTO_ECDSA
-    depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
     help
      Use an elliptic curve key (NIST P384) for module signing. Consider
      using a strong hash like sha256 or sha384 for hashing modules.
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC 01/12] Add picosat.h
  2021-10-20  9:35 ` [RFC 01/12] Add picosat.h Thorsten Berger
@ 2021-10-20 15:54   ` Luis Chamberlain
  0 siblings, 0 replies; 15+ messages in thread
From: Luis Chamberlain @ 2021-10-20 15:54 UTC (permalink / raw)
  To: Thorsten Berger
  Cc: linux-kbuild, Luis R. Rodriguez, deltaone, phayax,
	Eugene Groshev, Sarah Nadi, Mel Gorman


Commit logs cannot be empty, and just a subject. Please add a
description for each patch.

  Luis


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 12/12] Simplify dependencies for MODULE_SIG_KEY_TYPE_RSA & MODULE_SIG_KEY_TYPE_ECDSA
  2021-10-20  9:49 ` [RFC 12/12] Simplify dependencies for MODULE_SIG_KEY_TYPE_RSA & MODULE_SIG_KEY_TYPE_ECDSA Thorsten Berger
@ 2021-10-28  2:48   ` Masahiro Yamada
  0 siblings, 0 replies; 15+ messages in thread
From: Masahiro Yamada @ 2021-10-28  2:48 UTC (permalink / raw)
  To: Thorsten Berger
  Cc: Linux Kbuild mailing list, Luis R. Rodriguez, deltaone, phayax,
	Eugene Groshev, Sarah Nadi, Mel Gorman, Luis R. Rodriguez

On Wed, Oct 20, 2021 at 6:49 PM Thorsten Berger <thorsten.berger@rub.de> wrote:
>
> Co-developed-by: Patrick Franz <deltaone@debian.org>
> Signed-off-by: Patrick Franz <deltaone@debian.org>
> Co-developed-by: Ibrahim Fayaz <phayax@gmail.com>
> Signed-off-by: Ibrahim Fayaz <phayax@gmail.com>
> Reviewed-by: Luis Chamberlain <mcgrof@suse.com>
> Tested-by: Evgeny Groshev <eugene.groshev@gmail.com>
> Suggested-by: Sarah Nadi <nadi@ualberta.ca>
> Suggested-by: Thorsten Berger <thorsten.berger@rub.de>
> Signed-off-by: Thorsten Berger <thorsten.berger@rub.de>
>



I had sent an equivalent patch before, (with commit description).

https://lore.kernel.org/all/20211001040126.1200230-1-masahiroy@kernel.org/




> ---
>  certs/Kconfig | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/certs/Kconfig b/certs/Kconfig
> index ae7f2e876a31..f69c92e5bc30 100644
> --- a/certs/Kconfig
> +++ b/certs/Kconfig
> @@ -17,6 +17,7 @@ config MODULE_SIG_KEY
>
>  choice
>      prompt "Type of module signing key to be generated"
> +    depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
>      default MODULE_SIG_KEY_TYPE_RSA
>      help
>       The type of module signing key type to generate. This option
> @@ -24,14 +25,12 @@ choice
>
>  config MODULE_SIG_KEY_TYPE_RSA
>      bool "RSA"
> -    depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
>      help
>       Use an RSA key for module signing.
>
>  config MODULE_SIG_KEY_TYPE_ECDSA
>      bool "ECDSA"
>      select CRYPTO_ECDSA
> -    depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
>      help
>       Use an elliptic curve key (NIST P384) for module signing. Consider
>       using a strong hash like sha256 or sha384 for hashing modules.
> --
> 2.33.0
>
>


-- 
Best Regards
Masahiro Yamada

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2021-10-28  2:49 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-20  9:32 [RFC 0/12] kconfig: add support for conflict resolution Thorsten Berger
2021-10-20  9:35 ` [RFC 01/12] Add picosat.h Thorsten Berger
2021-10-20 15:54   ` Luis Chamberlain
2021-10-20  9:36 ` [RFC 02/12] Add picosat.c (1/3) Thorsten Berger
2021-10-20  9:37 ` [RFC 03/12] Add picosat.c (2/3) Thorsten Berger
2021-10-20  9:38 ` [RFC 04/12] Add picosat.c (3/3) Thorsten Berger
2021-10-20  9:40 ` [RFC 05/12] Add definitions Thorsten Berger
2021-10-20  9:41 ` [RFC 06/12] Add files for building constraints Thorsten Berger
2021-10-20  9:43 ` [RFC 07/12] Add files for handling expressions Thorsten Berger
2021-10-20  9:44 ` [RFC 08/12] Add files for RangeFix Thorsten Berger
2021-10-20  9:45 ` [RFC 09/12] Add files with utility functions Thorsten Berger
2021-10-20  9:46 ` [RFC 10/12] Add tools Thorsten Berger
2021-10-20  9:48 ` [RFC 11/12] Add xconfig-modifications Thorsten Berger
2021-10-20  9:49 ` [RFC 12/12] Simplify dependencies for MODULE_SIG_KEY_TYPE_RSA & MODULE_SIG_KEY_TYPE_ECDSA Thorsten Berger
2021-10-28  2:48   ` Masahiro Yamada

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.