Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Errors with Natural #99

Open
martyall opened this issue Jan 3, 2024 · 12 comments · Fixed by #102
Open

Errors with Natural #99

martyall opened this issue Jan 3, 2024 · 12 comments · Fixed by #102

Comments

@martyall
Copy link

martyall commented Jan 3, 2024

I was using to the plug-in, and part of my program involved an (==) expression on this type. The plug-in threw the following exception:

ghc: panic! (the 'impossible' happened)
  (GHC version 9.0.2:
	Categorifier failed to categorify the following expression:
\ (ds_dIjG :: (F_BN128, F_BN128)) ->
  case ds_dIjG of { (x, y) ->
  let {
    x_sIkK
      :: Prime
           21888242871839275222246405745257275088548364400416034343698204186575808495617
    [LclId,
     Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=False,
             WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 350 0}]
    x_sIkK
      = let {
          $dKnownNat_sIkE :: Natural
          [LclId,
           Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
                   WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 100 0}]
          $dKnownNat_sIkE
            = 21888242871839275222246405745257275088548364400416034343698204186575808495617 } in
        let {
          $dNum_aIiq :: Num F_BN128
          [LclId,
           Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=True,
                   WorkFree=False, Expandable=True, Guidance=IF_ARGS [] 20 0}]
          $dNum_aIiq
            = $fNumPrime
                @21888242871839275222246405745257275088548364400416034343698204186575808495617
                ($dKnownNat_sIkE
                 `cast` (Sym (N:SNat[0]
                                  <21888242871839275222246405745257275088548364400416034343698204186575808495617>_P) ; Sym (N:KnownNat[0]) <21888242871839275222246405745257275088548364400416034343698204186575808495617>_N
                         :: Coercible
                              Natural
                              (KnownNat
                                 21888242871839275222246405745257275088548364400416034343698204186575808495617))) } in
        - @F_BN128
          $dNum_aIiq
          (+ @F_BN128 $dNum_aIiq x (fromInteger @F_BN128 $dNum_aIiq 7))
          y } in
  let {
    y_sIkL
      :: Prime
           21888242871839275222246405745257275088548364400416034343698204186575808495617
    [LclId,
     Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=False,
             WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 130 0}]
    y_sIkL = fromInteger @F_BN128 $dNum_aIhK 0 } in
  case case x_sIkK
            `cast` (N:Prime[0] <21888242871839275222246405745257275088548364400416034343698204186575808495617>_N ; N:Mod[0]
                                                                                                                       <21888242871839275222246405745257275088548364400416034343698204186575808495617>_P
                    :: Coercible
                         (Prime
                            21888242871839275222246405745257275088548364400416034343698204186575808495617)
                         Natural)
       of x1
       { __DEFAULT ->
       case y_sIkL
            `cast` (N:Prime[0] <21888242871839275222246405745257275088548364400416034343698204186575808495617>_N ; N:Mod[0]
                                                                                                                       <21888242871839275222246405745257275088548364400416034343698204186575808495617>_P
                    :: Coercible
                         (Prime
                            21888242871839275222246405745257275088548364400416034343698204186575808495617)
                         Natural)
       of y1
       { __DEFAULT ->
       case naturalEq# x1 y1 of wild { __DEFAULT ->
       tagToEnum# @Bool wild
       }
       }
       }
  of {
    False -> fromInteger @F_BN128 $dNum_aIhK 0;
    True -> fromInteger @F_BN128 $dNum_aIhK 42
  }
  }
  - The Categorifier plugin was unable to inline naturalEq#

My understanding from the discord thread is that the expression had been optimized to the underlying Natural type by the time it hit the plug-in, and there is apparently no support for Natural.

I guess I either need (1) to add support for Natural to the plugin or (2) better understand what classes need to be implemented in order to compile the Prime p type. It is also a supported object in my target category.

