/*******************************************************************************
* Copyright 2014 Felipe Takiyama
*
* Licensed 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 br.usp.poli.takiyama.acfove;
import br.usp.poli.takiyama.common.Marginal;
import br.usp.poli.takiyama.common.Parfactor;
import br.usp.poli.takiyama.common.StdMarginal.StdMarginalBuilder;
import br.usp.poli.takiyama.prv.LogicalVariable;
import br.usp.poli.takiyama.prv.Prv;
import br.usp.poli.takiyama.utils.MathUtils;
/**
* This operation eliminates a free {@link LogicalVariable} from a
* {@link Parfactor}. This is done using the Counting operation.
*/
public final class CountingConvert implements MacroOperation {
// Marginal that contains the parfactor being counted
private final Marginal marginal;
// Parfactor being counted
private final Parfactor countableParfactor;
// Logical variable being counted
private final LogicalVariable freeVariable;
// PRV that contains the free variable
private Prv prvToCount;
public CountingConvert(Marginal marginal, Parfactor countable, LogicalVariable freeVariable) {
this.marginal = marginal;
this.countableParfactor = countable;
this.freeVariable = freeVariable;
this.prvToCount = countable.factor().getVariableHaving(freeVariable);
}
@Override
public Marginal run() {
StdMarginalBuilder resultBuilder = new StdMarginalBuilder();
resultBuilder.add(marginal).remove(countableParfactor);
Parfactor counted = countableParfactor.count(freeVariable);
resultBuilder.add(counted);
return resultBuilder.build();
}
/**
* Returns the counted factor size, which is given by
* <p>
* |F| / |range(f(...A...))| *
* combination(|D(A):C| + |range(f(...A...))| - 1, |range(f(...A...))| - 1)
* </p>
* where
* <li> |F| is factor component size from parfactor being counted
* <li> |range(f(...A...))| is the size of the counted PRV range
* <li> |D(A):C| is the number of free logical variable individuals
* satisfying constraints from the parfactor being counted
*/
@Override
public int cost() {
if (countableParfactor.isCountable(freeVariable)) {
int f = countableParfactor.factor().size();
int r = prvToCount.range().size();
int h = getNumberOfHistograms();
return f / r * h;
} else {
return (int) Double.POSITIVE_INFINITY;
}
}
/**
* Returns the number of histograms created when converting the
* standard parameterized random variable to a counting formula.
*/
private int getNumberOfHistograms() {
int domain = freeVariable.numberOfIndividualsSatisfying(countableParfactor.constraints());
int range = prvToCount.range().size() - 1;
int numberOfHistograms = MathUtils.combination(domain + range, range).intValue();
return numberOfHistograms;
}
/**
* Returns zero.
*/
@Override
public int numberOfRandomVariablesEliminated() {
return 0;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("COUNTING-CONVERT").append("\n")
.append(countableParfactor).append("\n")
.append(freeVariable);
return builder.toString();
}
}