// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static boolean canTranspose(ITabularFormula formula, ITier tier, int varName1, int varName2)
// {
//     ITier otherTier = ensureTheOnlyTierWithVariableExistsAndGetTheTier(formula, varName1);
//         
//     if (otherTier != tier)
//     {
//         return false;
//     }
//     otherTier = ensureTheOnlyTierWithVariableExistsAndGetTheTier(formula, varName2);
//     if (otherTier != tier)
//     {
//         return false;
//     }
//     return true;
// }
// 
// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static boolean endsWith(ITabularFormula formula, int varName1, int varName2)
// {
//     IPermutation permutation = formula.getPermutation();
//         
//     int permutationSize = permutation.size();
//         
//     return permutation.get(permutationSize - 2) == varName1
//         && permutation.get(permutationSize - 1) == varName2;
// }
// 
// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static ITier ensureTheOnlyTierWithVariableExistsAndGetTheTier(ITabularFormula formula, int varName)
// {
//     ObjectArrayList tiers = formula.findTiersFor(varName);
//     if (tiers == null)
//     {
//         return null;
//     }
//     if (tiers.size() == 1)
//     {
//         return (ITier) tiers.get(0);
//     }
//     return null;
// }
// 
// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static ITier ensureTheOnlyTierWithVariablesExistsAndGetTheTier(ITabularFormula formula, int varName1, int varName2)
// {
//     ObjectArrayList tiers = formula.findTiersFor(varName1, varName2);
//     if (tiers == null)
//     {
//         return null;
//     }
//     if (tiers.size() == 1)
//     {
//         return (ITier) tiers.get(0);
//     }
//     return null;
// }
// 
// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static boolean startsWith(ITabularFormula formula, int varName)
// {
//     return formula.getPermutation().get(0) == varName;
// }


import static com.anjlab.sat3.Join2BetweenTiers.canTranspose;
import static com.anjlab.sat3.JoinMethods.endsWith;
import static com.anjlab.sat3.JoinMethods.ensureTheOnlyTierWithVariableExistsAndGetTheTier;
import static com.anjlab.sat3.JoinMethods.ensureTheOnlyTierWithVariablesExistsAndGetTheTier;
import static com.anjlab.sat3.JoinMethods.startsWith;
import cern.colt.list.ObjectArrayList;

            return false;
        }
        
        return tryJoin2Left1Right(formula, tier, a, b, c)
            || tryJoin2Left1Right(formula, tier, a, c, b)
            || tryJoin2Left1Right(formula, tier, b, a, c)
            || tryJoin2Left1Right(formula, tier, b, c, a)
            || tryJoin2Left1Right(formula, tier, c, a, b)
            || tryJoin2Left1Right(formula, tier, c, b, a)
            
            || tryJoin1Left2Right(formula, tier, a, b, c)
            || tryJoin1Left2Right(formula, tier, a, c, b)
            || tryJoin1Left2Right(formula, tier, b, a, c)
            || tryJoin1Left2Right(formula, tier, b, c, a)
            || tryJoin1Left2Right(formula, tier, c, a, b)
            || tryJoin1Left2Right(formula, tier, c, b, a);
    }

}

final class Join2BetweenTiers implements IJoinMethod
{
    public static boolean tryJoin2BetweenTiers(ITabularFormula formula, ITier tier, int left, int right, int middle)
    {
        int leftIndex = formula.getPermutation().indexOf(left);
        int middleIndex = formula.getPermutation().indexOf(middle);
        int rightIndex = formula.getPermutation().indexOf(right);
        
        if (leftIndex > rightIndex || leftIndex < 0 || rightIndex < 0 || middleIndex >= 0)
        {

// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static boolean canTranspose(ITabularFormula formula, ITier tier, int varName1, int varName2)
// {
//     ITier otherTier = ensureTheOnlyTierWithVariableExistsAndGetTheTier(formula, varName1);
//         
//     if (otherTier != tier)
//     {
//         return false;
//     }
//     otherTier = ensureTheOnlyTierWithVariableExistsAndGetTheTier(formula, varName2);
//     if (otherTier != tier)
//     {
//         return false;
//     }
//     return true;
// }
// 
// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static boolean endsWith(ITabularFormula formula, int varName1, int varName2)
// {
//     IPermutation permutation = formula.getPermutation();
//         
//     int permutationSize = permutation.size();
//         
//     return permutation.get(permutationSize - 2) == varName1
//         && permutation.get(permutationSize - 1) == varName2;
// }
// 
// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static ITier ensureTheOnlyTierWithVariableExistsAndGetTheTier(ITabularFormula formula, int varName)
// {
//     ObjectArrayList tiers = formula.findTiersFor(varName);
//     if (tiers == null)
//     {
//         return null;
//     }
//     if (tiers.size() == 1)
//     {
//         return (ITier) tiers.get(0);
//     }
//     return null;
// }
// 
// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static ITier ensureTheOnlyTierWithVariablesExistsAndGetTheTier(ITabularFormula formula, int varName1, int varName2)
// {
//     ObjectArrayList tiers = formula.findTiersFor(varName1, varName2);
//     if (tiers == null)
//     {
//         return null;
//     }
//     if (tiers.size() == 1)
//     {
//         return (ITier) tiers.get(0);
//     }
//     return null;
// }
// 
// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
// public static boolean startsWith(ITabularFormula formula, int varName)
// {
//     return formula.getPermutation().get(0) == varName;
// }


// Path: 3-sat-core/src/main/java/com/anjlab/sat3/JoinMethods.java
import static com.anjlab.sat3.Join2BetweenTiers.canTranspose;
import static com.anjlab.sat3.JoinMethods.endsWith;
import static com.anjlab.sat3.JoinMethods.ensureTheOnlyTierWithVariableExistsAndGetTheTier;
import static com.anjlab.sat3.JoinMethods.ensureTheOnlyTierWithVariablesExistsAndGetTheTier;
import static com.anjlab.sat3.JoinMethods.startsWith;
import cern.colt.list.ObjectArrayList;

            return false;
        }
        
        return tryJoin2Left1Right(formula, tier, a, b, c)
            || tryJoin2Left1Right(formula, tier, a, c, b)
            || tryJoin2Left1Right(formula, tier, b, a, c)
            || tryJoin2Left1Right(formula, tier, b, c, a)
            || tryJoin2Left1Right(formula, tier, c, a, b)
            || tryJoin2Left1Right(formula, tier, c, b, a)
            
            || tryJoin1Left2Right(formula, tier, a, b, c)
            || tryJoin1Left2Right(formula, tier, a, c, b)
            || tryJoin1Left2Right(formula, tier, b, a, c)
            || tryJoin1Left2Right(formula, tier, b, c, a)
            || tryJoin1Left2Right(formula, tier, c, a, b)
            || tryJoin1Left2Right(formula, tier, c, b, a);
    }

}

final class Join2BetweenTiers implements IJoinMethod
{
    public static boolean tryJoin2BetweenTiers(ITabularFormula formula, ITier tier, int left, int right, int middle)
    {
        int leftIndex = formula.getPermutation().indexOf(left);
        int middleIndex = formula.getPermutation().indexOf(middle);
        int rightIndex = formula.getPermutation().indexOf(right);
        
        if (leftIndex > rightIndex || leftIndex < 0 || rightIndex < 0 || middleIndex >= 0)
        {

            return false;
