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

Tutorial / walkthrough please #4

Open
joelburget opened this issue Jul 3, 2018 · 8 comments
Open

Tutorial / walkthrough please #4

joelburget opened this issue Jul 3, 2018 · 8 comments

Comments

@joelburget
Copy link

These libraries (dimensions / easytensor) look useful and interesting. Unfortunately it's not clear how to get started. Some examples / tutorial would be much appreciated!

@achirkin
Copy link
Owner

achirkin commented Jul 3, 2018

Thanks for the comment, work on this is in progress!

In the meanwhile, you can find some rudimentary examples documentation-and-tutorials section of the readme.

@Rotaerk
Copy link
Contributor

Rotaerk commented Jul 28, 2018

Just wanted to say I'm learning a lot reading through the implementation of easytensor. And slowly going crazy... :P

@achirkin
Copy link
Owner

Ha-ha, sorry :)
While I don't have time for a full tutorial at this moment, you may ask here about specific parts in the project and I will quickly haddock more elaborate descriptions.

@joelburget
Copy link
Author

Documentation of functions / datatypes is not the problem for me. What I need is one or two simple examples for each project of how it's intended to be used.

@Rotaerk
Copy link
Contributor

Rotaerk commented Jul 28, 2018

One thing I'm unclear on is why you would ever use XN n for any n > 0. What do you get out of statically knowing that that dimension has at least n elements?

For instance, in this snippet, the data frame will have 7 vertices; why specify that it's statically unknown but at least 3? Why not 0, or 7?

achirkin referenced this issue in achirkin/vulkan Jul 29, 2018
@achirkin
Copy link
Owner

achirkin commented Jul 29, 2018

@joelburget yes, I understand that. I will add the tutorial as soon as finish writing my thesis (likely in September , sorry for that)

@Rotaerk In general, XN n is meant for data import. Imagine something like this:

importCsv :: FilePath -> IO (Either String (DataFrame Vertex '[XN 1]))

The function above reads a non-empty data frame or fails. We cannot index DataFrame using Nat here, because we don't know dimensionality in advance. On the other hand, we may want to reject the imported file if it has too few lines.
In vulkan-triangles, the constraint comes not from the data, but from the program logic: shader pipeline requires at least 3 vertices to draw at least one triangle primitive. I decided, that would be handy to declare explicitly. Added a comment to the code.

@Rotaerk
Copy link
Contributor

Rotaerk commented Aug 5, 2018

Well, I was going to write up something about having issues with getting XFrame matching to work, but it turns out it was resolved by adding more type annotations to unrelated functions in my code... However, the type errors were rather troublesome to make sense of, and I only accidentally got it working.

In the commit Rotaerk/vulkanTest@033701b, I wanted to move the XFrame matching outside of the createVertexBuffer and fillVertexbufferMemory functions. So I moved it up into the beginning of main, and indented the entire runResourceT block to be inside of it.

Problems I encountered while working on this change:

  1. It took me some work to figure out what type to give the revised fillVertexBufferMemory function. I initially tried DataFrame Vertex (ns :: [Nat]), but that gave me this error:

    src/Main.hs:723:70: error:
        • Overlapping instances for PrimBytes
                                      (Numeric.DataFrame.Internal.Array.Family.Array Vertex ns)
            arising from a use of ‘bSizeOf’
          Matching instances:
            instance [overlappable] (VulkanMarshalPrim a, Storable a) =>
                                    PrimBytes a
              -- Defined in ‘Graphics.Vulkan.Marshal.Create.DataFrame’
            instance (PrimBytes a, PrimBytes b) => PrimBytes (Either a b)
              -- Defined in ‘Numeric.PrimBytes’
            instance PrimBytes Int16 -- Defined in ‘Numeric.PrimBytes’
            ...plus 15 others
            ...plus 13 instances involving out-of-scope types
            (use -fprint-potential-instances to see them all)
          (The choice depends on the instantiation of ‘ns’
           To pick the first instance above, use IncoherentInstances
           when compiling the other instance declarations)
        • In the second argument of ‘($)’, namely ‘bSizeOf vertices’
          In the fourth argument of ‘mappedMemory’, namely
            ‘(fromIntegral $ bSizeOf vertices)’
          In the first argument of ‘with’, namely
            ‘(mappedMemory
                device vertexBufferMemory 0 (fromIntegral $ bSizeOf vertices))’
        |
    723 |       with (mappedMemory device vertexBufferMemory 0 (fromIntegral $ bSizeOf vertices)) $ \ptr ->
        |                                                                      ^^^^^^^^^^^^^^^^
    

    I'm still not really sure how I would give it a DataFrame type, but I was able to get it to work with the more generic type that it has now.

  2. In addition to making the obvious code changes, I also had to add type annotations to maxFramesInFlight and to evalStateTWith. Without them, I got some pretty strange type errors. It seems odd that this would be suddenly required just because these things are used inside of the XFrame case.

@achirkin
Copy link
Owner

achirkin commented Aug 7, 2018

Looks like I messed up with instances of PrimBytes. I have created an issue #9 to improve the situation with that.

In general, whenever you encounter Overlapping instances error, you should first check if there is any instance in scope that satisfies the class constraint.
In your case, GHC does not know which instance of Array type family is used inside the DataFrame and, thus, cannot find a suitable type class instance for PrimBytes. Thus, you need to provide the instances explicitly. The XNat-indexed DataFrame carries only a few instances for a Nat-indexed DataFrame behind its existential constructor. If you need any more instance in the scope of pattern match, you can use inference functions, e.g.

case xdf of
  XFrame df
    | E <- inferPrim df -> do
       ... -- df has an instance of PrimBytes here

Most commonly required inference functions are given by DataFrameInference class.

As for the second problem, cannot really say right now, without trying it myself.

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

No branches or pull requests

3 participants