生成速记功能签名

时间:2013-12-04 22:54:02

标签: algorithm signature formal-languages

假设函数foo()具有以下四个重载:

foo(a, b)
foo(a, b, d)
foo(a, c)
foo(a, c, d)

我想生成一个简洁的字符串,一次代表所有重载。在这种情况下,结果应为foo(a, (b|c), [d])

编辑:通常有多个简洁的表示形式。我的目标是获得尽可能短的表示,仅计算参数。因此foo(a, (b|c), [d])长度为4,因此优于foo(a, ((b, [d])|(c, [d]))),其长度为5。

是否存在解决此(或类似)问题的现有算法?

如果没有,任何人都可以草拟一种方法吗?

我对编程语言并不挑剔(不过我正在使用C#)。

规则是:

  • 具有相同名称的参数代表所有重载的相同内容。 aabb ...
  • 在所有重载(在本例中为a, b, c, d)收集所有不同参数时,每个重载都将遵循此参数顺序。
  • [...]表示封闭的子表达式可以作为一个整体省略。
  • (...|...|...)表示选择其中一个子表达式。为了便于阅读,这样的子表达式不能为空。

进一步说明:(相当人为的)函数bar()

bar(a, b,          f, g, h, i)
bar(a, b,          f, g, h)
bar(a, b,          f, g)

bar(a,    c,          g, h, i)
bar(a,    c,          g, h)
bar(a,    c,          g)

bar(a,       d,    f, g, h, i)
bar(a,       d,    f, g, h)
bar(a,       d,    f, g)

bar(a,          e, f, g, h, i)
bar(a,          e, f, g, h)
bar(a,          e, f, g)

应表示为bar(a, (((b|d|e), f)|c), g, [h, [i]])

3 个答案:

答案 0 :(得分:1)

实际上,可以减少问题以简化逻辑电路。 您可以使用卡诺图来执行简化:

http://en.wikipedia.org/wiki/Karnaugh_map

编辑:电路最小化问题: http://en.wikipedia.org/wiki/Circuit_minimization

基于假设功能参数之间不存在顺序变化,从过载问题减少到电路最小化。通过写入True Table来执行缩减,其中电路的输入参数恰好是函数的所有可能参数,并且对于每个现有的重载,电路的输出对于所有行(和确切地说,重载的使用参数是'1'。

答案 1 :(得分:0)

我不知道是否有一种标准方法可以解决它,但这是一个建议的启发式方法。请注意,我不考虑此建议中的表现。

  1. 您始终可以将此类重载表示为所有可能组合的“OR”ed表达式的“普通”形式:

    foo( (a, b) | (a, b, d) | (a, c) | (a, c, d) )
    
  2. 如果要提取更简单的表单,可以尝试使用贪心算法。从简单形式的ORed表达式开始。然后使用以下基本步骤 - 比较表达式对,看看它们是否可以按以下方式分组:

    • 或者| ,.例如(a,b)| (a,c) - > (a,(b | c))
    • 选择性[] ,.例如(a,b)| (a,b,d) - > (a,b,[d])

    应该完成基本步骤:

    • 直到无法进行分组。
    • 递归:算法应该遍历子表达式以检查内部对是否可以分组。
  3. 上述算法不保证最佳形式。例如,这里可以在foo输入上执行上述算法('{'仅用于可读性,它们与'(')相同:

        (a, b) | (a, b, d) | (a, c) | (a, c, d)
        (a, b, [d]) | (a, c) | (a, c, d)
        (a, b, (c | [d]) | (a, c, d)
        a, {(b, {c | [d]}) | (c, d)}
    

    这比你提出的形式复杂得多,a,(b | c),[d]。要创建表达式的最佳形式,您应首先声明什么是最佳形式。根据这样的声明,您可以决定是否可以使用贪婪算法作为起点并强制结果根据您的需要进行优化,或者您应该有另一种算法。

    以下是有关如何获得更优化形式的演示:

    1. 在可选性之前,可以强制算法通过OR表达式进行分组。然后上面的执行无效,典型的执行就像:

      (a, b) | (a, b, d) | (a, c) | (a, c, d)
      {a, (b | c)} | (a, c) | (a, c, d)
      {a, (b | c)} | (a, b, d) | (a, c, d)
      a, { (b | c) | (b, d) | (c, d) }
      a, { (b | c) | (b | c, d) }
      a, { (b | c) , [d] }
      
    2. 可以对所有可能的分组操作顺序进行反向跟踪算法,以找到存在的最佳形式。

答案 2 :(得分:0)

首先,让我们指定一些命名法。

  • [...]是一个选项。
  • ..., ...是一个序列。
  • ... | ...是一个选择。

由于两个原因,这个问题似乎很棘手。首先,语法与布尔表达式中的语法不同。例如,尽管Choice类似于OR,但它意味着“采取任何一个”,而不是“至少采取一个”。因此,生成最佳布尔表达式的算法一旦“翻译”为我们的语法,就可能导致次优结果。

其次,最佳解决方案可能类似于选项内序列中的选择内的序列。因此,任何只能创建一种结构的算法(如序列选择)都不可能总是返回最优解。

以下介绍了我找到的解决方案。还有a working implementation

首先,我们需要在所有重载上创建所有不同参数的列表。根据问题,每个重载都将遵循此参数顺序。因此,每个重载都可以表示为布尔数组,其中每个条目指示是否存在相应的参数。现在,参数列表和重载列表被赋予一个递归函数,其作用如下:

  1. 删除重复的重载,以便每个重载都是不同的。
  2. 如果只有一个重载,则返回已使用参数的序列。
  3. 如果其中一个重载为空:以递归方式调用该函数并返回所有其他重载并在结果中返回结果。
  4. 将参数列表拆分为常量区域(对于所有过载都相同)和独立区域。每个独立区域应尽可能短。如果您可以采取任何过载并将该区域内的标志替换为来自任何其他过载的标志,则该区域是独立的。如果此拆分导致至少一个常量区域,则返回包含常量部分的序列并递归独立区域。
  5. 如果所有这些都失败了,可能是因为重载太不相同了。因此,创建多个类似的重载组。要通过强力执行此操作,请生成所有分区(请参阅How to find all partitions of a set)。对于每个分区中的每组重载,递归调用该函数并将结果与​​Choice组合。然后返回最短的选择。
  6. 我相信由于上述原因,找到最佳解决方案的算法不会简单得多。我无法证明这个算法确实总能找到最佳解决方案,但对于我迄今为止尝试过的签名,确实找到了。