Пример #1
0
 def __call__(self, lk, check_paths):
     v = Verifier(lk, Backend())
     v.add_constraint(v.fvar() > 5.0)
     v.add_constraint(
         z3.PbLe([(v.xvar(fid).get(), 1)
                  for fid in v.instance(0).feat_ids()], 50))
     return v
Пример #2
0
            def __call__(self, lk, check_paths):
                v = Verifier(lk, Backend())
                v.add_constraint(v.fvar(instance=0) < 0.0)
                v.add_constraint(v.xvar(0, instance=0) > 50)
                v.add_constraint(v.xvar(1, instance=0) < 50)

                # instances are exactly the same!
                for fid1, fid2 in zip(
                        v.instance(0).feat_ids(),
                        v.instance(1).feat_ids()):
                    v.add_constraint(
                        v.xvar(fid1, instance=0) == v.xvar(fid2, instance=1))

                v.add_constraint(
                    v.fvar(instance=1).get() - v.fvar(instance=0).get() < 9999)

                return v
Пример #3
0
 def __call__(self, lk, check_paths):
     v = Verifier(lk, Backend())
     v.add_constraint(v.fvar() < 0.0)
     v.add_constraint(v.xvar(0) > 50)
     v.add_constraint(v.xvar(1) < 50)
     return v
Пример #4
0
    def test_mark_paths2(self):
        at = AddTree.read("tests/models/xgb-img-easy.json")
        dt = DomTree(at, {})
        l0 = dt.get_leaf(0)
        v = Verifier(l0, Backend())
        v.add_constraint(v.fvar() < 0.0)
        v.add_constraint(v.xvar(0) > 50)
        v.add_constraint(v.xvar(0) <= 80)

        def test_reachable(m, l0):
            m(l0.is_reachable(0, 9, 109))
            m(l0.is_reachable(0, 9, 117))
            m(l0.is_reachable(0, 9, 95))
            m(l0.is_reachable(0, 9, 104))
            m(l0.is_reachable(0, 9, 83))
            m(l0.is_reachable(0, 9, 70))
            m(l0.is_reachable(0, 9, 52))
            m(l0.is_reachable(0, 9, 37))
            m(l0.is_reachable(0, 9, 5))
            m(l0.is_reachable(0, 9, 29))
            m(l0.is_reachable(0, 8, 96))
            m(l0.is_reachable(0, 8, 3))
            m(l0.is_reachable(0, 7, 23))
            m(l0.is_reachable(0, 7, 15))
            m(l0.is_reachable(0, 6, 118))
            m(l0.is_reachable(0, 6, 98))
            m(l0.is_reachable(0, 6, 37))
            m(l0.is_reachable(0, 6, 5))
            m(l0.is_reachable(0, 6, 29))
            m(l0.is_reachable(0, 5, 112))
            m(l0.is_reachable(0, 5, 90))
            m(l0.is_reachable(0, 5, 66))
            m(l0.is_reachable(0, 5, 3))
            m(l0.is_reachable(0, 5, 37))
            m(l0.is_reachable(0, 4, 84))
            m(l0.is_reachable(0, 4, 70))
            m(l0.is_reachable(0, 4, 53))
            m(l0.is_reachable(0, 4, 37))
            m(l0.is_reachable(0, 4, 5))
            m(l0.is_reachable(0, 4, 29))
            m(l0.is_reachable(0, 4, 23))
            m(l0.is_reachable(0, 3, 108))
            m(l0.is_reachable(0, 3, 92))
            m(l0.is_reachable(0, 3, 84))
            m(l0.is_reachable(0, 3, 78))
            m(l0.is_reachable(0, 3, 3))
            m(l0.is_reachable(0, 3, 49))
            m(l0.is_reachable(0, 3, 43))
            m(l0.is_reachable(0, 3, 37))
            m(l0.is_reachable(0, 2, 96))
            m(l0.is_reachable(0, 2, 80))
            m(l0.is_reachable(0, 2, 66))
            m(l0.is_reachable(0, 2, 3))
            m(l0.is_reachable(0, 2, 49))
            m(l0.is_reachable(0, 2, 37))
            m(l0.is_reachable(0, 1, 94))
            m(l0.is_reachable(0, 1, 82))
            m(l0.is_reachable(0, 1, 66))
            m(l0.is_reachable(0, 1, 3))
            m(l0.is_reachable(0, 1, 35))
            m(l0.is_reachable(0, 1, 23))
            m(l0.is_reachable(0, 0, 98))
            m(l0.is_reachable(0, 0, 86))
            m(l0.is_reachable(0, 0, 29))
            m(l0.is_reachable(0, 0, 5))

        test_reachable(self.assertTrue, l0)
        for i in range(len(at)):
            v.instance(0).mark_unreachable_paths(i)
        test_reachable(self.assertFalse, l0)
