All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thorsten Berger <thorsten.berger@rub.de>
To: linux-kbuild@vger.kernel.org
Cc: deltaone@debian.org, phayax@gmail.com,
	Eugene Groshev <eugene.groshev@gmail.com>,
	Sarah Nadi <nadi@ualberta.ca>, Mel Gorman <mgorman@suse.de>,
	"Luis R. Rodriguez" <mcgrof@suse.com>
Subject: [RFC v3 08/12] Add files for RangeFix
Date: Fri, 22 Oct 2021 15:44:22 +0200	[thread overview]
Message-ID: <6917af58-6735-7265-472f-17a732f19741@rub.de> (raw)
In-Reply-To: <7706ed5e-4771-770a-5cf2-d3c8346fa1dc@rub.de>

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>

The algorithm RangeFix is used to resolve the conflicts. This is the
implementation of the algorithm.

---
 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



  parent reply	other threads:[~2021-10-22 13:44 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-22 13:34 [RFC v3 00/12] kconfig: add support for conflict resolution Thorsten Berger
2021-10-22 13:35 ` [RFC v3 01/12] Add picosat.h Thorsten Berger
2021-10-22 16:57   ` Luis Chamberlain
2021-10-22 13:36 ` [RFC v3 02/12] Add picosat.c (1/3) Thorsten Berger
2021-10-22 16:58   ` Luis Chamberlain
2021-10-22 13:38 ` [RFC v3 03/12] Add picosat.c (2/3) Thorsten Berger
2021-10-22 16:59   ` Luis Chamberlain
2021-10-24  9:05   ` Masahiro Yamada
2021-10-24 23:52     ` Thorsten Berger
2021-10-22 13:39 ` [RFC v3 04/12] Add picosat.c (3/3) Thorsten Berger
2021-10-22 13:40 ` [RFC v3 05/12] Add definitions Thorsten Berger
2021-10-22 16:56   ` Luis Chamberlain
2021-10-22 13:41 ` [RFC v3 06/12] Add files for building constraints Thorsten Berger
2021-10-22 16:56   ` Luis Chamberlain
2021-10-22 13:43 ` [RFC v3 07/12] Add files for handling expressions Thorsten Berger
2021-10-22 13:44 ` Thorsten Berger [this message]
2021-10-22 13:45 ` [RFC v3 09/12] Add files with utility functions Thorsten Berger
2021-10-22 13:46 ` [RFC v3 10/12] Add tools Thorsten Berger
2021-10-22 13:47 ` [RFC v3 11/12] Add xconfig-modifications Thorsten Berger
2021-11-04  9:30   ` Masahiro Yamada
2021-10-22 13:48 ` [RFC v3 12/12] Simplify dependencies for MODULE_SIG_KEY_TYPE_RSA & MODULE_SIG_KEY_TYPE_ECDSA Thorsten Berger
2021-10-22 17:03   ` Luis Chamberlain

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6917af58-6735-7265-472f-17a732f19741@rub.de \
    --to=thorsten.berger@rub.de \
    --cc=deltaone@debian.org \
    --cc=eugene.groshev@gmail.com \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=mcgrof@suse.com \
    --cc=mgorman@suse.de \
    --cc=nadi@ualberta.ca \
    --cc=phayax@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.