You can find the offending program here:
https://github.com/martyall/straw/blob/snarkl-json-update/examples/Examples/Arithmetic.hs#L50-L64

@sellout
Copy link
Member

sellout commented Jan 15, 2024

@martyall Can you try this with the branch from #102? I’m having trouble getting your fork of straw to build. You’ll need to add the extra flags, etc. mentioned in the commend on that PR.

@martyall
Copy link
Author

So I think I'm including everything, but I'm still getting the same error. I see that you have added support for naturalEq in that branch, so I don't really understand.

here is the diff and commit you can try to build from:
l-adic/stalk@2894049

(NOTE: the github org on that url is no longer martyall, we moved everything over. however, curious why the build failed for you. If you are using the flake shell (nix develop) and building with cabal, it would hopefully work...)

@sellout
Copy link
Member

sellout commented Jan 17, 2024

I’m not too surprised. If you look at the error, you see naturalEq#, not naturalEq. The former has the type Natural# -> Natural# -> Bool – those # means the type is “unlifted” and they actually have a different kind than Type.

For a few reasons (which I’m happy to get into) the plugin doesn’t support unlifted types (I need to document that). But most operations on unlifted types have a lifted equivalent. And it’s a matter of catching the operation before it’s been inlined far enough to get down to unlifted types.

That PR has the initial work for Natural support, but I basically crossed my fingers that it’d work without any additional changes to manage the inlining.

Re: building Straw, I don’t know why I didn’t try that. I had only tried nix build …. But I’ll go back to it now, and probably I can replicate the issue.

@martyall
Copy link
Author

Re: building Straw, I don’t know why I didn’t try that. I had only tried nix build …. But I’ll go back to it now, and probably I can replicate the issue.

Also in case it helps you can use this binary cache which has all the stuff
martyall.cachix.org-1:CrJFPxvYeNEFevcbWAD/Hj1NYu9mtGbLh6Bojvc9TBE=

@zliu41
Copy link
Member

zliu41 commented Jan 18, 2024

The plugin needs to have the ability to output something similar to a stack trace, which will make it a lot easier to figure out where naturalEq# is introduced. Showing just the last CoreExpr is rarely helpful.

@sellout
Copy link
Member

sellout commented Jan 19, 2024

Sorry, this was not fixed by #102 (as discussed above). I just forgot to fix the description of that PR before merging.

@sellout sellout reopened this Jan 19, 2024
@martyall
Copy link
Author

martyall commented Jan 23, 2024

@sellout Just wanted to check in on this one. After thinking about it a little bit, I could also change the underlying representation of Prime to be Integer instead of Mod, which AFAIK the plugin supports. This would require some amount of work on my fork, but maybe it's easier than making this change for the plugin ?

@sellout
Copy link
Member

sellout commented Jan 23, 2024

I don’t think Integer will be any better. Both it and Natural changed the same way with GHC 9.0. GHC 8.10 shouldn’t have this issue, if your code would work with that for the time being. However, I really want to fix this in the plugin.

I did manage to replicate the issue locally, and I think I know what needs to change. I can try to make those changes today. In parallel, I also want to write more documentation on how to debug this and how to extend the plugin properly (took long enough to get it back in my head that there clearly needs to be more explanation if anyone else is going to have a chance).

@martyall
Copy link
Author

martyall commented Jan 23, 2024

I didn't try it with raw Integer, but I did just swap out the implementation of galois-fields to use this instead

https://hackage.haskell.org/package/modular-arithmetic-2.0.0.3/docs/Data-Modular.html

instantiating newtype Prime p = Prime (Mod Integer p)

which resulted in an even stranger error message

