帮助计算(四叉树)矩阵的列和的算法?

发布于 2024-10-16 12:05:22 字数 1532 浏览 5 评论 0原文

给定这个定义和一个测试矩阵:

data (Eq a, Show a) => QT a = C a | Q (QT a) (QT a) (QT a) (QT a)
    deriving (Eq, Show)

data (Eq a, Num a, Show a) => Mat a = Mat {nexp :: Int, mat :: QT a}
    deriving (Eq, Show)

-- test matrix, exponent is 2, that is matrix is 4 x 4
test = Mat 2 (Q (C 5) (C 6) (Q (C 1) (C 0) (C 2) (C 1)) (C 3))

|     |     |
|  5  |  6  |
|     |     |
-------------
|1 | 0|     |
|--|--|  3  |
|2 | 1|     |

我正在尝试编写一个函数来输出列总和列表,例如:[13, 11, 18, 18] 。基本思想是对每个子四叉树求和:

  • 如果四叉树是 (C c),则输出重复 2 ^ (n - 1) 乘以值 >c * 2 ^ (n - 1)示例:第一个四叉树是 (C 5) 所以我们重复 5 * 2^(2 - 1) = 10, 2 ^ (n - 1) = 2次,得到[5, 5]。
  • 否则,给定 (Q abcd),我们 zipWith a 和 c(以及 b 和 d)的余和。

当然,这是不起作用(甚至无法编译),因为经过一些递归之后,我们得到了:

zipWith (+) [[10, 10], [12, 12]] [zipWith (+) [[1], [0]] [[2], [1]], [6, 6]]

因为我从Haskell开始,我觉得我错过了一些东西,需要一些关于我可以使用的函数的建议。 不起作用 colsum 的定义是:

colsum :: (Eq a, Show a, Num a) => Mat a -> [a]
colsum m = csum (mat m)
    where
        n = nexp m
        csum (C c)       = take (2 ^ n) $ repeat (c * 2 ^ n)
        csum (Q a b c d) = zipWith (+) [colsum $ submat a, colsum $ submat b]
                                       [colsum $ submat c, colsum $ submat d]
        submat q = Mat (n - 1) q

任何想法都会很棒并且非常感激......

Given this definition and a test matrix:

data (Eq a, Show a) => QT a = C a | Q (QT a) (QT a) (QT a) (QT a)
    deriving (Eq, Show)

data (Eq a, Num a, Show a) => Mat a = Mat {nexp :: Int, mat :: QT a}
    deriving (Eq, Show)

-- test matrix, exponent is 2, that is matrix is 4 x 4
test = Mat 2 (Q (C 5) (C 6) (Q (C 1) (C 0) (C 2) (C 1)) (C 3))

|     |     |
|  5  |  6  |
|     |     |
-------------
|1 | 0|     |
|--|--|  3  |
|2 | 1|     |

I'm trying to write a function that will output a list of columns sum, like: [13, 11, 18, 18]. The base idea is to sum each sub-quadtree:

  • If quadtree is (C c), then output the a repeating 2 ^ (n - 1) times the value c * 2 ^ (n - 1). Example: first quadtree is (C 5) so we repeat 5 * 2^(2 - 1) = 10, 2 ^ (n - 1) = 2 times, obtaining [5, 5].
  • Otherwise, given (Q a b c d), we zipWith the colsum of a and c (and b and d).

Of course this is not working (not even compiling) because after some recursion we have:

zipWith (+) [[10, 10], [12, 12]] [zipWith (+) [[1], [0]] [[2], [1]], [6, 6]]

Because I'm beginning with Haskell I feel I'm missing something, need some advice on function I can use. Not working colsum definition is:

colsum :: (Eq a, Show a, Num a) => Mat a -> [a]
colsum m = csum (mat m)
    where
        n = nexp m
        csum (C c)       = take (2 ^ n) $ repeat (c * 2 ^ n)
        csum (Q a b c d) = zipWith (+) [colsum $ submat a, colsum $ submat b]
                                       [colsum $ submat c, colsum $ submat d]
        submat q = Mat (n - 1) q

Any ideas would be great and much appreciated...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦里的微风 2024-10-23 12:05:22

也许“某人”应该向担心四叉树深度的人解释,矩阵类型中的 nexp 字段正是用于确定 (C _) 的实际大小。

关于第一个答案中提出的解决方案,好的,它有效。然而构造和解构 Mat 是毫无用处的,这是很容易避免的。此外,调用 fromIntegral 来“绕过”由于使用复制而产生的类型检查问题可以得到解决,而无需强制先进入 Integral 然后再返回,就像

let m = 2^n;复制 k (m*x) 中的 k=2^n

无论如何,这里的挑战是避免由于 ++ 导致的二次行为,这就是我所期望的。

干杯,

Probably "someone" should have explained to who is worried about the depth of the QuadTree that the nexp field in the Matrix type is exactly meant to be used to determine the real size of a (C _).

About the solution presented in the first answer, ok it works. However it is quite useless to construct and deconstruct Mat, this could be easily avoided. Moreover the call to fromIntegral to "bypass" the type checking problem coming from the use of replicate can be solved without forcing to first going to Integral and then coming back, like

let m = 2^n; k=2^n in replicate k (m*x)

Anyway, the challenge here is to avoid the quadratical behavior due to the ++, that is what I would expect.

Cheers,

岁月流歌 2024-10-23 12:05:22

让我们考虑一下您的 colsum

colsum :: (Eq a, Show a, Num a) => Mat a -> [a]
colsum m = csum (mat m)
    where
        n = nexp m
        csum (C c)       = take (2 ^ n) $ repeat (c * 2 ^ n)
        csum (Q a b c d) = zipWith (+) [colsum $ submat a, colsum $ submat b]
                                       [colsum $ submat c, colsum $ submat d]
        submat q = Mat (n - 1) q

它几乎是正确的,除了您定义 csum (Q abcd) = ... 的行。

让我们考虑一下类型。 colsum 返回数字列表。 ZipWith (+) 按元素对两个列表求和:

ghci> :t zipWith (+)
zipWith (+) :: Num a => [a] -> [a] -> [a]

这意味着您需要将两个数字列表传递给 zipWith (+)。相反,您可以创建两个数字列表列表,如下所示:

[colsum $ submat a, colsum $ submat b]

此表达式的类型是 [[a]],而不是您需要的 [a]

您需要做的是连接两个数字列表以获得单个数字列表(这可能就是您想要做的):

((colsum $ submat a) ++ (colsum $ submat b))

类似地,您连接 c 的部分和列表和 d 那么你的函数应该开始工作。

Let's consider your colsum:

colsum :: (Eq a, Show a, Num a) => Mat a -> [a]
colsum m = csum (mat m)
    where
        n = nexp m
        csum (C c)       = take (2 ^ n) $ repeat (c * 2 ^ n)
        csum (Q a b c d) = zipWith (+) [colsum $ submat a, colsum $ submat b]
                                       [colsum $ submat c, colsum $ submat d]
        submat q = Mat (n - 1) q

It is almost correct, except the line where you define csum (Q a b c d) = ....

Let think about types. colsum returns a list of numbers. ZipWith (+) sums two lists elementwise:

ghci> :t zipWith (+)
zipWith (+) :: Num a => [a] -> [a] -> [a]

This means that you need to pass two lists of numbers to zipWith (+). Instead you create two lists of lists of numbers, like this:

[colsum $ submat a, colsum $ submat b]

The type of this expression is [[a]], not [a] as you need.

What you need to do is to concatenate two lists of numbers to obtain a single list of numbers (and this is, probably, what you intended to do):

((colsum $ submat a) ++ (colsum $ submat b))

Similarly, you concatenate lists of partial sums for c and d then your function should start working.

你在看孤独的风景 2024-10-23 12:05:22

让我们更笼统地讨论一下,然后回到手头的目标。

考虑如何将四叉树投影到 2n×2n 矩阵中。我们可能不需要创建此投影来计算其列总和,但这是一个有用的概念。

  • 如果我们的四叉树是单个单元格,那么我们只需用该单元格的值填充整个矩阵即可。
  • 否则,如果 n ≥ 1,我们可以将矩阵分成象限,并让每个子四叉树填充一个象限(即让每个子四叉树填充一个 2n-1×2n -1矩阵)。
  • 请注意,还有一个案例尚未完成。如果 n = 0(即我们有一个 1×1 矩阵)并且四叉树不是单个单元怎么办?我们需要为这种情况指定一些行为 - 也许我们只是让子四叉树之一填充整个矩阵,或者我们用一些默认值填充矩阵。

现在考虑这种投影的列总和。

  • 如果我们的四叉树是单个单元格,则 2n 列的总和将为 2n
    乘以该单元格中存储的值。

    (提示:查看 hoogle 上的 replicategenericReplicate)。

  • 否则,如果 n ≥ 1,则每列与两个不同的象限重叠。
    我们一半的柱子将完全由西象限决定,
    另一半是东象限,特定列的总和
    可以定义为该列贡献的总和
    从其北半部分(即北象限中该列的列总和),
    及其南半部(同样)。

    (提示:我们需要将西列总和附加到东列总和
    获取所有列的总和,并合并北部和南部的半列总和
    以获得每列的实际总和)。

  • 同样,我们有第三种情况,这里的列总和取决于如何
    将四个子四叉树投影到 1×1 矩阵上。幸运的是,1×1 矩阵意味着
    只有一个列总和!

现在,我们只关心一个特定的投影 - 到大小为 2dd×2d 的矩阵上的投影
其中 d 是四叉树的深度。所以你还需要计算深度。自从一个
单个细胞“自然地”适合大小为 1×1 的矩阵,这意味着它具有
深度为 0。四分支必须具有足够大的深度以允许其每个子四分支相适应
进入矩阵的象限。

Let's go more general, and come back to the goal at hand.

Consider how we would project a quadtree into a 2n×2n matrix. We may not need to create this projection in order to calculate its column sums, but it's a useful notion to work with.

  • If our quadtree is a single cell, then we'd just fill the entire matrix with that cell's value.
  • Otherwise, if n ≥ 1, we can divide the matrix up into quadrants, and let the subquadtrees each fill one quadrant (that is, have each subquadtree fill a 2n-1×2n-1 matrix).
  • Note that there's still a case remaining. What if n = 0 (that is, we have a 1×1 matrix) and the quadtree isn't a single cell? We need to specify some behaviour for this case - maybe we just let one of the subquadtrees populate the entire matrix, or we fill the matrix with some default value.

Now consider the column sums of such a projection.

  • If our quadtree was a single cell, then the 2n column sums will all be 2n
    times the value stored in that cell.

    (hint: look at replicate and genericReplicate on hoogle).

  • Otherwise, if n ≥ 1, then each column overlaps two distinct quadrants.
    Half of our columns will be completely determined by the western quadrants,
    and the other half by the eastern quadrants, The sum for a particular column
    can be defined as the sum of the contribution to that column
    from its northern half (that is, the column sum for that column in the northern quadrant),
    and its southern half (likewise).

    (hint: We'll need to append the western column sums to the eastern column sums
    to get all the column sums, and combien the northern and southern demi-column sums
    to get the actual sums for each column).

  • Again, we have a third case, and the column sum here depends on how
    you project four subquadtrees onto a 1×1 matrix. Fortunately, a 1×1 matrix means
    only a single column sum!

Now, we only care about a particular projection - the projection onto a matrix of size 2dd×2d
where d is the depth of our quadtree. So you'll need to figure the depth too. Since a
single cell fits "naturally" into a matrix of size 1×1, that implies that it has a
depth of 0. A quadbranch must have depth great enough to allow each of its subquads to fit
into their quadrant of the matrix.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文