clash-lang / ghc-typelits-extra

Extra type-level operations on GHC.TypeLits.Nat and a custom solver
Other
16 stars 9 forks source link

Could not deduce: `CLog 2 (n * 2)` ~ `CLog 2 n + 1` #42

Open martijnbastiaan opened 2 years ago

martijnbastiaan commented 2 years ago

This should hold for all n*, but the plugin doesn't infer it.

*For n ~ 0 the answer is undefined in both cases

martijnbastiaan commented 2 years ago

A workaround would be to define:

import Data.Type.Equality ((:~:)(Refl))
import Unsafe.Coerce (unsafeCoerce)

clog2axiom :: (CLog 2 (n * 2)) :~: ((CLog 2 n) + 1)
clog2axiom = unsafeCoerce Refl

And use it like:

coerceIndices :: forall n. (KnownNat n, 1 <= n) => Index (n*2) -> (Index n, Bool)
coerceIndices = case clog2axiom @n of Refl -> bitCoerce
martijnbastiaan commented 2 years ago

@rowanG077 mentioned that we should be able to add this derivation by patching:

https://github.com/clash-lang/ghc-typelits-extra/blob/fe80881503c8ba80c86f17fbdaf481dcd1304d44/src/GHC/TypeLits/Extra/Solver/Operations.hs#L191

martijnbastiaan commented 2 years ago

Finally, some "proof" that this equation holds:

>>> import Clash.Util (clogBase)
>>> import Test.QuickCheck (quickCheck, withMaxSuccess)
>>> clog2 = clogBase 2
>>> prop_eq n = (clog2 (n*2)) == (succ <$> clog2 n)
>>> quickCheck (withMaxSuccess 1000000 prop_eq)
+++ OK, passed 1000000 tests.