Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell中的嵌套三角环?_Haskell - Fatal编程技术网

Haskell中的嵌套三角环?

Haskell中的嵌套三角环?,haskell,Haskell,我在Java中有以下内容,基本上是一个嵌套的三角形循环: int n = 10; B bs[] = new B[n]; // some initial values, bla bla double dt = 0.001; for (int i = 0; i < n; i++) { bs[i] = new B(); bs[i].x = i * 0.5; bs[i].v = i * 2.5;

我在Java中有以下内容,基本上是一个嵌套的三角形循环:

    int n = 10;
    B bs[] = new B[n];
    // some initial values, bla bla
    double dt = 0.001;
    for (int i = 0; i < n; i++) {
        bs[i] = new B();
        bs[i].x = i * 0.5;
        bs[i].v = i * 2.5;
        bs[i].m = i * 5.5;
    }
    for (int i = 0; i < n; i++) {
        for (int j = **(i+1)**; j < n; j++) {
            double d = bs[i].x - bs[j].x;

            double sqr = d * d + 0.01;
            double dist = Math.sqrt(sqr);
            double mag = dt / (sqr * dist);

            bs[i].v -= d * bs[j].m * mag;
            **bs[j].v += d * bs[i].m * mag;**
        }
    }   

    // printing out the value v
    for (int i = 0; i < n; i++) {
        System.out.println(bs[i].v);
    }
在每次迭代中,数组索引i和j处的值会同时更新,从而避免执行完整的嵌套循环。下面给出了相同的结果,但它是一个完整的嵌套循环(请原谅我使用的术语,它们可能不正确,但我希望它有意义)

