如何测试一个设计用来仅通过五次比较来排序四个数字的系统?

huangapple go评论59阅读模式
英文:

How to Test a System Designed to Sort Four Numbers Using Only Five Comparisons?

问题

我有一个系统,可以使用五次比较来排序四个数字。该系统使用一系列名为“MinMax”的比较器箱,接受两个数字并输出最小值和最大值。我的配置如下:

  1. 我首先并行使用两个MinMax箱来比较a和b,以及c和d。
  2. 随后,将这些箱的最小值和最大值输出送入另外两个MinMax箱,以确定整体的最小值和最大值。
  3. 最后,使用一个最终的MinMax箱来比较第二小值和第二大值。

该系统旨在使用这五次比较来排序任何给定的四个数字序列。然而,我担心系统可能会出现故障 - 例如,如果其中一个MinMax箱出现故障。

我想设计一个测试,以确保系统的所有组件都正常运行。我的问题是:我可以输入哪个最小序列来验证系统的完整性,为什么选择这个序列?我寻找一个能够有效测试系统中的所有MinMax箱和连接的序列。
(有一个类似的问题询问如何排序,而不是如何测试。https://stackoverflow.com/questions/6145364/sort-4-number-with-few-comparisons)

英文:

I have a system to sort four numbers using a sequence of five comparisons. The system uses a series of 'MinMax' comparator boxes that take in two numbers and output the minimum and maximum. My configuration is as follows:

  1. I use two MinMax boxes in parallel to compare a & b and c & d initially.
  2. The minimum and maximum outputs from those boxes are then fed into two more MinMax boxes to determine the overall minimum and maximum.
  3. The second minimum and second maximum are then compared using a final MinMax box.

The system is designed to sort any given sequence of four numbers with these five comparisons. However, I am concerned about potential failures in the system - if one of the MinMax boxes were to malfunction, for instance.

I would like to devise a test to ensure that all components of the system are functioning correctly. My question is: What is the minimal sequence of numbers that I can input to verify the integrity of the system, and why those sequence? I'm looking for a sequence that would efficiently test all MinMax boxes and connections in the system.
(There is a similar question that ask how to sort, not how to test. https://stackoverflow.com/questions/6145364/sort-4-number-with-few-comparisons)

答案1

得分: 1

为了全面测试排序功能,您必须创建具有元素之间所有可能关系的输入样本。对于 N=4,一些示例可能如下所示:

{{C},{B},{A},{D}} → (C<B) & (B<A) & (A<D) → [2,1,0,3]
{{A,D},{B,C}} → (A=D) & (D<B) & (B=C) → [0,1,1,0]
{{B},{A,C,D}} → (B<A) & (A=C) & (C=D) → [1,0,1,1]

这里相同组的元素{}是相等的,但比前面的组元素大。

相等组的有序分区总数为2^N-1,您必须全部处理。在您的情况下,将有8个分区:

{1,1,1,1}
{1,1,2}
{1,2,1}
{2,1,1}
{1,3}
{2,2}
{3,1}
{4}

因此,对于每个分区,您必须迭代所有可能的不相交的N个元素集合。例如,对于分区{2,2},有6种这样的组合:

{{A,B},{C,D}}
{{A,C},{B,D}}
{{A,D},{B,C}}
{{B,C},{A,D}}
{{B,D},{A,C}}
{{C,D},{A,B}}

然后,为了获得具体的数字,只需为第一组元素设置值为0,并逐渐递增,以创建N个元素的实际样本,每个样本对于给定的分区都会产生唯一的排序:

{{A,B},{C,D}} → [0,0,1,1]
{{A,C},{B,D}} → [0,1,0,1]
{{A,D},{B,C}} → [0,1,1,0]
{{B,C},{A,D}} → [1,0,0,1]
{{B,D},{A,C}} → [1,0,1,0]
{{C,D},{A,B}} → [1,1,0,0]

当您完成所有分区时,您将获得对您的算法的完整单元测试(前提是无论被排序的数字的具体算术属性如何,它都表现出一致的行为)。

如果您不想手动执行此操作,以下代码段将生成N=4的所有样本(共75个):

英文:

In order to test sorting function exhaustively, you have to create input samples with all possible relations between their elements.<br>For N=4 some samples might look like this:

{{C},{B},{A},{D}}  →  (С&lt;B) &amp; (B&lt;A) &amp; (A&lt;D)  →  [2,1,0,3]
{{A,D},{B,C}}      →  (A=D) &amp; (D&lt;B) &amp; (B=C)  →  [0,1,1,0]
{{B},{A,C,D}}      →  (B&lt;A) &amp; (A=C) &amp; (C=D)  →  [1,0,1,1]

Here elements of the same group {} are equal, but greater than elements of previous groups.

Total number of ordered partitions of equality groups is 2<sup>N-1</sup>, all of which you have to work through.<br>In your case there will be 8 partitions:

{1,1,1,1}
{1,1,2}
{1,2,1}
{2,1,1}
{1,3}
{2,2}
{3,1}
{4}

So for each partition, you have to iterate over all possible disjoint sets of N elements.<br>For example, for the partition {2,2} there're 6 such combinations:

{{A,B},{C,D}}
{{A,C},{B,D}}
{{A,D},{B,C}}
{{B,C},{A,D}}
{{B,D},{A,C}}
{{C,D},{A,B}}

Then, in order to get concrete numbers, it's enough to set a value of 0 for the elements of the first group, and increase it by 1 for the elements of each subsequent group. This will create actual samples of N elements, each resulting in a unique ordering for a given partition:

{{A,B},{C,D}}  →  [0,0,1,1]
{{A,C},{B,D}}  →  [0,1,0,1]
{{A,D},{B,C}}  →  [0,1,1,0]
{{B,C},{A,D}}  →  [1,0,0,1]
{{B,D},{A,C}}  →  [1,0,1,0]
{{C,D},{A,B}}  →  [1,1,0,0]

When you're done with all partitions, you'll have a complete unit test for your algorithm (provided that it behaves coherently regardless of specific arithmetic properties of the numbers being sorted).

If you don't like doing it by hand, the following snippet will generate all samples for N=4 (75 in total):

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

function generateSamples (length, callback) {

    // test sample
    let sample = new Uint32Array(length);

    // doubly linked list of unused indices in sample
    let unused = [];
    let unusedHead = 0;
    let unusedCount = length;
    for (let i = 0; i &lt; length; i++) {
        unused.push({ index: i, prev: null, next: null });
    }
    for (let i = 1; i &lt; length; i++) {
        unused[i - 1].next = unused[i];
        unused[i].prev = unused[i - 1];
    }

    // list of group sizes
    let partition;

    // flag for callback
    let newPartition;

    // recurse groups
    function processNextGroup (groupId) {

        // proceed to the next group
        if (groupId &lt; partition.length) {
            processNextElement(groupId, partition[groupId], unused[unusedHead], unusedCount - partition[groupId] + 1);
        }

        // the final group is exhausted, the sample is complete
        else if (newPartition) {
            newPartition = false;
            callback(sample.slice(), `{${partition.join(&#39;,&#39;)}}`);
        }
        else {
            callback(sample.slice(), false);
        }
    }

    // recurse group elements
    function processNextElement (groupId, groupSize, indexItem, variants) {

        // iterate over remaining variants for the current element
        for (let i = 0; i &lt; variants; i++, indexItem = indexItem.next) {

            // unlink index item from the list
            if (indexItem.prev) {
                indexItem.prev.next = indexItem.next;
            }
            else {
                unusedHead = indexItem.next?.index;
            }
            if (indexItem.next) {
                indexItem.next.prev = indexItem.prev;
            }

            // update current sample element
            sample[indexItem.index] = groupId;

            // recurse...
            unusedCount--;
            if (groupSize &gt; 1) {
                // ... to the next element
                processNextElement(groupId, groupSize - 1, indexItem.next, variants - i);
            }
            else {
                // ... to the next group
                processNextGroup(groupId + 1);
            }
            unusedCount++;

            // return index item to the list
            if (indexItem.prev) {
                indexItem.prev.next = indexItem;
            }
            else {
                unusedHead = indexItem.index;
            }
            if (indexItem.next) {
                indexItem.next.prev = indexItem;
            }
        }
    }

    // generate partitions by iterating bitmaps
    // - 1-bit: current element starts new group
    // - 0-bit: current element continues the last group
    let maxBitmap = 2 ** (length - 1);
    for (let bitmap = 0; bitmap &lt; maxBitmap; bitmap++) {

        partition = [];
        let groupSize = 1;
        for (let pos = length - 2; pos &gt;= 0; pos--) {
            if ((bitmap &gt;&gt;&gt; pos) &amp; 1) {
                partition.push(groupSize);
                groupSize = 1;
            }
            else {
                groupSize++;
            }
        }
        partition.push(groupSize);
        newPartition = true;

        // generate every combination of the current partition
        processNextGroup(0);
    }
}

let lastSignature;
let samples;
let samplesAll = [];

function logSamples (caption, samples) {
    console.log(caption);
    console.log(`[\n  [${samples.join(&#39;],\n  [&#39;)}]\n]`);
}

generateSamples(4, (sample, newSignature) =&gt; {
    if (newSignature) {
        if (samples) {
            logSamples(`Partition = ${lastSignature}`, samples);
        }
        lastSignature = newSignature;
        samples = [];
    }
    samples.push(sample);
    samplesAll.push(sample);
});
logSamples(`Partition = ${lastSignature}`, samples);
logSamples(`ALL SAMPLES: ${samplesAll.length}`, samplesAll);

<!-- end snippet -->

PS: The function generateSamples can generate larger sets for whatever reasons. I tested it up to N=9 which yielded 7,087,261 combinations. Internally it uses O(N) space and generates each sample in O(N) time.

答案2

得分: 1

由于零一原则对于排序网络的适用性,如果你的排序算法可以看作是一个排序网络(正如你所称的MinMax框的组合几乎是排序网络的定义),那么只需检查所有的二进制输入就足够了,在这种情况下只有2<sup>4</sup>=16种可能。

这些输入对应于数字0到15(将作为4个单独的位输入到算法中),因此生成输入序列的算法非常简单。

英文:

Thanks to the zero-one principle of sorting networks, if your sorting algorithm can be viewed as a sorting network (a composition of MinMax boxes as you call them is pretty much the definition of a sorting network) it suffices to check all binary inputs, of which there are only 2<sup>4</sup>=16 in this case.

Those inputs correspond to the numbers 0..15 (which would be fed into the algorithm as 4 separate bits, not one number) so the algorithm to generate the sequence of inputs is trivial.

答案3

得分: 0

有4!= 24种(1,2,3,4)的排列。枚举它们很容易。如果您的系统将其中一些排序错误,那么它是有问题的。如果它正确排序了所有这些排列,我们可以声明它正确地排序了(1,2,3,4)的排列。这增强了对其正确运行的信心,但不能证明它。确实,如果您的系统中的一个比较箱比较了23002936894782192854和94528594871170264370,而且只有这一对排序不正确呢?要排除所有这种故障模式,需要检查所有4个数字的所有排列,而这些排列有无限多。

英文:

There are 4!=24 permutations of (1,2,3,4). It is easy to enumerate them. If your system sorts some of them incorrectly, then it is broken. If it sorts all of them correctly, we can claim that it correctly sorts permutations of (1,2,3,4). This inspires confidence in its correct functioning, but cannot prove it. Indeed, what if one of your boxes compares 23002936894782192854 and 94528594871170264370, and only this pair, incorrectly? It is impossible to weed out all such failure modes without checking all permutations of all 4-tuples of numbers, and there are infinitely many of those.

huangapple
  • 本文由 发表于 2023年5月28日 06:47:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76349325.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定