OCaml 新手:我将如何实施高斯消元法?

发布于 2024-12-09 05:43:08 字数 154 浏览 0 评论 0原文

我是 OCaml 的新手,我想实现高斯消元法作为练习。我可以使用有状态算法轻松完成此操作,这意味着将矩阵保留在内存中并通过传递对它的引用来递归操作它。

然而,这种有状态性有点像命令式编程。我知道 OCaml 中有能力做到这一点,但我想问是否有一些我没有首先想到的聪明的功能方法。

I'm new to OCaml, and I'd like to implement Gaussian Elimination as an exercise. I can easily do it with a stateful algorithm, meaning keep a matrix in memory and recursively operating on it by passing around a reference to it.

This statefulness, however, smacks of imperative programming. I know there are capabilities in OCaml to do this, but I'd like to ask if there is some clever functional way I haven't thought of first.

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

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

发布评论

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

评论(3

九局 2024-12-16 05:43:08

OCaml 数组是可变的,很难避免像命令式语言中的数组一样对待它们。

Haskell 有不可变数组,但根据我对 Haskell 的(有限)经验,在大多数情况下你最终会切换到一元的、可变的数组。对于某些特定目的来说,不可变数组可能是令人惊奇的。我一直想象你可以在 Haskell 中编写一个漂亮的动态编程实现,其中数组条目之间的依赖关系完全由其中的表达式定义。关键是您实际上只需要指定每个数组条目的内容一次。我不认为高斯消除遵循这种模式,因此它似乎不太适合不可变数组。不过,看看它的效果如何会很有趣。

OCaml arrays are mutable, and it's hard to avoid treating them just like arrays in an imperative language.

Haskell has immutable arrays, but from my (limited) experience with Haskell, you end up switching to monadic, mutable arrays in most cases. Immutable arrays are probably amazing for certain specific purposes. I've always imagined you could write a beautiful implementation of dynamic programming in Haskell, where the dependencies among array entries are defined entirely by the expressions in them. The key is that you really only need to specify the contents of each array entry one time. I don't think Gaussian elimination follows this pattern, and so it seems it might not be a good fit for immutable arrays. It would be interesting to see how it works out, however.

双手揣兜 2024-12-16 05:43:08

您可以使用Map来模拟矩阵。键是一对引用行和列的整数。您需要使用自己的 get x y 函数来确保 x x y 。 ny n 但不是直接访问 Map。 (编辑)您可以直接使用Pervasives中的比较功能。

module OrderedPairs = struct
    type t = int * int
    let compare = Pervasives.compare
end                     
module Pairs = Map.Make (OrderedPairs)

let get_ n set x y =
    assert( x < n && y < n ); 
    Pairs.find (x,y) set

let set_ n set x y v = 
    assert( x < n && y < n ); 
    Pairs.add (x,y) set v

实际上,拥有一组通用函数(至少 get x yset x y),而不指定实现,将是一个更好的选择。然后,这些函数可以传递给函数,或者通过函子在模块中实现(这是一个更好的解决方案,但拥有一组函数来完成您需要的操作将是第一步,因为您是 OCaml 新手)。这样你就可以使用MapArrayHashtbl或者一组函数来访问硬盘上的文件来实现矩阵,如果你想要的话。这是函数式编程真正重要的方面;您相信接口而不是利用副作用,而不用担心底层实现——因为它被认为是纯粹的。

You can use a Map to emulate a matrix. The key would be a pair of integers referencing the row and column. You'll want to use your own get x y function to ensure x < n and y < n though, instead of accessing the Map directly. (edit) You can use the compare function in Pervasives directly.

module OrderedPairs = struct
    type t = int * int
    let compare = Pervasives.compare
end                     
module Pairs = Map.Make (OrderedPairs)

let get_ n set x y =
    assert( x < n && y < n ); 
    Pairs.find (x,y) set

let set_ n set x y v = 
    assert( x < n && y < n ); 
    Pairs.add (x,y) set v

Actually, having a general set of functions (get x y and set x y at a minimum), without specifying the implementation, would be an even better option. The functions then can be passed to the function, or be implemented in a module through a functor (a better solution, but having a set of functions just doing what you need would be a first step since you're new to OCaml). In this way you can use a Map, Array, Hashtbl, or a set of functions to access a file on the hard-drive to implement the matrix if you wanted. This is the really important aspect of functional programming; that you trust the interface over exploiting the side-effects, and not worry about the underlying implementation --since it's presumed to be pure.

虚拟世界 2024-12-16 05:43:08

到目前为止的答案是使用/模拟可变数据类型,但是函数式方法是什么样的?

为了看清楚,让我们将问题分解为一些功能组件:

高斯消除涉及一系列行运算,因此首先定义一个采用 2 行和缩放因子的函数,并返回行运算的结果是有用的。

我们想要的行操作应该从特定行中消除变量(列),因此让我们定义一个函数,该函数接受一对行和一个列索引,并使用先前定义的行操作返回修改后的行,其中该列条目为零。

然后我们定义两个函数,一个将矩阵转换为三角形式,另一个通过依次消除每一列将三角矩阵反向替换为对角形式(使用之前定义的函数)。我们可以迭代或递归列,并且矩阵可以定义为列表、向量或列表、向量或数组的数组。输入没有改变,但是返回了一个修改后的矩阵,所以我们最终可以这样做:

let out_matrix = to_diagonal(to_triangle in_matrix);

它的功能不在于数据类型(数组或列表)是否可变,而在于它们的使用方式。这种方法可能不是特别“聪明”,也不是在 OCaml 中进行高斯消除的最有效方法,但使用纯函数可以让您清晰地表达算法。

The answers so far are using/emulating mutable data-types, but what does a functional approach look like?

To see, let's decompose the problem into some functional components:

Gaussian elimination involves a sequence of row operations, so it is useful first to define a function taking 2 rows and scaling factors, and returning the resultant row operation result.

The row operations we want should eliminate a variable (column) from a particular row, so lets define a function which takes a pair of rows and a column index and uses the previously defined row operation to return the modified row with that column entry zero.

Then we define two functions, one to convert a matrix into triangular form, and another to back-substitute a triangular matrix to the diagonal form (using the previously defined functions) by eliminating each column in turn. We could iterate or recurse over the columns, and the matrix could be defined as a list, vector or array of lists, vectors or arrays. The input is not changed, but a modified matrix is returned, so we can finally do:

let out_matrix = to_diagonal (to_triangular in_matrix);

What makes it functional is not whether the data-types (array or list) are mutable, but how they they are used. This approach may not be particularly 'clever' or be the most efficient way to do Gaussian eliminations in OCaml, but using pure functions lets you express the algorithm cleanly.

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