public Grammar mergeStates(boolean[][][] mergeThesePairs,double[][] mergeWeights){
  if (logarithmMode) {
    throw new Error("Do not merge grammars in logarithm mode!");
  }
  short[] newNumSubStates=new short[numSubStates.length];
  short[][] mapping=new short[numSubStates.length][];
  short[][][] partners=new short[numSubStates.length][][];
  calculateMergeArrays(mergeThesePairs,newNumSubStates,mapping,partners,numSubStates);
  Grammar grammar=new Grammar(newNumSubStates,findClosedPaths,smoother,this,threshold);
  for (  BinaryRule oldRule : binaryRuleMap.keySet()) {
    short pS=oldRule.getParentState(), lcS=oldRule.getLeftChildState(), rcS=oldRule.getRightChildState();
    double[][][] oldScores=oldRule.getScores2();
    double[][][] newScores=new double[newNumSubStates[lcS]][newNumSubStates[rcS]][newNumSubStates[pS]];
    for (int i=0; i < numSubStates[pS]; i++) {
      if (partners[pS][i][0] == i) {
        int parentSplit=partners[pS][i].length;
        for (int j=0; j < numSubStates[lcS]; j++) {
          if (partners[lcS][j][0] == j) {
            int leftSplit=partners[lcS][j].length;
            for (int k=0; k < (numSubStates[rcS]); k++) {
              if (partners[rcS][k][0] == k) {
                int rightSplit=partners[rcS][k].length;
                double[][][] scores=new double[leftSplit][rightSplit][parentSplit];
                for (int js=0; js < leftSplit; js++) {
                  for (int ks=0; ks < rightSplit; ks++) {
                    if (oldScores[partners[lcS][j][js]][partners[rcS][k][ks]] == null)                     continue;
                    for (int is=0; is < parentSplit; is++) {
                      scores[js][ks][is]=oldScores[partners[lcS][j][js]][partners[rcS][k][ks]][partners[pS][i][is]];
                    }
                  }
                }
                if (rightSplit == 2) {
                  for (int is=0; is < parentSplit; is++) {
                    for (int js=0; js < leftSplit; js++) {
                      scores[js][0][is]=scores[js][1][is]=scores[js][0][is] + scores[js][1][is];
                    }
                  }
                }
                if (leftSplit == 2) {
                  for (int is=0; is < parentSplit; is++) {
                    for (int ks=0; ks < rightSplit; ks++) {
                      scores[0][ks][is]=scores[1][ks][is]=scores[0][ks][is] + scores[1][ks][is];
                    }
                  }
                }
                if (parentSplit == 2) {
                  for (int js=0; js < leftSplit; js++) {
                    for (int ks=0; ks < rightSplit; ks++) {
                      double mergeWeightSum=mergeWeights[pS][partners[pS][i][0]] + mergeWeights[pS][partners[pS][i][1]];
                      if (SloppyMath.isDangerous(mergeWeightSum))                       mergeWeightSum=1;
                      scores[js][ks][0]=scores[js][ks][1]=((scores[js][ks][0] * mergeWeights[pS][partners[pS][i][0]]) + (scores[js][ks][1] * mergeWeights[pS][partners[pS][i][1]])) / mergeWeightSum;
                    }
                  }
                }
                for (int is=0; is < parentSplit; is++) {
                  for (int js=0; js < leftSplit; js++) {
                    for (int ks=0; ks < rightSplit; ks++) {
                      newScores[mapping[lcS][partners[lcS][j][js]]][mapping[rcS][partners[rcS][k][ks]]][mapping[pS][partners[pS][i][is]]]=scores[js][ks][is];
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    BinaryRule newRule=new BinaryRule(oldRule);
    newRule.setScores2(newScores);
    grammar.addBinary(newRule);
  }
  for (  UnaryRule oldRule : unaryRuleMap.keySet()) {
    short pS=oldRule.getParentState(), cS=oldRule.getChildState();
    double[][] newScores=new double[newNumSubStates[cS]][newNumSubStates[pS]];
    double[][] oldScores=oldRule.getScores2();
    boolean allZero=true;
    for (int i=0; i < numSubStates[pS]; i++) {
      if (partners[pS][i][0] == i) {
        int parentSplit=partners[pS][i].length;
        for (int j=0; j < numSubStates[cS]; j++) {
          if (partners[cS][j][0] == j) {
            int childSplit=partners[cS][j].length;
            double[][] scores=new double[childSplit][parentSplit];
            for (int js=0; js < childSplit; js++) {
              if (oldScores[partners[cS][j][js]] == null)               continue;
              for (int is=0; is < parentSplit; is++) {
                scores[js][is]=oldScores[partners[cS][j][js]][partners[pS][i][is]];
              }
            }
            if (childSplit == 2) {
              for (int is=0; is < parentSplit; is++) {
                scores[0][is]=scores[1][is]=scores[0][is] + scores[1][is];
              }
            }
            if (parentSplit == 2) {
              for (int js=0; js < childSplit; js++) {
                double mergeWeightSum=mergeWeights[pS][partners[pS][i][0]] + mergeWeights[pS][partners[pS][i][1]];
                if (SloppyMath.isDangerous(mergeWeightSum))                 mergeWeightSum=1;
                scores[js][0]=scores[js][1]=((scores[js][0] * mergeWeights[pS][partners[pS][i][0]]) + (scores[js][1] * mergeWeights[pS][partners[pS][i][1]])) / mergeWeightSum;
              }
            }
            for (int is=0; is < parentSplit; is++) {
              for (int js=0; js < childSplit; js++) {
                newScores[mapping[cS][partners[cS][j][js]]][mapping[pS][partners[pS][i][is]]]=scores[js][is];
                allZero=allZero && (scores[js][is] == 0);
              }
            }
          }
        }
      }
    }
    UnaryRule newRule=new UnaryRule(oldRule);
    newRule.setScores2(newScores);
    grammar.addUnary(newRule);
  }
  grammar.pruneSplitTree(partners,mapping);
  grammar.isGrammarTag=this.isGrammarTag;
  grammar.closedSumRulesWithParent=grammar.closedViterbiRulesWithParent=grammar.unaryRulesWithParent;
  grammar.closedSumRulesWithChild=grammar.closedViterbiRulesWithChild=grammar.unaryRulesWithC;
  return grammar;
}

public Grammar mergeStates ( boolean [ ] [ ] [ ] mergeThesePairs , double [ ] [ ] mergeWeights ) { if ( logarithmMode ) { throw new Error ( "Do not merge grammars in logarithm mode!" ) ; } short [ ] newNumSubStates = new short [ numSubStates . length ] ; short [ ] [ ] mapping = new short [ numSubStates . length ] [ ] ; short [ ] [ ] [ ] partners = new short [ numSubStates . length ] [ ] [ ] ; calculateMergeArrays ( mergeThesePairs , newNumSubStates , mapping , partners , numSubStates ) ; Grammar grammar = new Grammar ( newNumSubStates , findClosedPaths , smoother , this , threshold ) ; for ( BinaryRule oldRule : binaryRuleMap . keySet ( ) ) { short pS = oldRule . getParentState ( ) , lcS = oldRule . getLeftChildState ( ) , rcS = oldRule . getRightChildState ( ) ; double [ ] [ ] [ ] oldScores = oldRule . getScores2 ( ) ; double [ ] [ ] [ ] newScores = new double [ newNumSubStates [ lcS ] ] [ newNumSubStates [ rcS ] ] [ newNumSubStates [ pS ] ] ; for ( int i = 0 ; i < numSubStates [ pS ] ; i ++ ) { if ( partners [ pS ] [ i ] [ 0 ] == i ) { int parentSplit = partners [ pS ] [ i ] . length ; for ( int j = 0 ; j < numSubStates [ lcS ] ; j ++ ) { if ( partners [ lcS ] [ j ] [ 0 ] == j ) { int leftSplit = partners [ lcS ] [ j ] . length ; for ( int k = 0 ; k < ( numSubStates [ rcS ] ) ; k ++ ) { if ( partners [ rcS ] [ k ] [ 0 ] == k ) { int rightSplit = partners [ rcS ] [ k ] . length ; double [ ] [ ] [ ] scores = new double [ leftSplit ] [ rightSplit ] [ parentSplit ] ; for ( int js = 0 ; js < leftSplit ; js ++ ) { for ( int ks = 0 ; ks < rightSplit ; ks ++ ) { if ( oldScores [ partners [ lcS ] [ j ] [ js ] ] [ partners [ rcS ] [ k ] [ ks ] ] == null ) continue ; for ( int is = 0 ; is < parentSplit ; is ++ ) { scores [ js ] [ ks ] [ is ] = oldScores [ partners [ lcS ] [ j ] [ js ] ] [ partners [ rcS ] [ k ] [ ks ] ] [ partners [ pS ] [ i ] [ is ] ] ; } } } if ( rightSplit == 2 ) { for ( int is = 0 ; is < parentSplit ; is ++ ) { for ( int js = 0 ; js < leftSplit ; js ++ ) { scores [ js ] [ 0 ] [ is ] = scores [ js ] [ 1 ] [ is ] = scores [ js ] [ 0 ] [ is ] + scores [ js ] [ 1 ] [ is ] ; } } } if ( leftSplit == 2 ) { for ( int is = 0 ; is < parentSplit ; is ++ ) { for ( int ks = 0 ; ks < rightSplit ; ks ++ ) { scores [ 0 ] [ ks ] [ is ] = scores [ 1 ] [ ks ] [ is ] = scores [ 0 ] [ ks ] [ is ] + scores [ 1 ] [ ks ] [ is ] ; } } } if ( parentSplit == 2 ) { for ( int js = 0 ; js < leftSplit ; js ++ ) { for ( int ks = 0 ; ks < rightSplit ; ks ++ ) { double mergeWeightSum = mergeWeights [ pS ] [ partners [ pS ] [ i ] [ 0 ] ] + mergeWeights [ pS ] [ partners [ pS ] [ i ] [ 1 ] ] ; if ( SloppyMath . isDangerous ( mergeWeightSum ) ) mergeWeightSum = 1 ; scores [ js ] [ ks ] [ 0 ] = scores [ js ] [ ks ] [ 1 ] = ( ( scores [ js ] [ ks ] [ 0 ] * mergeWeights [ pS ] [ partners [ pS ] [ i ] [ 0 ] ] ) + ( scores [ js ] [ ks ] [ 1 ] * mergeWeights [ pS ] [ partners [ pS ] [ i ] [ 1 ] ] ) ) / mergeWeightSum ; } } } for ( int is = 0 ; is < parentSplit ; is ++ ) { for ( int js = 0 ; js < leftSplit ; js ++ ) { for ( int ks = 0 ; ks < rightSplit ; ks ++ ) { newScores [ mapping [ lcS ] [ partners [ lcS ] [ j ] [ js ] ] ] [ mapping [ rcS ] [ partners [ rcS ] [ k ] [ ks ] ] ] [ mapping [ pS ] [ partners [ pS ] [ i ] [ is ] ] ] = scores [ js ] [ ks ] [ is ] ; } } } } } } } } } BinaryRule newRule = new BinaryRule ( oldRule ) ; newRule . setScores2 ( newScores ) ; grammar . addBinary ( newRule ) ; } for ( UnaryRule oldRule : unaryRuleMap . keySet ( ) ) { short pS = oldRule . getParentState ( ) , cS = oldRule . getChildState ( ) ; double [ ] [ ] newScores = new double [ newNumSubStates [ cS ] ] [ newNumSubStates [ pS ] ] ; double [ ] [ ] oldScores = oldRule . getScores2 ( ) ; boolean allZero = true ; for ( int i = 0 ; i < numSubStates [ pS ] ; i ++ ) { if ( partners [ pS ] [ i ] [ 0 ] == i ) { int parentSplit = partners [ pS ] [ i ] . length ; for ( int j = 0 ; j < numSubStates [ cS ] ; j ++ ) { if ( partners [ cS ] [ j ] [ 0 ] == j ) { int childSplit = partners [ cS ] [ j ] . length ; double [ ] [ ] scores = new double [ childSplit ] [ parentSplit ] ; for ( int js = 0 ; js < childSplit ; js ++ ) { if ( oldScores [ partners [ cS ] [ j ] [ js ] ] == null ) continue ; for ( int is = 0 ; is < parentSplit ; is ++ ) { scores [ js ] [ is ] = oldScores [ partners [ cS ] [ j ] [ js ] ] [ partners [ pS ] [ i ] [ is ] ] ; } } if ( childSplit == 2 ) { for ( int is = 0 ; is < parentSplit ; is ++ ) { scores [ 0 ] [ is ] = scores [ 1 ] [ is ] = scores [ 0 ] [ is ] + scores [ 1 ] [ is ] ; } } if ( parentSplit == 2 ) { for ( int js = 0 ; js < childSplit ; js ++ ) { double mergeWeightSum = mergeWeights [ pS ] [ partners [ pS ] [ i ] [ 0 ] ] + mergeWeights [ pS ] [ partners [ pS ] [ i ] [ 1 ] ] ; if ( SloppyMath . isDangerous ( mergeWeightSum ) ) mergeWeightSum = 1 ; scores [ js ] [ 0 ] = scores [ js ] [ 1 ] = ( ( scores [ js ] [ 0 ] * mergeWeights [ pS ] [ partners [ pS ] [ i ] [ 0 ] ] ) + ( scores [ js ] [ 1 ] * mergeWeights [ pS ] [ partners [ pS ] [ i ] [ 1 ] ] ) ) / mergeWeightSum ; } } for ( int is = 0 ; is < parentSplit ; is ++ ) { for ( int js = 0 ; js < childSplit ; js ++ ) { newScores [ mapping [ cS ] [ partners [ cS ] [ j ] [ js ] ] ] [ mapping [ pS ] [ partners [ pS ] [ i ] [ is ] ] ] = scores [ js ] [ is ] ; allZero = allZero && ( scores [ js ] [ is ] == 0 ) ; } } } } } } UnaryRule newRule = new UnaryRule ( oldRule ) ; newRule . setScores2 ( newScores ) ; grammar . addUnary ( newRule ) ; } grammar . pruneSplitTree ( partners , mapping ) ; grammar . isGrammarTag = this . isGrammarTag ; grammar . closedSumRulesWithParent = grammar . closedViterbiRulesWithParent = grammar . unaryRulesWithParent ; grammar . closedSumRulesWithChild = grammar . closedViterbiRulesWithChild = grammar . unaryRulesWithC ; return grammar ; }
this merges the substate pairs indicated by mergethesepairs [ state ] [ substate pair ] . it requires merge weights calculated by tallymergeweights .
