【问题标题】:completely testing an algorithm output (dynamic programming longest subsequence)完全测试算法输出(动态规划最长子序列)
【发布时间】:2018-03-27 17:25:46
【问题描述】:

在我开始之前,我只想说这是一个家庭作业。我最近在这门课上遇到的一个问题是能够有效地测试我的代码,这样当我提交我的解决方案时,我可以确信所有输入组合都会被覆盖。有人告诉我,很多测试都是主观的,需要对实现有实际的了解……一种尺寸永远不会适合所有人。话虽这么说,是否有关于如何有效测试的指导方针?

我目前正在努力解决的一个例子是最长子序列 if 元素的动态编程实现。我所有的测试都有效,但是当我提交给评分者时,我陷入了我认为是边缘情况的问题(我们不允许在某个测试之后看到失败测试用例的输入或输出)。

import java.util.Arrays;
import java.util.Scanner;

public class LCS2 {
    int [][] solutionMatrix;
    public int lcs2(int[] a, int[] b) {
        final int aARRAY_LENGTH = a.length + 1;
        final int bARRAY_LENGTH = b.length + 1;
        solutionMatrix = new int[aARRAY_LENGTH][bARRAY_LENGTH];


    //set endge indexes equal to i
    for (int i = 1; i < aARRAY_LENGTH; i++) {
        solutionMatrix[i][0] = i;
    }
    for (int i = 1; i < bARRAY_LENGTH; i++) {
        solutionMatrix[0][i] = i;
    }
    //fill in matrix to determine if each element is a insert, delete, match or mismatch
    for (int i = 1; i < aARRAY_LENGTH; i++) {
        for (int j = 1; j < bARRAY_LENGTH; j++) {
            int insertion = solutionMatrix[i    ][j - 1] + 1;
            int deletion  = solutionMatrix[i - 1][j    ] + 1;
            int match     = solutionMatrix[i - 1][j - 1];
            int mismatch  = solutionMatrix[i - 1][j - 1] + 1;
            //System.out.println("i: " + i + " j: " + j + " [" +insertion + " " + deletion + " " + match + " " + mismatch + "] ");
            if (a[i - 1] == b[j - 1])
                solutionMatrix[i][j] = Math.min(insertion, Math.min(deletion,match));
            else
                solutionMatrix[i][j] = Math.min(insertion, Math.min(deletion,mismatch));
        }
    }
    //print out matrix for visualization
    System.out.println("       " + Arrays.toString(b));
    for (int i = 0; i < aARRAY_LENGTH; i++) {
      if (i - 1 < 0)
        System.out.println("    " + Arrays.toString(solutionMatrix[i]));
      else
        System.out.println("[" + a[i -1] + "] " + Arrays.toString(solutionMatrix[i]));
    }
    return outputAlignment(a.length, b.length, 0);
}
private int outputAlignment(int i, int j, int ret){
    //recursive call..  if indexes are 0 then return
    if (i == 0 && j == 0)
        return ret;
    //find pointer.. is this a insert, deletion, match or mismatch
    int backtrack = backtrack(i, j);
    //change current index based on result of backtrack
    if (backtrack == 3)
    //if matched then add one to the longest sequence
        ret = outputAlignment(i - 1, j - 1, ret) + 1;
    else if (backtrack == 2)
        ret = outputAlignment(i - 1, j    , ret);
    else if (backtrack == 1)
        ret = outputAlignment(i    , j - 1, ret);
    else
        ret = outputAlignment(i - 1, j - 1, ret);

    return ret;
}
private int backtrack(int i, int j){
    //System.out.println("i: " + i + " j: " + j);
    int currValue = solutionMatrix[i][j];
   // System.out.println(currValue);
    if (     currValue == solutionMatrix[i    ][j - 1] + 1)
        return 1; // insertion
    else if (currValue == solutionMatrix[i - 1][j    ] + 1)
        return 2; //deletion
    else if (currValue == solutionMatrix[i - 1][j - 1]    )
        return 3; //match
    else if (currValue == solutionMatrix[i - 1][j - 1] + 1)
        return 4; //mismatch
    return 5;
}

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int n = scanner.nextInt();
    int[] a = new int[n];
    for (int i = 0; i < n; i++) {
        a[i] = scanner.nextInt();
    }

    int m = scanner.nextInt();
    int[] b = new int[m];
    for (int i = 0; i < m; i++) {
        b[i] = scanner.nextInt();
    }
    LCS2 lcs = new LCS2();
    System.out.println(lcs.lcs2(a, b));
}
}

这是我整理的一些 junit 测试,无需额外设置即可运行。

  @Test
