summaryrefslogtreecommitdiff
path: root/bin/model-config.py
blob: 9e86d4a014ffd009c1d3d67df517388a7ac272d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python3

import json
import kconfiglib
import logging
import os
import sys

import numpy as np

numeric_level = getattr(logging, "DEBUG", None)
if not isinstance(numeric_level, int):
    print(f"Invalid log level: {loglevel}", file=sys.stderr)
    sys.exit(1)
logging.basicConfig(level=numeric_level)

kconfig_path = "/tmp/multipass/Kconfig"
configs_base = "/tmp/multipass-model"

kconf = kconfiglib.Kconfig(kconfig_path)

symbols = sorted(
    map(
        lambda sym: sym.name,
        filter(
            lambda sym: kconfiglib.TYPE_TO_STR[sym.type] == "bool", kconf.syms.values()
        ),
    )
)
config_vector = tuple(map(lambda sym: kconf.syms[sym].tri_value == 2, symbols))

with open("kconfigmodel.json", "r") as f:
    data = json.load(f)

assert symbols == data["symbols"]

model = data["model"]

kconf.load_config(sys.argv[1])


class DTreeLeaf:
    def __init__(self, value, stddev):
        self.value = value
        self.stddev = stddev

    def __repr__(self):
        return f"<DTreeLeaf({self.value}, {self.stddev})>"

    def model(self, kconf):
        return self.value


class DTreeNode:
    def __init__(self, symbol, false_child=None, true_child=None):
        self.symbol = symbol
        self.false_child = false_child
        self.true_child = true_child

    def set_false_child(self, child_node):
        self.false_child = child_node

    def set_true_child(self, child_node):
        self.true_child = child_node

    def __repr__(self):
        return f"<DTreeNode({self.false_child}, {self.true_child})>"

    def model(self, kconf):
        if kconf.syms[self.symbol].tri_value == 2 and self.true_child:
            return self.true_child.model(kconf)
        elif kconf.syms[self.symbol].tri_value == 0 and self.false_child:
            return self.false_child.model(kconf)
        return None


def load_model(tree):
    if tree is None:
        return None
    if "value" in tree:
        return DTreeLeaf(tree["value"], tree["stddev"])
    return DTreeNode(
        tree["symbol"], load_model(tree["false"]), load_model(tree["true"])
    )


root = load_model(model)


def vector_diff(v1, v2):
    return sum(map(lambda i: int(v1[i] != v2[i]), range(len(v1))))


current_model = root.model(kconf)
print(f"Model result: {current_model}")

for symbol in symbols:
    kconf_sym = kconf.syms[symbol]
    if kconf_sym.tri_value == 0 and 2 in kconf_sym.assignable:
        kconf_sym.set_value(2)
        new_vector = tuple(map(lambda sym: kconf.syms[sym].tri_value == 2, symbols))
        num_changes = vector_diff(config_vector, new_vector)
        model_diff = root.model(kconf) - current_model
        print(
            f"Setting {symbol:30s} to y changes {num_changes:2d} symbols, model change: {model_diff:+5.0f}"
        )
    elif kconf_sym.tri_value == 2 and 0 in kconf_sym.assignable:
        kconf_sym.set_value(0)
        new_vector = tuple(map(lambda sym: kconf.syms[sym].tri_value == 2, symbols))
        num_changes = vector_diff(config_vector, new_vector)
        model_diff = root.model(kconf) - current_model
        print(
            f"Setting {symbol:30s} to n changes {num_changes:2d} symbols, model change: {model_diff:+5.0f}"
        )
    kconf.load_config(sys.argv[1])