ideas-math-1.2: src/Domain/LinearAlgebra/GramSchmidtRules.hs
-----------------------------------------------------------------------------
-- Copyright 2015, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer : bastiaan.heeren@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-----------------------------------------------------------------------------
-- $Id: GramSchmidtRules.hs 7527 2015-04-08 07:58:06Z bastiaan $
module Domain.LinearAlgebra.GramSchmidtRules
( ruleNext, ruleNextOrthogonal
, ruleOrthogonal, ruleNormalize
, rulesGramSchmidt
) where
import Control.Monad
import Domain.LinearAlgebra.Vector
import Ideas.Common.Library
import Ideas.Common.Utils
varI, varJ :: Ref Int
varI = makeRef "considered"
varJ = makeRef "j"
getVarI, getVarJ :: EnvMonad Int
getVarI = varI :? 0
getVarJ = varJ :? 0
rulesGramSchmidt :: (Eq a, Floating a, Reference a) => [Rule (Context (VectorSpace a))]
rulesGramSchmidt = [ruleNormalize, ruleOrthogonal, ruleNext]
-- Make the current vector of length 1
-- (only applicable if this is not already the case)
ruleNormalize :: (Eq a, Floating a) => Rule (Context (VectorSpace a))
ruleNormalize = ruleTrans "Turn into unit Vector" $ makeTransLiftContext $ \vs -> do
v <- current vs
guard (norm v `notElem` [0, 1])
setCurrent (toUnit v) vs
-- Make the current vector orthogonal with some other vector
-- that has already been considered
ruleOrthogonal :: (Eq a, Floating a, Reference a) => Rule (Context (VectorSpace a))
ruleOrthogonal = ruleTrans "Make orthogonal" $
supplyContextParameters transOrthogonal $ \_ -> do
i <- getVarI
j <- getVarJ
guard (i>j)
return (pred j, pred i)
-- Variable "j" is for administrating which vectors are already orthogonal
ruleNextOrthogonal :: Rule (Context (VectorSpace a))
ruleNextOrthogonal = minor $ ruleTrans "Orthogonal to next" $
makeTransLiftContext_ $ const $ do
i <- getVarI
j <- liftM succ getVarJ
guard (j < i)
varJ := j
-- Consider the next vector
-- This rule should fail if there are no vectors left
ruleNext :: Rule (Context (VectorSpace a))
ruleNext = minor $ ruleTrans "Consider next vector" $
makeTransLiftContext_ $ \vs -> do
i <- getVarI
guard (i < length (vectors vs))
varI := i+1
varJ := 0
-- Two indices, change the second vector and make it orthogonal
-- to the first
transOrthogonal :: (Eq a, Reference a, Floating a) => ParamTrans (Int, Int) (VectorSpace a)
transOrthogonal = parameter2 "vector 1" "vector 2" $ \i j ->
transMaybe $ \a -> do
guard (i /= j && i >=0 && j >= 0)
let vs = vectors a
u <- elementAt i vs
guard (isUnit u)
liftM makeVectorSpace $ changeAt j (makeOrthogonal u) vs
current :: VectorSpace a -> EnvMonad (Vector a)
current vs = do
i <- getVarI
elementAt (i-1) (vectors vs)
setCurrent :: Vector a -> VectorSpace a -> EnvMonad (VectorSpace a)
setCurrent v vs = do
i <- getVarI
liftM makeVectorSpace $ replaceAt (i-1) v $ vectors vs