Algorithm 如何优化跳转表的大小?

Algorithm 如何优化跳转表的大小?,algorithm,enums,mathematical-optimization,Algorithm,Enums,Mathematical Optimization,考虑类似C语言中的典型枚举类型,如下所示: enum foo { FOO_A, FOO_B, FOO_C, /* ... */ FOO_N }; enum example { EX_A, EX_C, EX_B, EX_D }; 存在类型为enum foo的switch语句转换值,可能不处理某些枚举值: enum foo bar; /* ... */ switch (bar) { case FOO_A: /* ... */

考虑类似C语言中的典型枚举类型,如下所示:

enum foo {
    FOO_A,
    FOO_B,
    FOO_C,
    /* ... */
    FOO_N
};
enum example {
    EX_A,
    EX_C,
    EX_B,
    EX_D
};
存在类型为
enum foo
的switch语句转换值,可能不处理某些枚举值:

enum foo bar;
/* ... */
switch (bar) {
case FOO_A: /* ... */
case FOO_B: /* ... */
case FOO_D: /* ... */
case FOO_L: /* ... */
default: /* ... */
}
现在,为了处理足够多的枚举值,编译器需要使用大小为(-+1)*sizeof(void*)的跳转表来实现switch语句

假设我有多个这样的switch语句,已知它们使用跳转表,因为每个语句都知道哪些值正在处理,哪些值没有处理。我如何重新排序
enum foo
中的值,使生成的所有跳转表的总大小最小

例子 下面是一个稍微简化的示例,它假设编译器为所有switch语句生成跳转表。这是枚举:

enum example {
    EX_A,
    EX_B,
    EX_C,
    EX_D
};
下面是两个switch语句:

enum example a, b;

switch (a) {
case EX_A: /* ... */
case EX_C: /* ... */
default: /* ... */
}

switch (b) {
case EX_B: /* ... */
case EX_D: /* ... */
default: /* ... */
}
对于本例,编译器将生成两个跳转表,每个跳转表有三个条目(第一种情况下从
EX_A
EX_C
,第二种情况下从
EX_B
EX_D
),总计6个用于跳转表的机器字。如果我对枚举进行了如下重新排序:

enum foo {
    FOO_A,
    FOO_B,
    FOO_C,
    /* ... */
    FOO_N
};
enum example {
    EX_A,
    EX_C,
    EX_B,
    EX_D
};
对于跳转表,我只需要4个数据字。

一个解决方案(可能有一个更快的解决方案)。就是用部分暴力

如果将每个开关视为一个集合,则所有集合(即开关)的交点可以首先聚束

具有以下枚举:

enum example {
    EX_A,
    EX_B,
    EX_C,
    EX_D,
    EX_E
};
这两个开关语句:

enum example a, b;

switch (a) {
case EX_A: /* ... */
case EX_C: /* ... */
default: /* ... */
}

switch (b) {
case EX_B: /* ... */
case EX_D: /* ... */
default: /* ... */
}
枚举示例a、b

switch (a) {
case EX_A: /* ... */
case EX_C: /* ... */
case EX_E: /* ... */
default: /* ... */
}

switch (b) {
case EX_B: /* ... */
case EX_D: /* ... */
case EX_E: /* ... */
default: /* ... */
}
十字路口是:

{ EX_E }
其余要素包括:

{ EX_A, EX_B, EX_C, EX_D }

所以你可以把交集放在第一位,然后遍历其余的所有排列,生成所有的跳转表,看看哪一个是较小的。这是n!(在本例中,您必须查看4!=24个配置)。

此问题是NP难问题,因为它将最小线性排列问题(MinLA)从图形推广到超图,MinLA是NP难问题(Garey--Johnson--Stockmeyer 1976)

已经对精确和近似求解MinLA进行了一些研究。有一个θ(2^n m)时间动态程序(Koren--Harel 2002),看起来可以推广。有很多关于线性规划松弛的工作,既要获得保证的近似值,又要用于分支定界。不幸的是,对于求解者来说,这些放松似乎都太大了。可能有人尝试过约束编程,但我粗略的搜索没有结果。有许多启发式方法,包括以下由Juvan和Mohar(1992)提出的可爱想法:根据拉普拉斯算子的第二个特征向量对标签进行排序


由于只有50个标签,如果能找到可证明的最佳排列,我不会感到惊讶,但如果它不需要在感兴趣的实例上进行几轮新的算法设计、实现和实验,我会感到惊讶。如果你想学习其中的一些技巧,我推荐帕斯卡·范·亨特纳里克的Coursera课程(我从他在布朗大学附属时的课程中学习了早期版本)。

如果我见过的话,这是一个超微小的微优化。这似乎是一个最小化的优化问题,例如,
max(EX_A,EX_C)-min(EX_A,EX_C)
max(EX_B, EX_D) - min(EX_B, 例如)
(你可以简单地添加它们,或者做一些更复杂的事情)(因此你可以简化它来解决这个问题)。@Dukeling感谢你澄清我的问题。你知道我怎样才能解决这个问题吗?哦,所有的一切都是独一无二的。不,我真的不知道解决这个问题的最佳方法。我的第一次尝试可能是,尽管您可以使用整数规划或将其建模为约束满足问题。如果我们只讨论十几个变量,暴力应该是可行的。@Dokeling实际应用程序是一个手写解析器,其中每个枚举值都是一种令牌类型。(可能有50个)。不过有很多switch语句。我认识到这种优化是次要的,可能可以忽略不计,我只是对如何真正做到这一点感兴趣,因为我不知道如何做到。暴力不是一个选项,因为有50!安排枚举的方法。@Steven Stewart Gallus他们通常使用大小为O(n*m)的二维数组(n:枚举值的数量;m:状态的数量)存储状态转换表和所有生产规则的一个切换。是否保证将交叉点集放在开头会找到最佳解决方案?很容易找到将交叉点放在前面会找到次优解决方案的情况。考虑元素{a,b,c}和开关{a,b}和{a,c}。将A放在前面会产生大小为2和3的切换表,这比大小为2和2的表的最优解{B,A,C}更糟糕。你的方法不管用。我想我当时误解了这个问题。我不太确定这是明拉问题的推广。要最小化的成本函数并不完全相同。@jbaylina你是对的;相应解决方案的目标相差一个常数,该常数仅取决于实例。