在Python中实现贪婪排名算法的教程
admin
2023-07-31 02:13:43
0

 在较早的一遍文章中,我曾经提到过我已经写了一个属于自己的排序算法,并且认为需要通过一些代码来重新回顾一下这个排序算法。

对于我所完成的工作,我核实并且保证微处理器的安全。对非常复杂的CPU进行测试的一个方法就是创建该芯片的另一个模型,其可以用来产生在CPU上运行的伪随机指令流。这所谓的ISG(指令流产生器)能够在很短的时间内创建几千(甚至几百万)个这样的测试,通过某种方式,使其可以巧妙地给出一些对将在CPU上执行的指令流的控制或操纵。

现在对这些指令流进行模拟,可以通过每一个测试实例花费的时间获取到CPU的那一部分被使用了(这叫做被覆盖)的信息,并且ISG所产生的的过个测试可能会覆盖CPU的同一个区域。为了增加CPU的整体覆盖范围,我们启动一个被称作复原的行为——所有的测试都运行,并且它们的覆盖范围和花费的时间将被存储起来。在这次复原的最后,您可能会有几千个测试实例只覆盖了CPU的某一部分。

如果你拿着这个复原测试的记过,并且对其进行排序,你会发现这个测试结果的一个子集会给出它们覆盖了CPU的所有部分。通常,上千的伪随机测试可能会被排序,进而产生一个只有几百个测试的子列表,它们在运行时将会给出同样的覆盖范围。接下来我们经常会做的是,查看CPU的哪个部分没有被覆盖,然后通过ISG或其它方法在产生更多的测试,来试图填补这一空白。再然后会运行一次新的复原,并且循环得再一次进行排序来充分使用该CPU,以达到某个覆盖范围目标。

对测试进行排名是复原流程的一个重要部分,当其进行地很好时你可能就会忘记它。不幸的是,有时,当我想要对其它数据进行排名时,CAD工具厂商所提供的常用排名算法并不适合。因此,能够扩展到处理成百上千个测试和覆盖点才是一个排名算法的本质。
 
输入

通常情况下,我不得不从其他CAD程序产生的文本或HTML文件来解析我的输入 – 这是个是单调乏味的工作,我会跳过这个乏味的工作,而通过以Python字典的形式提供理想的输入。 (有时用于解析输入文件的代码可以跟排名算法一样大或着更大)。
让我们假设每个ISG测试都有一个名称,在确定的“时间”内运行,当模拟显示\’覆盖\’设计中的 一组编号的特性时。解析之后,所收集的输入数据由程序中的结果字典来表示。

 

results = {
#  \'TEST\': ( TIME, set([COVERED_POINT ...])),
 \'test_00\': ( 2.08, set([2, 3, 5, 11, 12, 16, 19, 23, 25, 26, 29, 36, 38, 40])),
 \'test_01\': ( 58.04, set([0, 10, 13, 15, 17, 19, 20, 22, 27, 30, 31, 33, 34])),
 \'test_02\': ( 34.82, set([3, 4, 6, 12, 15, 21, 23, 25, 26, 33, 34, 40])),
 \'test_03\': ( 32.74, set([4, 5, 10, 16, 21, 22, 26, 39])),
 \'test_04\': (100.00, set([0, 1, 4, 6, 7, 8, 9, 11, 12, 18, 26, 27, 31, 36])),
 \'test_05\': ( 4.46, set([1, 2, 6, 11, 14, 16, 17, 21, 22, 23, 30, 31])),
 \'test_06\': ( 69.57, set([10, 11, 15, 17, 19, 22, 26, 27, 30, 32, 38])),
 \'test_07\': ( 85.71, set([0, 2, 4, 5, 9, 10, 14, 17, 24, 34, 36, 39])),
 \'test_08\': ( 5.73, set([0, 3, 8, 9, 13, 19, 23, 25, 28, 36, 38])),
 \'test_09\': ( 15.55, set([7, 15, 17, 25, 26, 30, 31, 33, 36, 38, 39])),
 \'test_10\': ( 12.05, set([0, 4, 13, 14, 15, 24, 31, 35, 39])),
 \'test_11\': ( 52.23, set([0, 3, 6, 10, 11, 13, 23, 34, 40])),
 \'test_12\': ( 26.79, set([0, 1, 4, 5, 7, 8, 10, 12, 13, 31, 32, 40])),
 \'test_13\': ( 16.07, set([2, 6, 9, 11, 13, 15, 17, 18, 34])),
 \'test_14\': ( 40.62, set([1, 2, 8, 15, 16, 19, 22, 26, 29, 31, 33, 34, 38])),
 }

 

贪婪排名算法的核心是对当前选择测试的子集进行排序:

  •     至少用一个测试集覆盖尽可能大的范围。
  •     经过第一个步骤,逐步减少测试集,同时覆盖尽可能大的范围。
  •     给选择的测试做出一个排序,这样小数据集的测试也可以选择使用
  •     完成上述排序后,接下来就可以优化算法的执行时间了
  •     当然,他需要能在很大的测试集下工作。

