高效的Scala实现替换合并

时间:2011-11-17 19:48:57

标签: algorithm scala optimization merge substitution

假设我们有两个替换,每个替换都是一对,我们如何有效地合并它们?一个列表中的对大小通常很大(大多数是大约100,有些是5000或更大)。 更正式的定义:

  • Substitution :: = List [Pair [Term]]
  • Term :: = Variable |恒定
  • Variable :: = Int of format:0xXXXXXXXXXXXX11 //例如:v1 = 7, v2 = 11,v3 = 15,....
  • Constant :: = Int of format:0xXXXXXXXXXXXX10 //例如:c1 = 6,c2 = 10,c3 = 14,....

条件: 一对仅将变量映射到常量,或将变量映射到另一个变量。它不能将常量映射到另一个常量或变量。

注意:

  1. 例如,两个替换可能无法合并。合并清单((7,6),(11,10)和清单(7,11)/ * {v1-> c1,v2-> c2}和{v1-> v2} * /
  2. 输入替换始终有效,意味着条件在开头就成立。没有识别对。
  3. 为简单起见,任何对的左侧部分中出现的变量都不能出现在任何一对的右侧部分。对于任何两对,左边的部分总是不同的。
  4. 问题:

    1. 什么是术语的有效编码。
    2. 什么是替换的有效编码。
    3. 合并两个替换的最佳方式是什么。
    4. 谢谢!

      更新算法说明(将一对新合并p =(s,t)合并为一个列表(L))

      1. 如果在新对p中,s是常量而t是变量,则改为(v,c);
      2. 如果新对是相同的s = t,则删除并完成;
      3. 如果新对将一个常量映射到另一个常量(c1<> c2),则失败并完成;
      4. 如果替换L中的一对左侧存在t,则将其替换为该对的右侧部分;
      5. 如果s存在于一对的左侧部分,则将该对的右侧部分保存为t2并转到7;如果没有这样的一对,转到6; 6如果替换中一对的右边部分等于s,则将其替换为t;将(s,t)添加到列表L中;并完成;
      6. 如果(s,t)已经在列表L中,则返回L和DONE;
      7. 如果t和t2是常数,则失败并完成;
      8. 如果t是常数goto 10 else goto 11;
      9. 如果替换中一对的右边部分等于t2,则将其替换为t;将(t2,t)添加到列表L中;并完成;
      10. 如果替换中一对的右边部分等于t,则将其替换为t2;将(t,t2)添加到列表L中;并完成;
      11. 基本术语定义:术语可能使用其他一些数据结构。

        object Terms {
            type Term = Int
            @inline final def isV( t : Term ) = ((t & 3) == 0x3)
            @inline final def isC(t : Term) = ((t & 3) == 0x2)
        }
        object MERGEException extends Exception
        

        主Scala代码:

        final case class Subst( _data : List[ Tuple2[Int, Int] ] ) {
            type Term = Int
            type PairType = Tuple2[Term, Term]
            type ListType = List[PairType]
        
            // Find a pair in the list, which the first element matches the query t
            // Returns the second element if found; t if no match
            private final def find(t : Term, list : ListType) : Term =
                list match {
                    case List() => t
                    case h :: list2 =>
                        val cmp = h._1 - t
                        if(cmp < 0) find(t, list2)
                        else if(cmp == 0) h._2
                        else t
                }
            // Replace s for t in the substitution (right part)
            private final def replace_helper(s : Term, t : Term, list : ListType) : ListType =
                list.map( h => if(h._2 equals s) (h._1, t) else h).distinct
            // Assume: s in not in the list
            private final def add(s : Term, t : Term, list : ListType) : ListType = {
                var wlist = list
                var rlist : ListType = List.empty
                while(wlist != List.empty) {
                    val h = wlist.head
                    if(h._1 < s) {
                        rlist = rlist ::: List(h)
                        wlist = wlist.tail
                    } else
                        return rlist ::: ( (s, t) :: wlist )
                }
                return rlist ::: List( (s, t) )
            }
            private final def merge_helper(e : PairType, list : ListType) : ListType = {
                // Orient the pair of SubTerms
                def orient(s : Term, t : Term) : PairType = 
                if( Terms.isC(s) && !Terms.isC(t) ) (t, s)
                    else (s, t)
        
                // Orientation
                var (s, t) = orient(e._1, e._2)
                // Remove identical pair
                if(s equals t) return list
                // Constant
                if(Terms.isC(s) && Terms.isC(t)) throw MERGEException
        
                if(list == List.empty) return List((s, t))
        
                // If t exists in the left part of one pair, replace it by the right part of the pair
                t = find(t, list)
                if(s equals t) list
                // now t is not in the left part of any pair
        
                val t2 = find(s, list)
                if(t2 equals s) {
                    // s doesn't appear in the left part of existed elements
                    add( s, t, replace_helper(s, t, list) )
                } else {
                    // s appears in the left part of existed elements
                    if( t2 equals t ) list
                    else {
                        // s appear in the left part of existed elements
                        // then s doesn't appear in the right part of existed elements
                        // and isDirected = false
                        //merge_helper( (t, t2), list, isDirected )
                        if(Terms.isC(t) && Terms.isC(t2)) throw MERGEException
                        else if(Terms.isC(t)) {
                            add( t2, t, replace_helper(t2, t, list) )
                        }
                        else add( t, t2, replace_helper(t, t2, list) )
                    }
                }
            }
            // Merge a pair into the substitution
            final def merge( e : PairType ) : Option[Subst] = {
                try {
                    val ret = merge_helper(e, _data)
                    return Some( Subst(ret) )
                } catch {
                    case MERGEException => return None
                }
            }
            // Union a new substitution together
            final def union(s : Subst) : Option[Subst] = {
                try {
                    if(_data.isEmpty) return Some(s)
                    else if(s.isEmpty) return Some(this)
                    else {
                        var ret = _data
                        var Subst(slist) = s
                        slist.foreach( e =>
                            ret = merge_helper(e, ret) )
                        return Some( Subst(ret) )
                    }
                } catch {
                    case e => return None
                }
            }
            final def isEmpty = _data.isEmpty
        }
        

        测试代码:

        // Test case 1
        val s1 = Subst( List( (7, 6), (11, 10) ) )  // {v1->c1, v2->c2}
        val s2 = Subst( List( (7, 11) ) )  // {v1->v2}
        val s3 = s1.union(s2)  // none
        // Test case 2
        val s12 = Subst( List( (7, 6), (11, 6), (23, 19), (27, 15), (31, 35) ) ) // {v1->c1, v2->c1, v5->v4, v6->v3, v7->v8}
        val s22 = Subst( List( (11, 7), (15, 7), (19, 10) ) ) // {v2->v1, v3->v1, v4->c2}
        val s32 = s12.union(s22)  // Some( Subst( List( (7, 6), (11, 6), (15, 6), (19, 10), (23, 10), (27, 6), (31, 35) ) ) )
        

0 个答案:

没有答案