-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop-update-arrays'. Close #36.
**Description** Copilot currently supports reading values from streams of arrays, but not changing them. We'd like to be able to modify an array by adjusting the value at a specific position. **Type** - Feature: new extension to the language. **Additional context** None. **Requester** - Ivan Perez **Method to check presence of bug** No applicable (not a bug). **Expected result** Copilot provides a mechanism to update elements in an array. The following Dockerfile installs copilot and runs a file with struct update operations, which it then links and compares against its expected output, printing the message "Success" if the output matches the expectation: ``` --- Dockerfile FROM ubuntu:focal ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update RUN apt-get install --yes libz-dev RUN apt-get install --yes git RUN apt-get install --yes wget RUN mkdir -p $HOME/.ghcup/bin RUN wget https://downloads.haskell.org/~ghcup/0.1.19.2/x86_64-linux-ghcup-0.1.19.2 -O $HOME/.ghcup/bin/ghcup RUN chmod a+x $HOME/.ghcup/bin/ghcup ENV PATH=$PATH:/root/.ghcup/bin/ ENV PATH=$PATH:/root/.cabal/bin/ RUN apt-get install --yes curl RUN apt-get install --yes gcc g++ make libgmp3-dev RUN apt-get install --yes pkg-config SHELL ["/bin/bash", "-c"] RUN ghcup install ghc 9.4 RUN ghcup install cabal 3.2 RUN ghcup set ghc 9.4.8 RUN cabal update ADD Arrays.hs /tmp/Arrays.hs ADD main.c /tmp/main.c ADD expected /tmp/expected CMD git clone $REPO \ && cd $NAME \ && git checkout $COMMIT \ && cabal v1-sandbox init \ && cabal v1-install alex happy \ && cabal v1-install copilot**/ \ && cabal v1-exec -- runhaskell /tmp/Arrays.hs \ && mv /tmp/main.c . \ && gcc main.c arrays.c -o main \ && ./main > actual \ && diff actual /tmp/expected \ && echo Success --- Arrays.hs {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE NoImplicitPrelude #-} module Main (main) where import Copilot.Compile.C99 import Data.Type.Equality as DE import Language.Copilot -- Sample values arr :: Stream (Array 2 Float) arr = [ array [1.0, 2.5] , array [2.5, 1.0] ] ++ arr arr1 = (arr !! 1 =$ (+1)) !! 0 =$ (+100) arr2 = arr1 !! 1 =$ ([0.0] ++) spec :: Spec spec = do trigger "arrays" true [arg arr2] main :: IO () main = do spec' <- reify spec compile "arrays" spec' --- main.c #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include "arrays.h" #include "arrays_types.h" void arrays( float* arrays_arg0 ) { printf("%f %f\n" , arrays_arg0[0] , arrays_arg0[1]); } int main() { step(); step(); step(); step(); } --- expected 101.000000 0.000000 102.500000 3.500000 101.000000 2.000000 102.500000 3.500000 ``` Command (substitute variables based on new path after merge): ``` $ docker run -e "REPO=https://github.com/Copilot-Language/copilot" -e "NAME=copilot" -e "COMMIT=<HASH>" -it copilot-verify-36 ``` **Solution implemented** Extend `copilot-language` to provide operations to modify values of arrays in streams, with a syntax that is uniform for structs and arrays. Extend `copilot-core`, `copilot-c99`, `copilot-theorem`, `copilot-interpreter` and `copilot-prettyprinter` as needed. Provide examples that demonstrate the new features. Provide (!) alternative to (.!!) to make syntax uniform. Adjust examples to use (!). Hide (!!) in copilot-libraries, and provide an alternative (!!!). **Further notes** None.
- Loading branch information
Showing
24 changed files
with
420 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,89 @@ | ||
{-# LANGUAGE Safe #-} | ||
|
||
{-# LANGUAGE TypeFamilies #-} | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE MultiParamTypeClasses #-} | ||
{-# LANGUAGE Safe #-} | ||
{-# LANGUAGE TypeFamilies #-} | ||
-- The following warning is disabled due to a necessary instance of Projectable | ||
-- defined in this module. | ||
{-# OPTIONS_GHC -fno-warn-orphans #-} | ||
|
||
-- | Combinators to deal with streams carrying arrays. | ||
module Copilot.Language.Operators.Array | ||
( (.!!) | ||
, (!) | ||
, (!!) | ||
, (=:) | ||
, (=$) | ||
) where | ||
|
||
import Copilot.Core ( Typed | ||
, Op2 (Index) | ||
, typeOf | ||
, Array | ||
) | ||
import Copilot.Language.Stream (Stream (..)) | ||
import Copilot.Core (Array, Op2 (Index), | ||
Op3 (UpdateArray), Typed, typeOf) | ||
import Copilot.Language.Operators.Projection (Projectable(..)) | ||
import Copilot.Language.Stream (Stream (..)) | ||
|
||
import Data.Word (Word32) | ||
import GHC.TypeLits (KnownNat) | ||
import Prelude hiding ((!!)) | ||
|
||
import Data.Word (Word32) | ||
import GHC.TypeLits (KnownNat) | ||
-- | Create a stream that carries an element of an array in another stream. | ||
-- | ||
-- This function implements a projection of the element of an array at a given | ||
-- position, over time. For example, if @s@ is a stream of type @Stream (Array | ||
-- '5 Word8)@, then @s ! 3@ has type @Stream Word8@ and contains the 3rd | ||
-- element (starting from zero) of the arrays in @s@ at any point in time. | ||
(!) :: (KnownNat n, Typed t) | ||
=> Stream (Array n t) -> Stream Word32 -> Stream t | ||
arr ! n = Op2 (Index typeOf) arr n | ||
|
||
-- | Create a stream that carries an element of an array in another stream. | ||
-- | ||
-- This function implements a projection of the element of an array at a given | ||
-- position, over time. For example, if @s@ is a stream of type @Stream (Array | ||
-- '5 Word8)@, then @s .!! 3@ has type @Stream Word8@ and contains the 3rd | ||
-- element (starting from zero) of the arrays in @s@ at any point in time. | ||
{-# DEPRECATED (.!!) "This function is deprecated in Copilot 4. Use (!)." #-} | ||
(.!!) :: ( KnownNat n | ||
, Typed t | ||
) => Stream (Array n t) -> Stream Word32 -> Stream t | ||
arr .!! n = Op2 (Index typeOf) arr n | ||
(.!!) = (!) | ||
|
||
-- | Pair a stream with an element accessor, without applying it to obtain the | ||
-- value of the element. | ||
-- | ||
-- This function is needed to refer to an element accessor when the goal is to | ||
-- update the element value, not just to read it. | ||
(!!) :: Stream (Array n t) | ||
-> Stream Word32 | ||
-> Projection (Array n t) (Stream Word32) t | ||
(!!) = ProjectionA | ||
|
||
-- | Update a stream of arrays. | ||
|
||
-- This is an orphan instance; we suppress the warning that GHC would | ||
-- normally produce with a GHC option at the top. | ||
instance (KnownNat n, Typed t) => Projectable (Array n t) (Stream Word32) t where | ||
|
||
-- | A projection of an element of a stream of arrays. | ||
data Projection (Array n t) (Stream Word32) t = | ||
ProjectionA (Stream (Array n t)) (Stream Word32) | ||
|
||
-- | Create a stream where an element of an array has been updated with | ||
-- values from another stream. | ||
-- | ||
-- For example, if an array has two elements of type @Int32@, and @s@ is a | ||
-- stream of such array type (@Stream (Array 2 Int32)@), and $v0$ is a stream | ||
-- of type @Int32@, then @s !! 0 =: v0@ has type @Stream (Array 2 Int32)@ and | ||
-- contains arrays where the value of the first element of each array is that | ||
-- of @v0@ at each point in time, and the value of the second element in the | ||
-- array is the same it had in @s@. | ||
(=:) (ProjectionA s ix) v = Op3 (UpdateArray typeOf) s ix v | ||
|
||
-- | Create a stream where an element of an array has been updated by | ||
-- applying a stream function to it. | ||
-- | ||
-- For example, if an array has two elements of type @Int32@, and @s@ is a | ||
-- stream of such array type (@Stream (Array 2 Int32)@), and $f$ is function | ||
-- of type @Stream Int32 -> Stream Int32@, then @s !! 0 =$ f@ has type | ||
-- @Stream (Array 2 Int32)@ and contains arrays where the value of the first | ||
-- element of each array is that of @f (s ! 0)@ at each point in time, and | ||
-- the value of the second element in the array is the same it had in @s@. | ||
(=$) (ProjectionA s ix) op = Op3 (UpdateArray typeOf) s ix (op (s ! ix)) |
38 changes: 38 additions & 0 deletions
38
copilot-language/src/Copilot/Language/Operators/Projection.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE FunctionalDependencies #-} | ||
{-# LANGUAGE TypeFamilies #-} | ||
-- | Interface to access portions of a larger data structure. | ||
-- | ||
-- Default operations to access elements from structs and arrays (e.g., a field | ||
-- of a struct, an element of an array) allow obtaining the values of those | ||
-- elements, but not modifying. | ||
-- | ||
-- This module defines a common interface to manipulate portions of a larger | ||
-- data structure. We define the interface in a generic way, using a type | ||
-- class with two operations: one to set the value of the sub-element, and | ||
-- one to update the value of such element applying a stream function. | ||
module Copilot.Language.Operators.Projection | ||
( Projectable (..) ) | ||
where | ||
|
||
import Copilot.Language.Stream (Stream) | ||
|
||
infixl 8 =: | ||
infixl 8 =$ | ||
|
||
-- | Common interface to manipulate portions of a larger data structure. | ||
-- | ||
-- A projectable d s t means that it is possible to manipulate a sub-element s | ||
-- of type t carried in a stream of type d.. | ||
class Projectable d s t | d s -> t where | ||
|
||
-- | Unapplied projection or element access on a type. | ||
data Projection d s t | ||
|
||
-- | Modify the value of a sub-element of a type in a stream of elements | ||
-- of that type. | ||
(=:) :: Projection d s t -> Stream t -> Stream d | ||
|
||
-- | Update the value of a sub-element of a type in a stream of elements of | ||
-- that type, by applying a function on streams. | ||
(=$) :: Projection d s t -> (Stream t -> Stream t) -> Stream d |
Oops, something went wrong.