贪婪排名算法的工作原理就是先选择当前测试集的某一项的最优解,然后寻找下一项的最优解,依次进行…

如果有两个以上的算法得出相同的执行结果,那么将以执行”时间“来比较两种算法优劣。

用下面的函数完成的算法:
 

def greedyranker(results):
  results = results.copy()
  ranked, coveredsofar, costsofar, round = [], set(), 0, 0
  noncontributing = []
  while results:
    round += 1
    # What each test can contribute to the pool of what is covered so far
    contributions = [(len(cover - coveredsofar), -cost, test)
             for test, (cost, cover) in sorted(results.items()) ]
    # Greedy ranking by taking the next greatest contributor        
    delta_cover, benefit, test = max( contributions )
    if delta_cover > 0:
      ranked.append((test, delta_cover))
      cost, cover = results.pop(test)
      coveredsofar.update(cover)
      costsofar += cost
    for delta_cover, benefit, test in contributions:
      if delta_cover == 0:
        # this test cannot contribute anything
        noncontributing.append( (test, round) )
        results.pop(test)
  return coveredsofar, ranked, costsofar, noncontributing

每次while循环(第5行),下一个最好的测试会被追加到排名和测试,不会 丢弃贡献的任何额外覆盖(37-41行)

上面的函数是略显简单,所以我花了一点时间用tutor来标注,当运行时打印出它做的。
函数(有指导):
它完成同样的事情,但代码量更大,太繁冗:
 

def greedyranker(results, tutor=True):
  results = results.copy()
  ranked, coveredsofar, costsofar, round = [], set(), 0, 0
  noncontributing = []
  while results:
    round += 1
    # What each test can contribute to the pool of what is covered so far
    contributions = [(len(cover - coveredsofar), -cost, test)
             for test, (cost, cover) in sorted(results.items()) ]
    if tutor:
      print(\'\\n## Round %i\' % round)
      print(\' Covered so far: %2i points: \' % len(coveredsofar))
      print(\' Ranked so far: \' + repr([t for t, d in ranked]))
      print(\' What the remaining tests can contribute, largest contributors first:\')
      print(\'  # DELTA, BENEFIT, TEST\')
      deltas = sorted(contributions, reverse=True)
      for delta_cover, benefit, test in deltas:
        print(\'   %2i,  %7.2f,  %s\' % (delta_cover, benefit, test))
      if len(deltas)>=2 and deltas[0][0] == deltas[1][0]:
        print(\' Note: This time around, more than one test gives the same\')
        print(\'    maximum delta contribution of %i to the coverage so far\'
            % deltas[0][0])
        if deltas[0][1] != deltas[1][1]:
          print(\'    we order based on the next field of minimum cost\')
          print(\'    (equivalent to maximum negative cost).\')
        else:
          print(\'    the next field of minimum cost is the same so\')
          print(\'    we arbitrarily order by test name.\')
      zeroes = [test for delta_cover, benefit, test in deltas
           if delta_cover == 0]
      if zeroes:
        print(\' The following test(s) cannot contribute more to coverage\')
        print(\' and will be dropped:\')
        print(\'  \' + \', \'.join(zeroes))
 
    # Greedy ranking by taking the next greatest contributor        
    delta_cover, benefit, test = max( contributions )
    if delta_cover > 0:
      ranked.append((test, delta_cover))
      cost, cover = results.pop(test)
      if tutor:
        print(\' Ranking %s in round %2i giving extra coverage of: %r\'
            % (test, round, sorted(cover - coveredsofar)))
      coveredsofar.update(cover)
      costsofar += cost
 
    for delta_cover, benefit, test in contributions:
      if delta_cover == 0:
        # this test cannot contribute anything
        noncontributing.append( (test, round) )
        results.pop(test)
  if tutor:
    print(\'\\n## ALL TESTS NOW RANKED OR DISCARDED\\n\')
  return coveredsofar, ranked, costsofar, noncontributing

每一块以  if tutor开始:  添加以上代码

样值输出
调用排序并打印结果的代码是:
 

totalcoverage, ranking, totalcost, nonranked = greedyranker(results)
print(\'\'\'
A total of %i points were covered,
using only %i of the initial %i tests,
and should take %g time units to run.
 
The tests in order of coverage added:
   
  TEST DELTA-COVERAGE\'\'\'
 % (len(totalcoverage), len(ranking), len(results), totalcost))
print(\'\\n\'.join(\' %6s %i\' % r for r in ranking))

结果包含大量东西,来自tutor并且最后跟着结果。

对这个伪随机生成15条测试数据的测试案例,看起来只需要七条去产生最大的总覆盖率。(而且如果你愿意放弃三条测试,其中每个只覆盖了一个额外的点,那么15条测试中的4条就将给出92.5%的最大可能覆盖率)。

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...