Пример #5
0
    def test_mark_paths(self):
        at = AddTree()
        t = at.add_tree()
        t.split(t.root(), 0, 2)
        t.split(t.left(t.root()), 0, 1)
        t.split(t.right(t.root()), 0, 3)
        t.set_leaf_value(t.left(t.left(t.root())), 0.1)
        t.set_leaf_value(t.right(t.left(t.root())), 0.2)
        t.set_leaf_value(t.left(t.right(t.root())), 0.3)
        t.set_leaf_value(t.right(t.right(t.root())), 0.4)

        #print(at)

        dt = DomTree([(at, {0: RealDomain(0, 2)}), (at, {})])
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_constraint(in_domain_constraint(v, l0.get_domains(0),
                                              instance=0))
        v.add_constraint(v.xvar(0, instance=0) == v.xvar(0, instance=1))

        self.assertFalse(l0.is_reachable(0, 0, 2))
        self.assertTrue(l0.is_reachable(1, 0, 2))

        v.instance(1).mark_unreachable_paths(0)

        v.add_constraint(v.xvar(0, instance=1) < 1.0)

        self.assertTrue(l0.is_reachable(0, 0, 4))
        self.assertTrue(l0.is_reachable(1, 0, 4))

        v.instance(0).mark_unreachable_paths(0, only_feat_id=999)
        v.instance(1).mark_unreachable_paths(0, only_feat_id=999)

        self.assertTrue(l0.is_reachable(0, 0, 4))  # no effect, wrong feat_id
        self.assertTrue(l0.is_reachable(1, 0, 4))

        v.instance(0).mark_unreachable_paths(0, only_feat_id=0)
        v.instance(1).mark_unreachable_paths(0, only_feat_id=0)

        self.assertFalse(l0.is_reachable(0, 0, 4))
        self.assertFalse(l0.is_reachable(1, 0, 4))

        self.assertFalse(l0.is_reachable(1, 0, 2))

        v.add_all_trees()
        #print(v._backend._solver)
        v.check()
        m = v.model()

        self.assertLess(m[0]["xs"][0], 1.0)
        self.assertGreaterEqual(m[0]["xs"][0], 0.0)
        self.assertEqual(m[0]["xs"][0], m[1]["xs"][0])
        self.myAssertAlmostEqual(m[0]["ws"][0], 0.1)