我将有非常大的价值,例如1000、5000等。
当n=1000时,一个完整的嵌套循环给出
长度[(i,j)| i这是一个使用包中未绑定可变向量的简单转换。代码有点难看,但应该非常快:

module Main
    where

import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M

numElts :: Int
numElts = 10

dt :: Double
dt = 0.001

loop :: Int -> M.IOVector Double -> M.IOVector Double 
        -> M.IOVector Double -> IO ()
loop n x v m = go 0
  where
    doWork i j = do xI <- M.read x i
                    xJ <- M.read x j
                    vI <- M.read v i
                    vJ <- M.read v j
                    mI <- M.read m i
                    mJ <- M.read m j

                    let d = xI - xJ
                    let sqr = d * d + 0.01
                    let dist = sqrt sqr
                    let mag = dt / (sqr * dist)

                    M.write v i (vI - d * mJ * mag)
                    M.write v j (vJ + d * mI * mag)

    go i | i < n     = do go' (i+1)
                          go  (i+1)
         | otherwise = return ()
      where
        go' j | j < n     = do doWork i j
                               go' (j + 1)
              | otherwise = return ()

main :: IO ()
main = do x <- generateVector 0.5
          v <- generateVector 2.5
          m <- generateVector 5.5
          loop numElts x v m
          v' <- U.unsafeFreeze v
          U.forM_ v' print

    where
      generateVector :: Double -> IO (M.IOVector Double)
      generateVector d = do v <- M.new numElts
                            generateVector' numElts d v
                            return v

      generateVector' :: Int -> Double -> M.IOVector Double -> IO ()
      generateVector' n d v = go 0
        where
          go i | i < n = do M.unsafeWrite v i (fromIntegral i * d)
                            go (i+1)
               | otherwise = return ()

因此,强制解决方案的速度大约是功能解决方案的50倍(当所有内容都放在缓存中时,对于较小的
n
,差异更为显著).我试图使Federico的解决方案适用于未绑定向量,但显然它在一个关键方面依赖于惰性,这使得未绑定版本永远循环。“纯向量”版本使用装箱向量。

我不确定这是否解决了您的问题,因为我还没有完全掌握它,但三角环本身在Haskell中非常容易实现:

triangularLoop :: (a -> a -> b) -> [a] -> [b]
triangularLoop f xs = do
    (x1 : t) <- tails xs
    x2 <- t
    return $ f x1 x2

在Haskell中编写嵌套循环的典型惯用方法是使用列表理解

以下是我将如何翻译您的代码:

import Data.Array

import Data.List (tails)

data Body = Body {x::Double,v::Double,m::Double}
            deriving Show

n::Int
n = 9

dt::Double
dt = 0.001

bs_0 :: Array Int Body
bs_0 = array (0,n) [(i,Body {x = i'*0.5,v = i'*2.5,m = i'*5.5}) | 
                    i <- [0..n], let i' = fromIntegral i]

bs :: Array Int Body
bs = accum (\b dv -> b {v = v b + dv}) bs_0 dvs
     where 
       dvs :: [(Int,Double)]
       dvs = concat [[(i,dv_i),(j,dv_j)] | (i:is) <- tails [0..n], 
                                            j <- is,
                                            let d = x(bs!i) - x(bs!j)
                                                sqr =  d * d + 0.01
                                                dist = sqrt sqr
                                                mag = dt / (sqr * dist)
                                                dv_i = -d * m(bs!j) * mag
                                                dv_j =  d * m(bs!i) * mag]

main :: IO()
main = mapM_ print (assocs bs)
导入数据。数组
导入数据列表(尾部)
数据体=体{x::Double,v::Double,m::Double}
衍生节目
n::Int
n=9
dt::双
dt=0.001
bs_0::数组整型体
bs_0=数组(0,n)[(i,Body{x=i'*0.5,v=i'*2.5,m=i'*5.5}]

我想如果你能解释一下
update\u i
update\u j
的作用,以及
result
是什么,那会有所帮助,否则就不清楚如何最好地编写你想要的东西了。@Haskell大象:我删除了这两个方法,并将其中的代码放进去了。我通过删除不必要的代码,简化了很多。你可以替换
dt
按任何值,都无所谓。Thanks@HaskellElephant:您确定您的两个循环实际执行相同的操作吗?毕竟,该循环可能会读取已更新的值
arr
。您提供的两个循环并不等效,因此很难分析您尝试执行的操作。请查看。我知道你的代码是用Java编写的,但在代码板上Java不是一个选项。@HaskellElephant,Anupam:你是对的,代码没有给出相同的结果。我的错。我只是试图简化我的代码,但现在代码更完整了,如果你检查,两个循环都给出相同的结果,除了第一个是“三角形”循环,而第二个是ful循环l嵌套循环。谢谢Mikhail。可变未绑定向量模块对我来说是新的。我实际上如何在主函数中打印/返回结果?我指的是更新的向量。我将使用我现有的代码来处理它,看看它是如何运行的。但我想看看如何使用不可变数组或haskell中的列表来实现它。这将有限地需要累积更改,然后最终将其应用于初始数组/列表。我不确定在这种情况下,纯功能解决方案是否能像命令式解决方案那样快。破坏性更新和恒定时间索引是您的算法的核心。@Mikhail:取消安全真的有意义吗?没有合理的w除了构造一个不可变的向量并不安全地解冻它之外,构造一个可变向量的方法是什么?@Peaker删除了对
unsafeThaw
的调用。仅供参考,I。强制解决方案要快得多;然而,我无法让您的代码处理未固定的向量。
module Main
    where

import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M

numElts :: Int
numElts = 10

dt :: Double
dt = 0.001

loop :: Int -> M.IOVector Double -> M.IOVector Double 
        -> M.IOVector Double -> IO ()
loop n x v m = go 0
  where
    doWork i j = do xI <- M.read x i
                    xJ <- M.read x j
                    vI <- M.read v i
                    vJ <- M.read v j
                    mI <- M.read m i
                    mJ <- M.read m j

                    let d = xI - xJ
                    let sqr = d * d + 0.01
                    let dist = sqrt sqr
                    let mag = dt / (sqr * dist)

                    M.write v i (vI - d * mJ * mag)
                    M.write v j (vJ + d * mI * mag)

    go i | i < n     = do go' (i+1)
                          go  (i+1)
         | otherwise = return ()
      where
        go' j | j < n     = do doWork i j
                               go' (j + 1)
              | otherwise = return ()

main :: IO ()
main = do x <- generateVector 0.5
          v <- generateVector 2.5
          m <- generateVector 5.5
          loop numElts x v m
          v' <- U.unsafeFreeze v
          U.forM_ v' print

    where
      generateVector :: Double -> IO (M.IOVector Double)
      generateVector d = do v <- M.new numElts
                            generateVector' numElts d v
                            return v

      generateVector' :: Int -> Double -> M.IOVector Double -> IO ()
      generateVector' n d v = go 0
        where
          go i | i < n = do M.unsafeWrite v i (fromIntegral i * d)
                            go (i+1)
               | otherwise = return ()
triangularLoop :: (a -> a -> b) -> [a] -> [b]
triangularLoop f xs = do
    (x1 : t) <- tails xs
    x2 <- t
    return $ f x1 x2
triangularLoop f = concat . map singlePass . tails
    where
        singlePass [] = []
        singlePass (h:t) = map (f h) t
import Data.Array

import Data.List (tails)

data Body = Body {x::Double,v::Double,m::Double}
            deriving Show

n::Int
n = 9

dt::Double
dt = 0.001

bs_0 :: Array Int Body
bs_0 = array (0,n) [(i,Body {x = i'*0.5,v = i'*2.5,m = i'*5.5}) | 
                    i <- [0..n], let i' = fromIntegral i]

bs :: Array Int Body
bs = accum (\b dv -> b {v = v b + dv}) bs_0 dvs
     where 
       dvs :: [(Int,Double)]
       dvs = concat [[(i,dv_i),(j,dv_j)] | (i:is) <- tails [0..n], 
                                            j <- is,
                                            let d = x(bs!i) - x(bs!j)
                                                sqr =  d * d + 0.01
                                                dist = sqrt sqr
                                                mag = dt / (sqr * dist)
                                                dv_i = -d * m(bs!j) * mag
                                                dv_j =  d * m(bs!i) * mag]

main :: IO()
main = mapM_ print (assocs bs)