-- Copyright (c) 2009-2010, ERICSSON AB-- All rights reserved.---- Redistribution and use in source and binary forms, with or without-- modification, are permitted provided that the following conditions are met:---- * Redistributions of source code must retain the above copyright notice,-- this list of conditions and the following disclaimer.-- * Redistributions in binary form must reproduce the above copyright-- notice, this list of conditions and the following disclaimer in the-- documentation and/or other materials provided with the distribution.-- * Neither the name of the ERICSSON AB nor the names of its contributors-- may be used to endorse or promote products derived from this software-- without specific prior written permission.---- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-- | A high-level interface to the operations in the core language-- ("Feldspar.Core"). Many of the functions defined here are imitations of-- Haskell's list operations, and to a first approximation they behave-- accordingly.---- A symbolic vector ('Vector') can be thought of as a representation of a-- 'parallel' core array. This view is made precise by the function-- 'freezeVector', which converts a symbolic vector to a core vector using-- 'parallel'.---- 'Vector' is instantiated under the 'Computable' class, which means that-- symbolic vectors can be used quite seamlessly with the interface in-- "Feldspar.Core".---- Note that the only operations in this module that introduce storage (through-- core arrays) are---- * 'freezeVector'---- * 'memorize'---- * 'vector'---- * 'unfoldVec'---- * 'unfold'---- * 'scan'---- * 'mapAccum'---- This means that vector operations not involving these operations will be-- completely \"fused\" without using any intermediate storage.---- Note also that most operations only introduce a small constant overhead on-- the vector. The exceptions are---- * 'dropWhile'---- * 'fold'---- * 'fold1'---- * Functions that introduce storage (see above)---- * \"Folding\" functions: 'sum', 'maximum', etc.---- These functions introduce overhead that is linear in the length of the-- vector.---- Finally, note that 'freezeVector' can be introduced implicitly by functions-- overloaded by the 'Computable' class. This means that, for example,-- @`printCore` f@, where @f :: Vector (Data Int) -> Vector (Data Int)@, will-- introduce storage for the input and output of @f@.moduleFeldspar.VectorwhereimportqualifiedPreludeimportControl.Arrow((&&&))importqualifiedData.List-- Only for documentation of 'unfold'importFeldspar.PreludeimportFeldspar.RangeimportFeldspar.Core.ExprimportFeldspar.Core-- * Types-- | Vector indextypeIx=Int-- | Symbolic vectordataVectora=Indexed{length::DataLength,index::DataIx->a}-- | Short-hand for non-nested parallel vectortypeDVectora=Vector(Dataa)-- * Construction/conversion-- | Converts a non-nested vector to a core vector.freezeVector::Storablea=>Vector(Dataa)->Data[a]freezeVector(Indexedlixf)=parallellixf-- | Converts a non-nested core vector to a parallel vector.unfreezeVector::Storablea=>DataLength->Data[a]->Vector(Dataa)unfreezeVectorlarr=Indexedl(getIxarr)-- | Optimizes vector lookup by computing all elements and storing them in a-- core array.memorize::Storablea=>Vector(Dataa)->Vector(Dataa)memorizevec=unfreezeVector(lengthvec)$freezeVectorvec-- XXX Should be generalized to arbitrary dimensions.indexed::DataLength->(DataIx->a)->Vectoraindexed=Indexed-- | Constructs a non-nested vector. The elements are stored in a core vector.vector::Storablea=>[a]->Vector(Dataa)vectoras=unfreezeVectorl(valueas)wherel=value$Prelude.lengthas-- XXX Should be generalized to arbitrary dimensions.modifyLength::(DataLength->DataLength)->Vectora->VectoramodifyLengthfvec=vec{length=f(lengthvec)}setLength::DataLength->Vectora->VectorasetLength=modifyLength.constboundVector::Int->Vectora->VectoraboundVectormaxLen=modifyLength(capr)wherer=negativeRange+singletonRange(fromIntegralmaxLen)+1-- XXX fromIntegral might not be needed in future.instanceStorablea=>Computable(Vector(Dataa))wheretypeInternal(Vector(Dataa))=(Length,[Internal(Dataa)])internalizevec=internalize(lengthvec,freezeVector$mapinternalizevec)externalizel_a=mapexternalize$unfreezeVectorlawherel=externalize$exprToData$Get21l_aa=externalize$exprToData$Get22l_ainstanceStorablea=>Computable(Vector(Vector(Dataa)))wheretypeInternal(Vector(Vector(Dataa)))=(Length,[Length],[[Internal(Dataa)]])internalizevec=internalize(lengthvec,freezeVector$maplengthvec,freezeVector$map(freezeVector.mapinternalize)vec)externalizeinp=map(mapexternalize.uncurryunfreezeVector)$zipl2sV(unfreezeVectorl1a)wherel1=externalize$exprToData$Get31inpl2s=externalize$exprToData$Get32inpa=externalize$exprToData$Get33inpl2sV=unfreezeVectorl1l2s-- * OperationsinstanceRandomAccess(Vectora)wheretypeElement(Vectora)=a(!)=index-- | Introduces an 'ifThenElse' for each element; use with care!(++)::Computablea=>Vectora->Vectora->VectoraIndexedl1ixf1++Indexedl2ixf2=Indexed(l1+l2)ixfwhereixfi=ifThenElse(i<l1)ixf1(ixf2.subtractl1)iinfixr5++take::DataInt->Vectora->Vectorataken(Indexedlixf)=Indexed(minXnl)ixfdrop::DataInt->Vectora->Vectoradropn(Indexedlixf)=Indexed(maxX0(l-n))(\x->ixf(x+n))dropWhile::(a->DataBool)->Vectora->VectoradropWhilecontvec=dropivecwherei=while((<lengthvec)&&*(cont.(vec!)))(+1)0splitAt::DataInt->Vectora->(Vectora,Vectora)splitAtnvec=(takenvec,dropnvec)head::Vectora->ahead=(!0)last::Vectora->alastvec=vec!(lengthvec-1)tail::Vectora->Vectoratail=drop1init::Vectora->Vectorainitvec=take(lengthvec-1)vectails::Vectora->Vector(Vectora)tailsvec=Indexed(lengthvec+1)(\n->dropnvec)inits::Vectora->Vector(Vectora)initsvec=Indexed(lengthvec+1)(\n->takenvec)inits1::Vectora->Vector(Vectora)inits1=tail.initspermute::(DataLength->DataIx->DataIx)->(Vectora->Vectora)permuteperm(Indexedlixf)=Indexedl(ixf.perml)reverse::Vectora->Vectorareverse=permute$\li->l-1-ireplicate::DataInt->a->Vectorareplicatena=Indexedn(consta)enumFromTo::DataInt->DataInt->Vector(DataInt)enumFromTomn=Indexed(n-m+1)(+m)-- XXX Type should be generalized.(...)::DataInt->DataInt->Vector(DataInt)(...)=enumFromTozip::Vectora->Vectorb->Vector(a,b)zip(Indexedl1ixf1)(Indexedl2ixf2)=Indexed(minl1l2)(ixf1&&&ixf2)unzip::Vector(a,b)->(Vectora,Vectorb)unzip(Indexedlixf)=(Indexedl(fst.ixf),Indexedl(snd.ixf))map::(a->b)->Vectora->Vectorbmapf(Indexedlixf)=Indexedl(f.ixf)zipWith::(a->b->c)->Vectora->Vectorb->VectorczipWithfaVecbVec=map(uncurryf)$zipaVecbVec-- | Corresponds to 'foldl'.fold::Computablea=>(a->b->a)->a->Vectorb->afoldfx(Indexedlixf)=for0(l-1)x(\is->fs(ixfi))-- | Corresponds to 'foldl1'.fold1::Computablea=>(a->a->a)->Vectora->afold1fa=foldf(heada)a-- | Like 'unfoldCore', but for symbolic vectors. The output elements are stored-- in a core vector.unfoldVec::(Computablestate,Storablea)=>DataLength->state->(DataInt->state->(Dataa,state))->(Vector(Dataa),state)unfoldVeclinitstep=(unfreezeVectorlarr,final)where(arr,final)=unfoldCorelinitstep-- | Somewhat similar to Haskell's 'Data.List.unfoldr'. The output elements are-- stored in a core vector.---- @`unfold` l init step@:---- * @l@ is the length of the resulting vector.---- * @init@ is the initial state.---- * @step@ is a function computing a new element and the next state from the-- current state.unfold::(Computablestate,Storablea)=>DataLength->state->(state->(Dataa,state))->Vector(Dataa)unfoldlinit=fst.unfoldVeclinit.const-- | Corresponds to 'scanl'. The output elements are stored in a core vector.scan::(Storablea,Computableb)=>(Dataa->b->Dataa)->Dataa->Vectorb->Vector(Dataa)scanfavec=fst$unfoldVec(lengthvec+1)a$\ia->(a,fa(vec!i))-- | Corresponds to 'Data.List.mapAccumL'. The output elements are stored in a-- core vector.mapAccum::(Storablea,Computableacc,Storableb)=>(acc->Dataa->(acc,Datab))->acc->Vector(Dataa)->(acc,Vector(Datab))mapAccumfinitvecA=(final,vecB)where(vecB,final)=unfoldVec(lengthvecA)init$\iacc->let(acc',b)=facc(vecA!i)in(b,acc')sum::(Numa,Computablea)=>Vectora->asum=fold(+)0maximum::Storablea=>Vector(Dataa)->Dataamaximum=fold1maxminimum::Storablea=>Vector(Dataa)->Dataaminimum=fold1min-- | Scalar product of two vectorsscalarProd::Numerica=>Vector(Dataa)->Vector(Dataa)->DataascalarProdab=sum(zipWith(*)ab)