public void testLCS2(){
    LCS2 lcs = new LCS2();
    int[] a = {2,7,5};
    int[] b = {2,5};
    assertEquals("Testing Longest Common SubSequence for [2,7,5] --> [2,5]", 2,lcs.lcs2(a,b));

    a = new int[] {2,3,9};
    b = new int[] {2,9,7,8};
    assertEquals("Testing Longest Common SubSequence for [2,3,9] --> [2,9,7,8]", 2,lcs.lcs2(a,b));

    a = new int[] {1,2,3,4};
    b = new int[] {1,2,3,4};
    assertEquals("Testing Longest Common SubSequence for [1,2,3,4] --> [1,2,3,4]", 4,lcs.lcs2(a,b));

    a = new int[] {7};
    b = new int[] {1,2,3,4};
    assertEquals("Testing Longest Common SubSequence for [7] --> [1,2,3,4]", 0,lcs.lcs2(a,b));

    a = new int[] {2,7,8,3};
    b = new int[] {5,2,8,7};
    assertEquals("Testing Longest Common SubSequence for [2,7,8,3] --> [5,2,8,7]", 2,lcs.lcs2(a,b));

    a = new int[] {1,1,1,1};
    b = new int[] {1,2,3,4};
    assertEquals("Testing Longest Common SubSequence for [2,7,8,3] --> [5,2,8,7]", 1,lcs.lcs2(a,b));

    a = new int[] {1,1,1,1};
    b = new int[] {1,2,3,4,1};
    assertEquals("Testing Longest Common SubSequence for [2,7,8,3] --> [5,2,8,7]", 2,lcs.lcs2(a,b));
}

【问题讨论】:

  • 你说的我们不能看到失败的测试用例的输入或输出是什么意思?如果评分者无法提供有用的反馈来帮助您学习,请与教授交谈。
  • 是的,关键是我们看不到评分器的输出。它是为了让我们“思考”和调试自己。
  • 认为评分员是个混蛋。在现实世界中,您要做的第一件事是获取导致错误的输入,以便您可以重新创建错误以便对其进行调试。与教授交谈。
  • 制作一个随机生成小子序列的函数,并制作一个蛮力求解器并针对蛮力求解器测试您的解决方案。如果它给了你正确的答案,那么你的解决方案很可能是正确的。现在考虑较大序列的错误-> 内存不足、整数溢出、堆栈溢出过多递归、超时等。制作一些超大序列来测试它,直到它崩溃。玩得开心。

标签: java algorithm dynamic-programming


【解决方案1】:

在此处发帖之前,您应该先完成研究以回答您提出的问题:“是否有关于如何有效测试的指南?”很容易找到关于令人麻木的长度的概述,例如 this 非常好的一个。

在您的情况下,我建议概述“等价类”。由于详尽的测试在大多数情况下是不切实际的,并且当输入是任意长度时也是不可能的,因此您开发了具有代表性的案例——每个类别一个,代表该类别的所有成员。例如,没有共同成员的列表可能会形成一个这样的类。

我不能很好地评价你给定的测试,部分原因是你没有解释为什么你测试这些特定的输入,或者为什么你决定这些是充足的。等价类要求您分析问题以确定(或估计)各种输入之间可能存在哪些处理差异。

写出你的理由,或许可以找个朋友和你一起头脑风暴。您是否涵盖了算法的第一次迭代可能会走错路并不得不回溯的各种方式?

【讨论】:

    【解决方案2】:

    因此,结合您的所有回复,我最终做了以下工作,非常感谢您的帮助。

    1. 要比较的布鲁斯力算法
    2. 在我的底层算法中发现了错误
    3. 只用一个从 main 或 junit 调用的方法来简化整个事情

      int [][] solutionMatrix;
      public int lcs2(int[] a, int[] b) {
        final int aARRAY_LENGTH = a.length + 1;
        final int bARRAY_LENGTH = b.length + 1;
        solutionMatrix = new int[aARRAY_LENGTH][bARRAY_LENGTH];
      
      
        //fill in matrix to determine if each element is a insert, delete, match or mismatch
      
        for (int i=0; i<=a.length; i++) {
            for (int j=0; j<=b.length; j++) {
                if (i == 0 || j == 0)
                    solutionMatrix[i][j] = 0;
                else if (a[i-1] == b[j-1])
                    solutionMatrix[i][j] = solutionMatrix[i-1][j-1] + 1;
                else
                    solutionMatrix[i][j] = Math.max(solutionMatrix[i-1][j], solutionMatrix[i][j-1]);
            }
        }
      
        return solutionMatrix[a.length][b.length];
      

      }

    【讨论】:

      猜你喜欢
      • 2016-08-12
      • 2017-04-26
      • 2016-05-02
      • 2019-05-28
      • 1970-01-01
      • 2011-10-18
      • 2012-06-28
      • 2021-12-24
      • 2011-02-07
      相关资源
      最近更新 更多