From dc3e512bbf4ccb24a0e1c8ef9fc23156d44c7b25 Mon Sep 17 00:00:00 2001 From: Christian Gram Kalhauge <chrg@dtu.dk> Date: Thu, 20 Feb 2025 10:02:41 +0100 Subject: [PATCH] Update to work. --- flake.lock | 25 ++-- flake.nix | 58 +++++----- pyrtree/rtree.py | 146 +++++++++++++++++++++++- rtree-c/bin/Main.hs | 2 +- rtree/rtree.cabal | 3 +- rtree/src/Control/Monad/IRTree.hs | 1 + rtree/src/Control/Monad/RTree.hs | 4 +- rtree/src/Control/Monad/RTree/Simple.hs | 29 ----- 8 files changed, 192 insertions(+), 76 deletions(-) delete mode 100644 rtree/src/Control/Monad/RTree/Simple.hs diff --git a/flake.lock b/flake.lock index 0b9c3a2..25d79f5 100644 --- a/flake.lock +++ b/flake.lock @@ -5,17 +5,16 @@ "systems": "systems" }, "locked": { - "lastModified": 1705309234, - "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" + "id": "flake-utils", + "type": "indirect" } }, "flake-utils_2": { @@ -120,18 +119,16 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1707939175, - "narHash": "sha256-D1xan0lgxbmXDyzVqXTiSYHLmAMrMRdD+alKzEO/p3w=", - "owner": "nixos", + "lastModified": 1739863612, + "narHash": "sha256-UbtgxplOhFcyjBcNbTVO8+HUHAl/WXFDOb6LvqShiZo=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "f7e8132daca31b1e3859ac0fb49741754375ac3d", + "rev": "632f04521e847173c54fa72973ec6c39a371211c", "type": "github" }, "original": { - "owner": "nixos", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" + "id": "nixpkgs", + "type": "indirect" } }, "root": { diff --git a/flake.nix b/flake.nix index ba4cb19..9f6a3cf 100644 --- a/flake.nix +++ b/flake.nix @@ -1,13 +1,11 @@ { inputs = { - nixpkgs.url = github:nixos/nixpkgs/nixpkgs-unstable; - flake-utils.url = github:numtide/flake-utils; - nix-filter.url = github:numtide/nix-filter; + nix-filter.url = "github:numtide/nix-filter"; language-c = { - url = github:kalhauge/language-c; + url = "github:kalhauge/language-c"; flake = false; }; - hspec-glitter.url = github:kalhauge/hspec-glitter; + hspec-glitter.url = "github:kalhauge/hspec-glitter"; }; outputs = { self, @@ -19,33 +17,41 @@ load = p: n: p.callCabal2nixWithOptions n (nix-filter.lib {root = "${self}/${n}";}) "" {}; - packages = lib: p: { - "language-c" = lib.dontCheck (p.callCabal2nixWithOptions "language-c" inputs.language-c "" {}); - "hspec-glitter" = p.callCabal2nixWithOptions "hspec-glitter" inputs.hspec-glitter "" {}; - "rtree" = lib.dontCheck (load p "rtree"); - "rtree-c" = lib.dontCheck (load p "rtree-c"); + packages = lib: final: prev: { + "language-c" = lib.dontCheck (final.callCabal2nixWithOptions "language-c" inputs.language-c "" {}); + "hspec-glitter" = final.callCabal2nixWithOptions "hspec-glitter" inputs.hspec-glitter "" {}; + "rtree" = lib.dontCheck (load final "rtree"); + "rtree-c" = lib.dontCheck (load final "rtree-c"); + }; + + overlay = final: prev: let + lib = final.haskell.lib; + hpkgs = prev.haskellPackages.override (hpArgs: { + overrides = final.lib.composeExtensions (hpArgs.overrides or (_: _: {})) (packages lib); + }); + in { + haskellPackages = hpkgs; + rtree-c = lib.justStaticExecutables (hpkgs.rtree-c); + rtree = hpkgs.rtree; }; in - flake-utils.lib.eachDefaultSystem + { + overlays.default = overlay; + } + // flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; - overlays = []; + overlays = [overlay]; }; - lib = pkgs.haskell.lib; - hpkgs = pkgs.haskellPackages.override (hpArgs: { - overrides = pkgs.lib.composeExtensions (hpArgs.overrides or (_: _: {})) ( - _hfinal: hprev: packages lib hprev - ); - }); in { packages = { - default = lib.justStaticExecutables (hpkgs.rtree-c); - rtree = hpkgs.rtree; - rtree-c = hpkgs.rtree-c; + default = pkgs.rtree-c; + rtree = pkgs.rtree; + rtree-c = pkgs.rtree-c; }; devShells = let - nativeBuildInputs = with hpkgs; [ + nativeBuildInputs = with pkgs.haskellPackages; [ cabal-install ghcid haskell-language-server @@ -53,7 +59,7 @@ fourmolu ]; withHoogle = true; - profiles = hpkgs.override (hpArgs: { + profiles = pkgs.haskellPackages.override (hpArgs: { overrides = pkgs.lib.composeExtensions (hpArgs.overrides or (_: _: {})) ( _hfinal: hprev: { mkDerivation = args: @@ -80,14 +86,14 @@ ); }); in { - rtree = hpkgs.rtree; + rtree = pkgs.haskellPackages.rtree; default = profiles.shellFor { name = "rtree-shells"; packages = p: [ - (lib.doCheck p.rtree) - (lib.doCheck p.rtree-c) + (pkgs.haskell.lib.doCheck p.rtree) + (pkgs.haskell.lib.doCheck p.rtree-c) ]; doBenchmark = true; genericBuilderArgsModifier = args: diff --git a/pyrtree/rtree.py b/pyrtree/rtree.py index ec34513..ac6b969 100644 --- a/pyrtree/rtree.py +++ b/pyrtree/rtree.py @@ -1,4 +1,26 @@ from dataclasses import dataclass +import math +from typing import TypeVar + + +def reduce_simp(predicate, rtree): + path: list[bool] = [] + labels: list[str] = [] + + def check(label): + labels.append(label) + return path[len(labels) - 1] if len(path) >= len(labels) else False + + i = rtree(check) + while len(path) < len(labels): + path.append(True) + labels.clear() + if t := predicate(j := rtree(check)): + i = j + else: + path[-1] = False + print(f"{labels[len(path) - 1]} ... test {j!r:<10} ... {t}") + return i class Probe: @@ -20,6 +42,23 @@ class Probe: return len(self.reasons) - len(self.path) +def reduce1(predicate, rtree): + # Extract the initial reduction probe, from the rightmost branch. + rp = Probe(rtree, []) + # Run exponential search after the depest sequence of trues + # that can be appended to the path without failing the predicate + depth = 1 + # Invariant: predicate(rp) == True + while rp.undecided() > 0: + # Try to probe the with current path extended by one trues + if predicate(rp_ := Probe(rtree, rp.path, depth)): + rp = rp_ + continue + rp.path.append(False) + # return the input. + return rp + + def reduce(predicate, rtree): # Extract the initial reduction probe, from the rightmost branch. rp = Probe(rtree, []) @@ -89,6 +128,29 @@ def latex( return newpred +def table( + predicate, + input_format="{}".format, + query_format=str, + start_count=0, +): + counter = start_count - 1 + + def newpred(rp): + nonlocal counter + counter += 1 + t = predicate(rp.input) + query = ", ".join( + query_format(a) for a in rp.reasons[len(rp.path) - rp.depth : len(rp.path)] + ) + theck = "true " if t else "false" + + print(f"{counter:02} - {input_format(rp.input)} - {theck} - {query}") + return t + + return newpred + + def pretty(rp): from itertools import zip_longest @@ -103,14 +165,94 @@ def pretty(rp): def reduce_abc(check) -> str: result = "" - for x in "abcdefghijklmnopqrstuvxyz": - if not check(f"{x}"): + for x in "abc": + if not check(f"remove {x}?"): result += x else: result += " " return result +def reduce_dd2(c: list, check) -> list: + if check(f"ignore {c}?"): + return [] + if len(c) == 1: + return c + pivot = len(c) // 2 + c2 = reduce_dd(c[pivot:], check) + c1 = reduce_dd(c[:pivot], check) + return c1 + c2 + + +def reduce_dd(c: list, check) -> list: + if len(c) == 1: + return c + pivot = len(c) // 2 + c1 = c[:pivot] + c2 = c[pivot:] + if check(f"result in c1: {c1}?"): + return reduce_dd(c1, check) + elif check(f"result in c2: {c2}?"): + return reduce_dd(c2, check) + else: + return reduce_dd(c1, check) + reduce_dd(c2, check) + + +I = TypeVar("I") + + +def reduce_df(i: I, actions, check) -> I: + j = None + while i != j: + for act in actions: + if check(f"apply {act}?"): + i, j = act(i), i + else: + break + return i + + +def reduce_ddmin(input: list, check, n=2) -> list: + def find_next(input, n): + step = math.ceil(len(input) / n) + subsets = [(step * i, step * (i + 1)) for i in range(n)] + for i, (f, t) in enumerate(subsets): + if check(f"delta: {i}/{n}"): + return input[f:t], 2 + + for i, (f, t) in enumerate(subsets) if n != 2 else []: + if check(f"complement: {i}/{n}"): + return input[:f] + input[t:], max(n - 1, 2) + + return input, n * 2 + + while len(input) > 1 and n < 2 * len(input): + input, n = find_next(input, n) + + return input + + +def test_reduce_dd(): + from functools import partial + + p = debug(lambda a: 3 in a and 6 in a) + rp = reduce(p, partial(reduce_dd, [1, 2, 3, 4, 5, 6, 7, 8])) + print(rp) + + +def test_reduce_ddmin(): + from functools import partial + + input_format = lambda a: "".join("X" if i in a else "." for i in range(1, 9)) + p = table( + lambda a: 1 in a and 7 in a and 8 in a, + input_format=input_format, + query_format=str, + ) + rp = reduce1(p, partial(reduce_ddmin, [1, 2, 3, 4, 5, 6, 7, 8])) + print(f" - {input_format(rp.input)}") + + if __name__ == "__main__": p = latex( lambda e: "a" in e or "p" in e, diff --git a/rtree-c/bin/Main.hs b/rtree-c/bin/Main.hs index d5b9e73..72b2df0 100644 --- a/rtree-c/bin/Main.hs +++ b/rtree-c/bin/Main.hs @@ -82,7 +82,7 @@ run = do fold [ long "keyword" , short 'k' - , help "don't do any reduction" + , help "special versions of the code" ] validity <- diff --git a/rtree/rtree.cabal b/rtree/rtree.cabal index 62066a4..dbc30ab 100644 --- a/rtree/rtree.cabal +++ b/rtree/rtree.cabal @@ -1,6 +1,6 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.2. +-- This file has been generated from package.yaml by hpack version 0.36.1. -- -- see: https://github.com/sol/hpack @@ -13,7 +13,6 @@ library Control.Monad.IRTree Control.Monad.Reduce Control.Monad.RTree - Control.Monad.RTree.Simple Data.RPath Data.Valuation other-modules: diff --git a/rtree/src/Control/Monad/IRTree.hs b/rtree/src/Control/Monad/IRTree.hs index 0f92d17..f6d4b2e 100644 --- a/rtree/src/Control/Monad/IRTree.hs +++ b/rtree/src/Control/Monad/IRTree.hs @@ -37,6 +37,7 @@ import Control.Monad.Reader import Control.Monad.Reduce import Data.Bits import Data.Foldable +import Data.Monoid import Data.Function import Data.Functor import Data.Functor.Identity diff --git a/rtree/src/Control/Monad/RTree.hs b/rtree/src/Control/Monad/RTree.hs index 2cf8793..2337088 100644 --- a/rtree/src/Control/Monad/RTree.hs +++ b/rtree/src/Control/Monad/RTree.hs @@ -36,9 +36,9 @@ module Control.Monad.RTree ( import Control.Monad import Control.Monad.Identity import Control.Monad.Reduce -import Data.Foldable import Data.Foldable.WithIndex -import Data.Function ((&)) +import Data.Function ((&), fix) +import Data.Foldable import Data.RPath import qualified Data.Sequence as Seq diff --git a/rtree/src/Control/Monad/RTree/Simple.hs b/rtree/src/Control/Monad/RTree/Simple.hs deleted file mode 100644 index 73ab863..0000000 --- a/rtree/src/Control/Monad/RTree/Simple.hs +++ /dev/null @@ -1,29 +0,0 @@ -{-# LANGUAGE BlockArguments #-} -{-# LANGUAGE DerivingVia #-} - -module Control.Monad.RTree.Simple where - -import Control.Monad.Identity -import Control.Monad.State - -type RTree a = State ([Bool], Int) a - -check :: RTree Bool -check = state \(c : cs, n) -> (c, (cs, n + 1)) - -probe :: RTree a -> [Bool] -> (a, Int) -probe root path = (extract, depth - length path) - where - (extract, (_, depth)) = runState root (path ++ repeat False, 0) - -reduce :: (a -> IO Bool) -> RTree a -> [Bool] -> IO a -reduce predicate root path - | undecided > 0 = do - result <- predicate (fst (probe root (path ++ [True]))) - reduce predicate root (path ++ [result]) - | otherwise = pure extract - where - (extract, undecided) = probe root path - -reduceAbc :: RTree [Char] -reduceAbc = filterM (\_ -> check) "abc" -- GitLab