Haskell中的多项式因式分解

时间:2011-10-07 13:15:44

标签: haskell template-haskell abstract-algebra

使用hammar's help我创建了一个模块Haskell位编译

$(zModP 5)

newtype Z5 = Z5 Int
instance Additive.C Z5 where
  (Z5 x) + (Z5 y) = Z5 $ (x + y) `mod` 5
...

我现在面临一个问题,我不认为我可以这样解决。

关于多项式的一个值得注意的事实是,如果它们是一些素数p的不可约的模数,它们在理性中是不可约的。我已经有了一种暴力试图在给定(有限)场上对多项式进行分解的方法。

我想尝试为多个字段运行此函数。这就是我想要的东西:

isIrreducible :: (FiniteField.C a) => Poly.T a -> Bool
isIrreducible p = ...

intPolyIrreducible :: Poly.T Int -> Bool
intPolyIrreducible p = isIrreducible (p :: Poly.T Z2) ||
                       isIrreducible (p :: Poly.T Z3) ||
                       isIrreducible (p :: Poly.T Z5) ||
                       ...

基本上我想尝试运行我的因子算法来获得大量的“除法”定义。

我认为这可能与TH有关,但似乎需要永远。我想知道将{arithmetical操作作为参数传递给isIrreducible是否更容易?

或者看起来这可能是Newtype模块可以提供帮助的东西,但我想不出如果没有以一种同样困难的方式使用TH它会如何工作......

任何人都对如何最好地实现这一点有任何想法?

2 个答案:

答案 0 :(得分:3)

您可以使用类型级数字在有限域中进行计算,例如使用type-level包:

{-# LANGUAGE ScopedTypeVariables #-}
module Mod where
import Data.TypeLevel.Num (Nat,toNum, reifyIntegral)

data Z p = Z Integer

instance Eq (Z p) where Z x == Z y = x == y
instance Ord (Z p) where -- dummy instance
instance Show (Z p) where show (Z n) = show n

instance Nat p => Num (Z p) where
    Z x + Z y = Z $ (x + y) `mod` toNum (undefined :: p)
    Z x - Z y = Z $ (x - y) `mod` toNum (undefined :: p)
    Z x * Z y = Z $ (x * y) `mod` toNum (undefined :: p)
    fromInteger n = Z (n `mod` toNum (undefined :: p))
    -- etc

-- Compute x^2-6 (mod p)
poly :: Nat p => Z p -> Z p
poly x = x*x-6

-- Computes whether x^2-6==0 (mod p), for x=3
checkPoly :: Integer -> Bool
checkPoly n = reifyIntegral n test
  where
    test :: forall p . Nat p => p -> Bool
    test _ = poly (3::Z p) == 0

test1 = map checkPoly [2,3,5]
-- Result: [False,True,False]

这种方法的优点是不需要为每种数字类型使用新的模板haskell实例。缺点是它可能比模板haskell解决方案慢,因为每个操作都通过类字典传递有限字段的大小。

答案 1 :(得分:2)

这有点像Poly.T的样子,但你能编写一个类型的函数(例如)

fmap :: (a -> b) -> (Poly.T a -> Poly.T b)

?如果是这样,那么当Z类型的模数不匹配时,其操作在运行时失败可能是有意义的:

data Z = Z Int Int
instance Applicative.C Z where
    (Z m v) + (Z m' v')
        | m == m' = Z m ((v + v') `mod` m)
        | otherwise = error "mismatched modulus"

然后你可以用普通的旧Haskell写这样的东西:

intPolyIrreducible :: Poly.T Int -> Bool
intPolyIrreducible p = any isIrreducible [fmap (Z m) p | m <- [2,3,5,7,11,13]]

当然,这种类型安全性稍差。但从参数化的角度来看,fmap (Z m)不会引入任何不匹配的模数。