Пример #6
0
    def test_mnist_multi_instance(self):
        at = AddTree.read(f"tests/models/xgb-mnist-yis0-easy.json")

        dt = DomTree([(at, {}), (at, {})])
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_all_trees(0)
        v.add_all_trees(1)
        v.add_constraint(v.fvar(0) > 5.0)  # it is with high certainty X
        v.add_constraint(v.fvar(1) < -5.0)  # it is with high certainty not X

        pbeq = []
        for feat_id in AddTreeFeatureTypes(at).feat_ids():
            bvar_name = f"b{feat_id}"
            v.add_bvar(bvar_name)

            bvar = v.bvar(bvar_name)
            xvar1 = v.xvar(feat_id, 0)
            xvar2 = v.xvar(feat_id, 1)

            v.add_constraint(
                z3.If(bvar.get(),
                      xvar1.get() != xvar2.get(),
                      xvar1.get() == xvar2.get()))
            pbeq.append((bvar.get(), 1))

        N = 4
        v.add_constraint(z3.PbLe(pbeq, N))  # at most N variables differ

        count = 0
        uniques = set()

        img1_prev, img2_prev = None, None
        while count < 10:
            check = v.check()
            if not check.is_sat():
                print("UNSAT")
                break

            model = v.model()
            img1 = np.zeros((28, 28))
            img2 = np.zeros((28, 28))
            hash1 = 127
            hash2 = 91
            for fid, x in model[0]["xs"].items():
                p = np.unravel_index(fid, (28, 28))
                if x is not None: img1[p[1], p[0]] = x
                hash1 = hash((hash1, fid, x))
            for fid, x in model[1]["xs"].items():
                p = np.unravel_index(fid, (28, 28))
                if x is not None: img2[p[1], p[0]] = x
                hash2 = hash((hash2, fid, x))
            uniques.add(hash((hash1, hash2)))

            if count > 0:
                diff1 = abs(img1 - img1_prev).sum()
                diff2 = abs(img2 - img2_prev).sum()
                print("mnist_multi_instance: norm difference:", diff1, diff2)
                self.assertGreater(diff1, 0.0)
                self.assertGreater(diff2, 0.0)
            img1_prev, img2_prev = img1, img2

            # Ensure that the different pixels have different values in the next iteration
            # We do not care about the other pixels
            fam = v.model_family(model)
            fam_diff0 = {}
            fam_diff1 = {}
            for n, b in model["bs"].items():
                if not b: continue
                i = int(n[1:])
                p = np.unravel_index(i, (28, 28))
                print("different pixel (bvar):", i, p, model[0]["xs"][i],
                      model[1]["xs"][i])
                if i in fam[0]: fam_diff0[i] = fam[0][i]
                if i in fam[1]: fam_diff1[i] = fam[1][i]
            v.add_constraint(
                not_in_domain_constraint(v, fam_diff0, 0)
                & not_in_domain_constraint(v, fam_diff1, 1))

            count += 1

            print("iteration", count, "uniques", len(uniques))
            if count % 100 != 0: continue

            fig, (ax1, ax2) = plt.subplots(1, 2)
            ax1.imshow(img1, vmin=0, vmax=255)
            ax2.imshow(img2, vmin=0, vmax=255)
            ax1.set_title("instance 1: f={:.3f}".format(model[0]["f"]))
            ax2.set_title("instance 2: f={:.3f}".format(model[1]["f"]))

            for n, b in model["bs"].items():
                if not b: continue
                i = int(n[1:])
                p = np.unravel_index(i, (28, 28))
                ax1.scatter([p[0]], [p[1]], marker=".", color="r")
                ax2.scatter([p[0]], [p[1]], marker=".", color="r")

            plt.show()

        self.assertEqual(count, 10)
        self.assertEqual(len(uniques), 10)
Пример #7
0
    def test_bin_mnist(self):
        at = AddTree.read(f"tests/models/xgb-mnist-bin-yis1-easy.json")
        dt = DomTree(at, {})
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_all_trees()
        v.add_constraint(v.fvar(0) > 5.0)  # it is with high certainty X

        count = 0
        uniques = set()
        img_prev = None
        while v.check().is_sat() and count < 10:
            model = v.model()
            img = np.zeros((28, 28), dtype=bool)
            hash1 = 91
            for fid, x in model["xs"].items():
                p = np.unravel_index(fid, (28, 28))
                if x is not None: img[p[1], p[0]] = x
                hash1 = hash((hash1, fid, x))
            uniques.add(hash1)

            fam = v.model_family(model)
            v.add_constraint(not_in_domain_constraint(v, fam, 0))

            if count > 0:
                ndiff = (img_prev != img).sum()
                print("bin_mnist: different =", ndiff)
                self.assertGreater(ndiff, 0)

            img_prev = img
            count += 1

            if count % 100 != 0: continue

            fig, ax = plt.subplots()
            ax.imshow(img)
            ax.set_title("instance: f={:.3f}".format(model["f"]))
            plt.show()

        self.assertEqual(count, 10)
        self.assertEqual(len(uniques), 10)
