com.cloudera.branchreduce.onezero.ImplicitEnumerationSolver.java Source code

Java tutorial

Introduction

Here is the source code for com.cloudera.branchreduce.onezero.ImplicitEnumerationSolver.java

Source

/**
 * Copyright (c) 2012, Cloudera, Inc. All Rights Reserved.
 *
 * Cloudera, Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"). You may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for
 * the specific language governing permissions and limitations under the
 * License.
 */
package com.cloudera.branchreduce.onezero;

import java.io.File;
import java.io.IOException;
import java.util.BitSet;
import java.util.List;
import java.util.Set;

import org.apache.hadoop.conf.Configuration;

import com.cloudera.branchreduce.BranchReduceContext;
import com.cloudera.branchreduce.BranchReduceJob;
import com.cloudera.branchreduce.Processor;
import com.cloudera.branchreduce.globalstate.MinimumInt;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import com.google.common.io.Files;

/**
 * TODO
 */
public class ImplicitEnumerationSolver extends Processor<PartialSolution, CurrentBestSolution> {

    public static final String LP_PROBLEM = "branchreduce.lp.problem";

    public static BranchReduceJob<PartialSolution, CurrentBestSolution> createJob(boolean runLocally, File lpFile) {
        return createJob(runLocally, lpFile, new Configuration());
    }

    public static BranchReduceJob<PartialSolution, CurrentBestSolution> createJob(boolean runLocally, File lpFile,
            Configuration conf) {
        BranchReduceJob<PartialSolution, CurrentBestSolution> job = new BranchReduceJob<PartialSolution, CurrentBestSolution>(
                runLocally, conf);

        job.setProcessorClass(ImplicitEnumerationSolver.class);
        job.setTaskClass(PartialSolution.class);
        job.setGlobalStateClass(CurrentBestSolution.class);
        job.setJarByClass(ImplicitEnumerationSolver.class);

        try {
            String problem = Joiner.on("\n").join(Files.readLines(lpFile, Charsets.UTF_8));
            job.getConfiguration().set(LP_PROBLEM, problem);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return job;
    }

    private Expression objective;
    private BitSet coefSigns;
    private int numVariables;
    private List<Constraint> constraints;

    @Override
    public void initialize(BranchReduceContext<PartialSolution, CurrentBestSolution> context) {
        if (objective == null) {
            Configuration conf = context.getConfiguration();
            String lpProblem = conf.get(LP_PROBLEM, "");
            if (lpProblem.isEmpty()) {
                throw new IllegalArgumentException("No branchreduce.lp.problem config value specified, exiting");
            }
            SimplifiedLpParser parser = new SimplifiedLpParser(lpProblem);
            parser.parse();
            init(parser.getObjective(), parser.getConstraints());
        }
    }

    private void init(Expression objective, List<Constraint> constraints) {
        this.objective = objective;
        this.numVariables = objective.getNumVariables();
        this.constraints = constraints;
        this.coefSigns = objective.coefSigns();
        this.coefSigns.flip(0, numVariables);
    }

    @Override
    public void execute(PartialSolution solution,
            BranchReduceContext<PartialSolution, CurrentBestSolution> context) {
        // First, see if the completion is feasible.
        int fixLimit = solution.getFixLimit();
        BitSet completion = fixLimit < numVariables ? coefSigns.get(fixLimit, numVariables) : new BitSet();
        boolean feasible = true;
        int[] deltas = new int[constraints.size()];
        for (int i = 0; i < deltas.length; i++) {
            deltas[i] = constraints.get(i).delta(solution, completion);
            if (deltas[i] < 0) {
                feasible = false;
            }
        }

        int bestPossible = objective.eval(solution, completion);
        int currentBestValue = context.readGlobalState().getValue();
        if (feasible) {
            if (bestPossible < currentBestValue) {
                // Awesome, the best possible solution is feasible. We've fathomed the problem.
                context.updateGlobalState(new CurrentBestSolution(solution.complete(completion, numVariables),
                        new MinimumInt(bestPossible)));
            }
            return;
        }

        // Okay, so maybe that didn't work. What's next? Well, we should check to see if _any_
        // feasible solution would be better than the current best solution.
        int[] dlimit = new int[deltas.length];
        for (int i = fixLimit; i < numVariables; i++) {
            boolean completes = completion.get(i - fixLimit);
            int baseValue = bestPossible + (completes ? -objective.getCoef(i) : objective.getCoef(i));
            if (baseValue < currentBestValue) {
                // Okay, so it can improve the objective.
                for (int j = 0; j < deltas.length; j++) {
                    if (deltas[j] < 0) {
                        int c = constraints.get(j).getCoef(i);
                        if ((c < 0 && !completes) || (c > 0 && completes)) {
                            dlimit[j] += Math.abs(c);
                        }
                    }
                }
            }
        }

        for (int j = 0; j < deltas.length; j++) {
            if (dlimit[j] + deltas[j] < 0) {
                // Can't possibly satisfy the constraints-- fathom it.
                return;
            }
        }

        // Otherwise, keep going down the tree.
        context.emit(solution.getNext(false), solution.getNext(true));
    }
}