【问题标题】:How can I modify a traditional cartesian product to reduce my memory overhead?如何修改传统的笛卡尔积以减少内存开销?
【发布时间】:2015-07-26 03:24:34
【问题描述】:

对于我的问题,您最多可以从 5-10,000 个项目中选择 24 个项目。换句话说,我们正在生成配置。

数字 24 来自项目类别,每个项目都与特定的安装位置相关联,位置 1 中的项目无法安装在位置 10 中,因此我安排了我的关联数组以分组组织数据。每个项目看起来像:

$items[9][] = array("id" => "0", "2" => 2, "13" => 20);

第一个参数 ($item[9]) 告诉您它允许进入的位置。如果您想考虑不能在排气管的位置安装轮胎的想法是可以的。

项目存储在 mySQL 数据库中。用户可以指定解决方案的限制条件,例如,属性 2 的最终值必须为 25 或更大。他们可以有多个相互竞争的限制。查询检索对所考虑的属性具有任何值的项目(未指定的属性被存储,但我们不对它们进行任何计算)。然后,PHP 脚本会删除任何多余的选择(例如:如果项目 1 的属性值为 3,而项目 2 的属性值为 5,则在没有另一个选项的情况下) 限制你永远不会选择第 1 项)。

所有处理完成后,得到一个关联数组,如下所示:

$items[10][] = array("id" => "3", "2" => 2, "13" => 100);
$items[10][] = array("id" => "4", "2" => 3, "13" => 50);
$items[9][] = array("id" => "0", "2" => 2, "13" => 20);
$items[9][] = array("id" => "1", "2" => -1, "13" => 50);

我在this pastebin link. 发布了一个完整的示例数据集。有理由相信我可以对数据集中接受的内容进行更多限制,但即使每个选项限制为 2 个元素,也存在问题。

在array()值中,id是对数组中item索引的引用,其他值是属性id和值对。所以$items[10][] = array("id" => "3", "2" => 2, "13" => 100); 意味着在位置 10 中有一个 id 为 3 的项目,它在属性 2 中的值为 2,在属性 13 中的值为 100。如果它有助于考虑由一对标识的项目,例如 (10, 0) 是位置 10 中的项目 0。

我知道我没有具体说明,有 61 个属性,我认为这不会改变问题的结构,因为它们代表的内容。如果我们愿意,我们可以将属性 2 视为权重,将属性 13 视为成本。用户想要解决的问题可能是生成一个权重正好为 25 且成本最小化的配置。

信封背面的数学表示粗略估计,如果每个位置只有 2 个选择,则为 2^24 个选择 x 记录大小。假设可以以某种方式对 32 位整数进行编码以表示单个记录,我们正在查看 16,777,216 * 4 = 67,108,864 字节的内存(完全忽略数据结构开销)并且没有理由相信这些假设中的任何一个都会是有效的,尽管内存上限为 67 兆的算法将是可接受的内存大小。

没有特别的理由坚持这种表示,我使用了关联数组,因为我可以使用可变数量的属性,并且认为这可以让我避免使用大型稀疏数组。上面的 "2"=>2 实际上意味着 id #2 的过滤属性的值为 2,同样,属性 13 的值为 100。我很高兴将我的数据结构更改为更紧凑的结构。

我的一个想法是,我确实有一个评估标准,可以用来丢弃大多数中间配置。例如,我可以计算 75 * "2" 的值" + 10 * "13" 的值来提供解决方案的相对权重。换句话说,如果对问题没有其他限制,则每个值属性 2 提高 1 的成本为 75,属性 13 的每个值的提升成本为 10。继续汽车零件的想法,将其想象为购买库存零件并让机械师根据我们的规格对其进行修改。

我看到过早丢弃配置的一个问题是,加权函数没有考虑诸如“最终结果必须有一个恰好是 25 的值“2”之类的限制。所以如果我有一个完整的 24 元素配置就可以了,我可以运行一个限制循环,丢弃不匹配的解决方案,然后最后按函数对剩余的解决方案进行排名,但我不确定是否存在有效让我能够更早地抛弃解决方案的思路。

有人对如何前进有任何建议吗?虽然语言无关的解决方案很好,但如果有一些相关的语言功能可能有用,我会在 PHP 中实现。

【问题讨论】:

  • 你能给出完整的描述和例子吗?那些“安装位置”是什么。每个位置您可以做出什么样的选择?归因 ID 是如何工作的?那么查询结果呢?这些是数据库查询吗?
  • @SpiderPig 我遗漏了很多细节以避免混淆人们并让它完全笼统,但我会根据您的要求添加更多细节。
  • 我的印象是深度优先搜索可能会提供我正在寻找的解决方案,因为我可以评估限制并决定要保留多少结果,调查仍在继续

标签: php algorithm cartesian-product


【解决方案1】:

我通过执行深度优先笛卡尔积解决了我的内存问题。我可以一次权衡一个解决方案,如果我选择或简单地输出它们,我可以保留一些解决方案,就像我在这段代码 sn-p 中所做的那样。

这个解决方案的主要灵感来自the very concise answer on this question。这是我的代码,因为似乎找到一个 php 深度优先笛卡尔积算法并不简单。

function dfcartesian ( $input, $current, $index ) {
    // sample use: $emptyArray = array();
    //             dfcartesian( $items, $emptyArray, 0 )
    if ( $index == count( $input ) ) {
        // If we have iterated over the entire space and are at the bottom
        // do whatever is relevant to your problem and return.
        //
        // If I were to improve the solution I suppose I'd pass in an
        // optional function name that we could pass data to if desired.
        var_dump( $current );
        echo '<br><br>';
        return;
    }

    // I'm using non-sequential numerical indicies in an associative array
    // so I want to skip any empty numerical index without aborting.
    //
    // If you're using something different I think the only change that
    // needs attention is to change $index + 1 to a different type of
    // key incrementer.  That sort of issue is tackled at
    // https://stackoverflow.com/q/2414141/759749
    if ( isset ( $input[$index] ) ) {
        foreach ( $input[$index] as $element ) {
            $current[] = $element;
            // despite my concern about recursive function overhead,
            // this handled 24 levels quite smoothly.
            dfcartesian( $input, $current, ( $index + 1 ) );
            array_pop( $current );
        }
    } else {
        // move to the next index if there is a gap
        dfcartesian( $input, $current, ( $index + 1 ) );
    }
}   

我希望这对解决同样问题的其他人有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-06
    • 2018-08-31
    • 2017-04-18
    • 1970-01-01
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多