Пример #8
0
    def test_img_sampling(self):
        # find all points with predictions less than 0.0
        with open("tests/models/xgb-img-easy-values.json") as f:
            ys = json.load(f)
        img = np.array(ys).reshape((100, 100))
        at = AddTree.read("tests/models/xgb-img-easy.json")

        dt = DomTree(at, {})
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_all_trees()
        v.add_constraint(v.fvar() < 0.0)

        models = []
        while v.check() == Verifier.Result.SAT:
            m = v.model()
            x = int(m["xs"][1])
            y = int(m["xs"][0])
            self.assertLess(m["f"], 0.0)
            self.assertAlmostEqual(img[y][x], m["f"], delta=1e-4)
            fam = v.model_family(m)

            # all predictions in the rectangle are the same
            for xx in range(int(fam[1].lo), int(min(fam[1].hi, 100))):
                for yy in range(int(fam[0].lo), int(min(fam[0].hi, 100))):
                    self.assertAlmostEqual(m["f"], at.predict_single([yy, xx]))

            models.append((x, y, fam))
            v.add_constraint(not_in_domain_constraint(v, fam, 0))

        #fig, ax = plt.subplots()
        #ax.imshow(img)
        #for x, y, dom in models:
        #    x0, y0, x1, y1 = max(0.0, dom[1].lo), max(0.0, dom[0].lo), min(100.0, dom[1].hi), min(100.0, dom[0].hi)
        #    w, h = x1-x0, y1-y0
        #    print((x0, y0), (x1, y1), w, h)
        #    rect = patches.Rectangle((x0-0.5,y0-0.5),w,h,linewidth=1,edgecolor='r',facecolor='none')
        #    ax.add_patch(rect)
        #    ax.scatter([x], [y], marker=".", c="b")
        #plt.show()

        self.assertEqual(len(models), 11)
Пример #9
0
    def test_img(self):
        with open("tests/models/xgb-img-easy-values.json") as f:
            ys = json.load(f)
        at = AddTree.read("tests/models/xgb-img-easy.json")

        m, M = min(ys), max(ys)
        img = np.array(ys).reshape((100, 100))

        #fig, ax = plt.subplots(2, 2)
        #ax[0, 0].imshow(img0, vmin=m, vmax=M)
        #ax[0, 1].imshow(img1, vmin=m, vmax=M)
        #ax[1, 0].imshow(img2, vmin=m, vmax=M)
        #ax[1, 1].imshow(img3, vmin=m, vmax=M)
        #plt.show()

        print("< 0")
        dt = DomTree(at, {})
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_all_trees()
        self.assertEqual(v.check(v.fvar() < 0.0), Verifier.Result.SAT)
        model = v.model()
        self.assertLess(model["f"], 0.0)
        self.assertGreaterEqual(model["f"], m)

        print("< m, > M")
        self.assertEqual(v.check((v.fvar() < m) | (v.fvar() > M)),
                         Verifier.Result.UNSAT)

        quandrant = 0
        img = np.array(ys).reshape((100, 100))
        for x0 in [0, 50]:
            for y0 in [0, 50]:
                print("quadrant", quandrant)
                x1, y1 = x0 + 50, y0 + 50
                imgq = img[x0:x1, y0:y1]
                m, M = imgq.min(), imgq.max()

                dt = DomTree(at, {
                    0: RealDomain(x0, x1),
                    1: RealDomain(y0, y1)
                })
                l0 = dt.get_leaf(dt.tree().root())
                v = Verifier(l0, Backend())
                v.add_all_trees()

                self.assertEqual(v.check(v.fvar() < m + 1e-4),
                                 Verifier.Result.SAT)
                self.assertAlmostEqual(v.model()["f"], m, delta=1e-4)
                self.assertEqual(v.check(v.fvar() > M - 1e-4),
                                 Verifier.Result.SAT)
                self.assertAlmostEqual(v.model()["f"], M, delta=1e-4)

                quandrant += 1
Пример #10
0
    def test_single_tree(self):
        at = AddTree()
        t = at.add_tree()
        t.split(t.root(), 0, 2)
        t.split(t.left(t.root()), 0, 1)
        t.split(t.right(t.root()), 0, 3)
        t.set_leaf_value(t.left(t.left(t.root())), 0.1)
        t.set_leaf_value(t.right(t.left(t.root())), 0.2)
        t.set_leaf_value(t.left(t.right(t.root())), 0.3)
        t.set_leaf_value(t.right(t.right(t.root())), 0.4)

        dt = DomTree(at, {})
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())

        self.assertEqual(v._backend.check(v.fvar() < 0.0), Verifier.Result.SAT)
        v.add_tree(0)
        self.assertEqual(v._backend.check(v.fvar() < 0.0),
                         Verifier.Result.UNSAT)
        self.assertEqual(v._backend.check(v.fvar() > 0.0), Verifier.Result.SAT)
        self.assertEqual(v._backend.check(v.fvar() < 0.41),
                         Verifier.Result.SAT)
        self.assertEqual(v._backend.check(v.fvar() > 0.41),
                         Verifier.Result.UNSAT)

        dt = DomTree(at, {0: RealDomain(1, 3)})
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_constraint(v.xvar(0) < 2.0)
        v.add_tree(0)
        check = v.check(
            v.fvar() != t.get_leaf_value(t.right(t.left(t.root()))))
        self.assertEqual(check, Verifier.Result.UNSAT)

        dt = DomTree(at, {0: RealDomain(1, 3)})
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_all_trees()
        self.assertEqual(v.check(v.fvar() < 0.0), Verifier.Result.UNSAT)
        self.assertEqual(v.check(v.fvar() > 0.0), Verifier.Result.SAT)
        self.assertEqual(v.check(v.fvar() < 0.41), Verifier.Result.SAT)
        self.assertEqual(v.check(v.fvar() > 0.41), Verifier.Result.UNSAT)
Пример #11
0
    def test_multi_instance(self):
        at = AddTree()
        t = at.add_tree()
        t.split(t.root(), 0, 2)
        t.split(t.left(t.root()), 0, 1)
        t.split(t.right(t.root()), 0, 3)
        t.set_leaf_value(t.left(t.left(t.root())), 0.1)
        t.set_leaf_value(t.right(t.left(t.root())), 0.2)
        t.set_leaf_value(t.left(t.right(t.root())), 0.3)
        t.set_leaf_value(t.right(t.right(t.root())), 0.4)
        t = at.add_tree()
        t.split(t.root(), 0, 2)
        t.split(t.left(t.root()), 1, 1)
        t.split(t.right(t.root()), 1, 3)
        t.set_leaf_value(t.left(t.left(t.root())), 0.1)
        t.set_leaf_value(t.right(t.left(t.root())), 0.2)
        t.set_leaf_value(t.left(t.right(t.root())), -0.3)
        t.set_leaf_value(t.right(t.right(t.root())), -0.4)

        #print(at)

        dt = DomTree([(at, {}), (at, {})])
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_all_trees()
        v.add_constraint(v.instance(0).fvar() > v.instance(1).fvar())
        v.add_constraint(v.instance(1).fvar() > 0)
        v.add_constraint(v.instance(0).xvar(0) == v.instance(1).xvar(0))
        v.add_constraint(v.instance(1).xvar(1) < 1)
        models = []
        while v.check() == Verifier.Result.SAT:
            m = v.model()

            self.assertGreater(m[0]["f"], m[1]["f"])
            self.assertGreater(m[1]["f"], 0.0)
            self.assertEqual(m[0]["xs"][0], m[1]["xs"][0])
            self.assertLess(m[1]["xs"][1], 1.0)

            print("MODEL xs", m[0]["xs"], m[1]["xs"])
            print("      ws", m[0]["ws"], m[1]["ws"])
            print("       f", m[0]["f"], m[1]["f"])
            models.append(m)
            fam = v.model_family(m)
            #print("FAM", fam)
            v.add_constraint(
                not_in_domain_constraint(v, fam[0], 0)
                | not_in_domain_constraint(v, fam[1], 1))

        self.assertEqual(len(models), 2)
Пример #12
0
    def test_two_trees(self):
        at = AddTree()
        t = at.add_tree()
        t.split(t.root(), 0, 2)
        t.split(t.left(t.root()), 0, 1)
        t.split(t.right(t.root()), 0, 3)
        t.set_leaf_value(t.left(t.left(t.root())), 0.1)
        t.set_leaf_value(t.right(t.left(t.root())), 0.2)
        t.set_leaf_value(t.left(t.right(t.root())), 0.3)
        t.set_leaf_value(t.right(t.right(t.root())), 0.4)
        t = at.add_tree()
        t.split(t.root(), 0, 2)
        t.split(t.left(t.root()), 1, 1)
        t.split(t.right(t.root()), 1, 3)
        t.set_leaf_value(t.left(t.left(t.root())), 0.1)
        t.set_leaf_value(t.right(t.left(t.root())), 0.2)
        t.set_leaf_value(t.left(t.right(t.root())), -0.3)
        t.set_leaf_value(t.right(t.right(t.root())), -0.4)

        dt = DomTree(at, {})
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_all_trees()
        self.assertEqual(v.check(v.fvar() < -0.11), Verifier.Result.UNSAT)
        self.assertEqual(v.check(v.fvar() < -0.09), Verifier.Result.SAT)
        self.myAssertAlmostEqual(v.model()["ws"], [0.3, -0.4])
        self.assertEqual(v.check(v.fvar() > -0.09), Verifier.Result.SAT)
        self.assertEqual(v.check(v.fvar() > 0.41), Verifier.Result.UNSAT)
        self.assertEqual(v.check(v.fvar() > 0.39), Verifier.Result.SAT)
        self.myAssertAlmostEqual(v.model()["ws"], [0.2, 0.2])

        v = Verifier(l0, Backend())
        v.add_all_trees()
        v.add_constraint(v.xvar(0) < 2.0)
        self.assertEqual(v.check(v.fvar() < -0.09), Verifier.Result.UNSAT)
        self.assertEqual(v.check(v.fvar() > 0.39), Verifier.Result.SAT)
        self.myAssertAlmostEqual(v.model()["ws"], [0.2, 0.2])

        v = Verifier(l0, Backend())
        v.add_all_trees()
        v.add_constraint(v.xvar(0) >= 2.0)
        self.assertEqual(v.check(v.fvar() < -0.09), Verifier.Result.SAT)
        self.myAssertAlmostEqual(v.model()["ws"], [0.3, -0.4])
        self.assertEqual(v.check(v.fvar() > 0.39), Verifier.Result.UNSAT)

        dt = DomTree(at, {0: RealDomain(-math.inf, 2.0)})
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_all_trees()
        self.assertEqual(v.check(v.fvar() < -0.09), Verifier.Result.UNSAT)
        self.assertEqual(v.check(v.fvar() > 0.39), Verifier.Result.SAT)
        self.myAssertAlmostEqual(v.model()["ws"], [0.2, 0.2])

        dt = DomTree(at, {0: RealDomain(2.0, math.inf)})
        l0 = dt.get_leaf(dt.tree().root())
        v = Verifier(l0, Backend())
        v.add_all_trees()
        self.assertEqual(v.check(v.fvar() < -0.09), Verifier.Result.SAT)
        self.myAssertAlmostEqual(v.model()["ws"], [0.3, -0.4])
        self.assertEqual(v.check(v.fvar() > 0.39), Verifier.Result.UNSAT)
        v.add_constraint(v.xvar(1) < 2.0)
        self.assertEqual(v.check(v.fvar() < -0.09), Verifier.Result.UNSAT)
        self.assertEqual(v.check(v.fvar() < 0.01), Verifier.Result.SAT)

        model = v.model()
        #print(model)
        self.myAssertAlmostEqual(model["ws"], [0.3, -0.3])
        #print(v.model_family(model))
        v.add_constraint(not_in_domain_constraint(v, v.model_family(model), 0))
        self.assertEqual(v.check(v.fvar() < 0.01), Verifier.Result.UNSAT)