ghc: panic! (the 'impossible' happened)
  (GHC version 9.0.2:
	Categorifier failed to categorify the following expression:
\ (ds_db4C :: (F_BN128, F_BN128)) ->
  case ds_db4C of { (x, y) ->
  let {
    x_sdV6
      :: Prime
           21888242871839275222246405745257275088548364400416034343698204186575808495617
    [LclId,
     Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=False,
             WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 380 0}]
    x_sdV6
      = let {
          $dKnownNat_sdU4 :: Natural
          [LclId,
           Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
                   WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 100 0}]
          $dKnownNat_sdU4
            = 21888242871839275222246405745257275088548364400416034343698204186575808495617 } in
        let {
          $d~_aalD :: 'True ~ 'True
          [LclId,
           Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
                   WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 0 10}]
          $d~_aalD
            = Eq# @Bool @'True @'True @~(<'True>_N :: 'True ~ 'True) } in
        let {
          $d(%,%)_aalB
            :: (KnownNat
                  21888242871839275222246405745257275088548364400416034343698204186575808495617,
                'True ~ 'True)
          [LclId,
           Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
                   WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
          $d(%,%)_aalB
            = ($dKnownNat_sdU4
               `cast` (Sym (N:SNat[0]
                                <21888242871839275222246405745257275088548364400416034343698204186575808495617>_P) ; Sym (N:KnownNat[0]) <21888242871839275222246405745257275088548364400416034343698204186575808495617>_N
                       :: Coercible
                            Natural
                            (KnownNat
                               21888242871839275222246405745257275088548364400416034343698204186575808495617)),
               $d~_aalD) } in
        let {
          $dNum_aals :: Num F_BN128
          [LclId,
           Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=True,
                   WorkFree=False, Expandable=True, Guidance=IF_ARGS [] 20 0}]
          $dNum_aals
            = $fNumPrime
                @21888242871839275222246405745257275088548364400416034343698204186575808495617
                ($d(%,%)_aalB
                 `cast` (((%,%)
                            <KnownNat
                               21888242871839275222246405745257275088548364400416034343698204186575808495617>_N
                            ((~)
                               <Bool>_N
                               (Sym (LeqDef (<1>_N,
                                             <21888242871839275222246405745257275088548364400416034343698204186575808495617>_N)))
                               <'True>_N)_N)_R
                         :: Coercible
                              (KnownNat
                                 21888242871839275222246405745257275088548364400416034343698204186575808495617,
                               'True ~ 'True)
                              (KnownNat
                                 21888242871839275222246405745257275088548364400416034343698204186575808495617,
                               (1
                                <=? 21888242871839275222246405745257275088548364400416034343698204186575808495617)
                               ~ 'True))) } in
        - @F_BN128
          $dNum_aals
          (+ @F_BN128 $dNum_aals x (fromInteger @F_BN128 $dNum_aals 7))
          y } in
  let {
    y_sdV7
      :: Prime
           21888242871839275222246405745257275088548364400416034343698204186575808495617
    [LclId,
     Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=False,
             WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 130 0}]
    y_sdV7 = fromInteger @F_BN128 $dNum_aa9f 0 } in
  case case x_sdV6
            `cast` (N:Prime[0] <21888242871839275222246405745257275088548364400416034343698204186575808495617>_N ; N:Mod[0]
                                                                                                                       <Integer>_R
                                                                                                                       <21888242871839275222246405745257275088548364400416034343698204186575808495617>_P
                    :: Coercible
                         (Prime
                            21888242871839275222246405745257275088548364400416034343698204186575808495617)
                         Integer)
       of x1
       { __DEFAULT ->
       case y_sdV7
            `cast` (N:Prime[0] <21888242871839275222246405745257275088548364400416034343698204186575808495617>_N ; N:Mod[0]
                                                                                                                       <Integer>_R
                                                                                                                       <21888242871839275222246405745257275088548364400416034343698204186575808495617>_P
                    :: Coercible
                         (Prime
                            21888242871839275222246405745257275088548364400416034343698204186575808495617)
                         Integer)
       of y1
       { __DEFAULT ->
       case integerEq# x1 y1 of wild { __DEFAULT ->
       tagToEnum# @Bool wild
       }
       }
       }
  of {
    False -> fromInteger @F_BN128 $dNum_aa9f 0;
    True -> fromInteger @F_BN128 $dNum_aa9f 42
  }
  }
  - Categorifier encountered a primop-related expression it can't handle at 'replacePrimOps':
        CO: <'True>_N
    (seen 1 time)

Please report this as a GHC bug:  https://www.haskell.org/ghc/reportabug

Error: cabal: Failed to build test:examples from straw-0.1.0.0.

My GHC Core skills aren't strong enough to know exactly what this means, but it seems like it doesn't like the value level witness for some kind of type equality check

let {
          $d~_aalD :: 'True ~ 'True
          [LclId,
           Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
                   WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 0 10}]
          $d~_aalD
            = Eq# @Bool @'True @'True @~(<'True>_N :: 'True ~ 'True) } in

FWIW I am using GHC 9.0.2

Thanks for tracking this down, I look forward to whatever solution ends up working. I am also eager to learn more, so it's interesting to me to see these changes coming in :)

@martyall
Copy link
Author

I don’t think Integer will be any better. Both it and Natural changed the same way with GHC 9.0. GHC 8.10 shouldn’t have this issue, if your code would work with that for the time being. However, I really want to fix this in the plugin.

Are you saying that this should JustWork™ (with the Natural based galois-fields implementation) if I switch to 8.10 ?

@sellout
Copy link
Member

sellout commented Jan 24, 2024

Are you saying that this should JustWork™ (with the Natural based galois-fields implementation) if I switch to 8.10 ?

Well, I think at least this particular problem should go away. I.e., == should work the way + and * do in the simpleArith example.

@martyall
Copy link
Author

I don’t think Integer will be any better. Both it and Natural changed the same way with GHC 9.0. GHC 8.10 shouldn’t have this issue, if your code would work with that for the time being. However, I really want to fix this in the plugin.

What you're saying tracks with my experience. I ripped out all of this type witness nonsense from the Integer based implementation in modular-arithmetic and got a similar error as before:

  - The Categorifier plugin was unable to inline integerEq#
  ((let {
      $dKnownNat_sdSS :: Natural
      [LclId]
      $dKnownNat_sdSS
        = 21888242871839275222246405745257275088548364400416034343698204186575808495617 } in
    let {
      $dNum_aakk :: Num F_BN128
      [LclId]
      $dNum_aakk
        = $fNumPrime
            @21888242871839275222246405745257275088548364400416034343698204186575808495617
            ($dKnownNat_sdSS
             `cast` (Sym (N:SNat[0]
                              <21888242871839275222246405745257275088548364400416034343698204186575808495617>_P) ; Sym (N:KnownNat[0]) <21888242871839275222246405745257275088548364400416034343698204186575808495617>_N
                     :: Coercible
                          Natural
                          (KnownNat
                             21888242871839275222246405745257275088548364400416034343698204186575808495617))) } in
    - @F_BN128
      $dNum_aakk
      (+ @F_BN128
         $dNum_aakk
         (fst @F_BN128 @F_BN128 ds_db3l)
         (fromInteger @F_BN128 $dNum_aakk 7))
      (snd @F_BN128 @F_BN128 ds_db3l))
   `cast` (N:Prime[0] <21888242871839275222246405745257275088548364400416034343698204186575808495617>_N ; N:Mod[0]
                                                                                                              <Integer>_R
                                                                                                              <21888242871839275222246405745257275088548364400416034343698204186575808495617>_P
           :: Coercible
                (Prime
                   21888242871839275222246405745257275088548364400416034343698204186575808495617)
                Integer))
  y1.
    There is no unfolding available for the identifier. It's possible that the
    identifier is an unspecialized type class method (methods never have
    unfoldings), a name used for `RebindableSyntax`, or that the unfolding
    somehow didn't get from the definition point to the module that called
   `categorify`. 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants