【问题标题】:Swift algorithm to enumerate a multilinear map, using multiples indexes:[Int]使用多重索引枚举多线性映射的 Swift 算法:[Int]
【发布时间】:2018-05-17 08:29:51
【问题描述】:

多线性映射 M 的元素存储在长度为 N 的一维数组中,形状 S 由 S:[Int] = [p,q,r,...] 定义,因此 q*p*r*... = N。 Shape 的大小是可变的,在编译时是未知的。

我要解决的问题是使用整数数组访问地图元素的通用方法,其中各个值是形状 S 中的坐标,例如:M[1,3,2], M[2,3,3,3] 等...这是一个不同的问题来自地图元素的简单枚举。

一种方法是使用M[i,j,k] 并实现下标方法。不幸的是,这种方法对地图的形状进行了硬编码,算法不再是通用的。

假设有一个实用函数从映射的 Shape 派生的元组返回元素索引,因此:

func index(_ indexes:[Int]) -> Int {....}

func elementAt(indexes:[Int]) -> Element { 
   return elements_of_the_map[self.index(indexes)]
}

M.elementAt(indexes:[i,j,k]) or M.elementAt(indexes:[i,j,k,l,m]) 始终有效。所以此时的问题是构建数组[i,j,k,...]

问题:有没有一种算法可以有效地枚举这些索引?嵌套循环不起作用,因为在编译时不知道循环的数量,并且递归函数似乎增加了很多复杂性(特别是跟踪以前的索引)。

我正在考虑一种算法'a la' base-x 计数,即在右上角的索引中添加一个单位,如果计数超过地图形状的元素数量,则向左移动一个单位。

【问题讨论】:

  • 给定一个形状(例如 [3, 2, 2]),您要枚举所有可能的索引 [0, 0, 0], [0, 0, 1], [0, 1, 0 ], ... [2, 1, 1] ?
  • 是的。但请注意,在编译时形状是未知的。
  • 注意:我很快测试了一个计算 'a la' base-x 的算法,虽然很笨重,但似乎可以工作。
  • 对于每个元素索引(在0..<N范围内)你可以计算相应的索引数组,是你做的吗?
  • IMO 不可能从0..<N 范围内的索引计算索引数组,因为对于一个给定的整数,可能有多种分解。我所做的是“如何以从右到左的方式将一个'单位'添加到 [1,1,2],限制为 [2,2,3]?也就是说,如果最右边的索引超过 2,则将其变为 0,然后移动到下一个。

标签: arrays swift algorithm


【解决方案1】:

同样的想法,但代码更少:

func addOneUnit(shape: [Int], indexes: [Int]) -> [Int]? {
    var next = indexes
    for i in shape.indices.reversed() {
        next[i] += 1
        if next[i] < shape[i] {
            return next 
        }
        next[i] = 0
    }
    return nil
}

【讨论】:

  • 嘿,谢谢,代码太简洁了!比我可怕的东西好多了。真的很有帮助,现在我可以按照我想要的方式查看张量。干杯!
【解决方案2】:

这是代码,它很原始,但应该可以工作。这个想法是从右到左递增,从 [1,2,1] 移动到 [1,2,2],形状约束为 [2,3,3]。

func add_one_unit(shape:[Int],indexes:[Int]) -> [Int]? {
    //Addition is right to left, so we have to reverse the arrays. Shape Arrays are usually very small, so it's fast.
    let uu = Array(indexes.reversed()); //Array to add one index to.
    let shape_reversed = Array(shape.dimensions.reversed()); //Shape array.

    var vv:[Int] = [];
    var move_next:Bool = true;

    for i in 0..<uu.count {
        if move_next {
            if uu[i] < shape_reversed[i] - 1 { //Shape constraint is OK.
                vv.append(uu[i] + 1)
                move_next = false;
            } else {
                vv.append(0) //Shape constraint is reached.
                move_next = true;//we'll flip the next index.
            }
        } else {
            vv.append(uu[i]) //Nothing to change.
        }
    }
    return ( vv.reduce(true, { $0&&($1 == 0) }) ) ? nil : Array(vv.reversed()); //Returns nil once we reached the Zero Vector.
}

这给了

add_one_unit(shape:[2,3,3],indexes:[0,0,0]) -> [0,0,1]
add_one_unit(shape:[2,3,3],indexes:[1,2,2]) -> [0,0,0]/nil

完成此操作后,此函数可用于枚举任何形状的多线性映射([i,j,k,...] 到唯一索引的映射,例如矩阵到索引映射是必要的,并且取决于在您的实现中),或从任何特定向量开始切片地图。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多