Skip to content

Commit

Permalink
Commander encoding for AMO constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
czengler committed May 12, 2016
1 parent e43723b commit 7384fe9
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,20 @@ public final class CCAMOBinary extends CCAtMostOne {
*/
public CCAMOBinary(final FormulaFactory f) {
this.f = f;
result = new ArrayList<>();
this.result = new ArrayList<>();
}

@Override
public ImmutableFormulaList build(final Variable... vars) {
result.clear();
this.result.clear();
if (vars.length <= 0)
return new ImmutableFormulaList(FType.AND, result);
return new ImmutableFormulaList(FType.AND, this.result);
final int numberOfBits = (int) Math.ceil((Math.log(vars.length) / Math.log(2)));
final int twoPowNBits = (int) Math.pow(2, numberOfBits);
final int k = (twoPowNBits - vars.length) * 2;
final Variable[] bits = new Variable[numberOfBits];
for (int i = 0; i < numberOfBits; i++)
bits[i] = f.newCCVariable();
bits[i] = this.f.newCCVariable();
int gray_code;
int next_gray;
int i = 0;
Expand All @@ -103,9 +103,9 @@ public ImmutableFormulaList build(final Variable... vars) {
for (int j = 0; j < numberOfBits; ++j)
if ((gray_code & (1 << j)) == (next_gray & (1 << j))) {
if ((gray_code & (1 << j)) != 0)
result.add(f.clause(vars[index].negate(), bits[j]));
this.result.add(this.f.clause(vars[index].negate(), bits[j]));
else
result.add(f.clause(vars[index].negate(), bits[j].negate()));
this.result.add(this.f.clause(vars[index].negate(), bits[j].negate()));
}
i++;
}
Expand All @@ -114,12 +114,12 @@ public ImmutableFormulaList build(final Variable... vars) {
gray_code = i ^ (i >> 1);
for (int j = 0; j < numberOfBits; ++j)
if ((gray_code & (1 << j)) != 0)
result.add(f.clause(vars[index].negate(), bits[j]));
this.result.add(this.f.clause(vars[index].negate(), bits[j]));
else
result.add(f.clause(vars[index].negate(), bits[j].negate()));
this.result.add(this.f.clause(vars[index].negate(), bits[j].negate()));
i++;
}
return new ImmutableFormulaList(FType.AND, result);
return new ImmutableFormulaList(FType.AND, this.result);
}

@Override
Expand Down
170 changes: 170 additions & 0 deletions src/main/java/org/logicng/cardinalityconstraints/CCAMOCommander.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
///////////////////////////////////////////////////////////////////////////
// __ _ _ ________ //
// / / ____ ____ _(_)____/ | / / ____/ //
// / / / __ \/ __ `/ / ___/ |/ / / __ //
// / /___/ /_/ / /_/ / / /__/ /| / /_/ / //
// /_____/\____/\__, /_/\___/_/ |_/\____/ //
// /____/ //
// //
// The Next Generation Logic Library //
// //
///////////////////////////////////////////////////////////////////////////
// //
// Copyright 2015-2016 Christoph Zengler //
// //
// 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. //
// //
///////////////////////////////////////////////////////////////////////////

/**
* PBLib -- Copyright (c) 2012-2013 Peter Steinke
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package org.logicng.cardinalityconstraints;

import org.logicng.collections.ImmutableFormulaList;
import org.logicng.collections.LNGVector;
import org.logicng.formulas.FType;
import org.logicng.formulas.Formula;
import org.logicng.formulas.FormulaFactory;
import org.logicng.formulas.Literal;
import org.logicng.formulas.Variable;

import java.util.ArrayList;
import java.util.List;

/**
* Encodes that at most one variable is assigned value true. Uses the commander encoding due to Klieber & Kwon.
* @version 1.1
* @since 1.1
*/
public final class CCAMOCommander extends CCAtMostOne {

private final FormulaFactory f;
private List<Formula> result;
private int k;
private LNGVector<Literal> literals;
private LNGVector<Literal> nextLiterals;
private LNGVector<Literal> currentLiterals;

/**
* Constructs the commander AMO encoder.
* @param f the formula factory
* @param k the group size for the encoding
*/
public CCAMOCommander(final FormulaFactory f, int k) {
this.f = f;
this.k = k;
this.result = new ArrayList<>();
this.literals = new LNGVector<>();
this.nextLiterals = new LNGVector<>();
this.currentLiterals = new LNGVector<>();
}

/**
* Constructs the commander AMO encoder.
* @param f the formula factory
*/
public CCAMOCommander(final FormulaFactory f) {
this(f, 3);
}

@Override
public ImmutableFormulaList build(final Variable... vars) {
this.result.clear();
if (vars.length <= 0)
return new ImmutableFormulaList(FType.AND, this.result);
this.currentLiterals.clear();
this.nextLiterals.clear();
for (final Variable var : vars)
this.currentLiterals.push(var);
this.encodeRecursive();
return new ImmutableFormulaList(FType.AND, this.result);
}

/**
* Internal recursive encoding.
*/
private void encodeRecursive() {
boolean isExactlyOne = false;
while (this.currentLiterals.size() > this.k) {
this.literals.clear();
this.nextLiterals.clear();
for (int i = 0; i < this.currentLiterals.size(); i++) {
this.literals.push(this.currentLiterals.get(i));
if (i % this.k == this.k - 1 || i == this.currentLiterals.size() - 1) {
this.encodeNonRecursive(this.literals);
this.literals.push(this.f.newCCVariable());
this.nextLiterals.push(this.literals.back().negate());
if (isExactlyOne && this.literals.size() > 0)
this.result.add(this.vec2clause(this.literals));
for (int j = 0; j < this.literals.size() - 1; j++)
this.result.add(this.f.clause(this.literals.back().negate(), this.literals.get(j).negate()));
this.literals.clear();
}
}
this.currentLiterals.replaceInplace(this.nextLiterals);
isExactlyOne = true;
}
this.encodeNonRecursive(this.currentLiterals);
if (isExactlyOne && this.currentLiterals.size() > 0)
this.result.add(this.vec2clause(this.currentLiterals));
}

/**
* Internal non recursive encoding.
* @param literals the current literals
*/
private void encodeNonRecursive(final LNGVector<Literal> literals) {
if (literals.size() > 1)
for (int i = 0; i < literals.size(); i++)
for (int j = i + 1; j < literals.size(); j++)
this.result.add(this.f.clause(literals.get(i).negate(), literals.get(j).negate()));
}

/**
* Returns a clause for a vector of literals.
* @param literals the literals
* @return the clause
*/
private Formula vec2clause(final LNGVector<Literal> literals) {
final List<Literal> lits = new ArrayList<>(literals.size());
for (final Literal l : literals)
lits.add(l);
return this.f.clause(lits);
}

@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,16 @@ public final class CCAMONested extends CCAtMostOne {
*/
public CCAMONested(final FormulaFactory f) {
this.f = f;
result = new ArrayList<>();
this.result = new ArrayList<>();
}

@Override
public ImmutableFormulaList build(final Variable... vars) {
result.clear();
this.result.clear();
if (vars.length <= 0)
return new ImmutableFormulaList(FType.AND, result);
encodeIntern(new LNGVector<Literal>(vars));
return new ImmutableFormulaList(FType.AND, result);
return new ImmutableFormulaList(FType.AND, this.result);
this.encodeIntern(new LNGVector<Literal>(vars));
return new ImmutableFormulaList(FType.AND, this.result);
}

/**
Expand All @@ -98,7 +98,7 @@ private void encodeIntern(final LNGVector<Literal> vars) {
if (vars.size() <= 4)
for (int i = 0; i + 1 < vars.size(); i++)
for (int j = i + 1; j < vars.size(); j++)
result.add(f.clause(vars.get(i).negate(), vars.get(j).negate()));
this.result.add(this.f.clause(vars.get(i).negate(), vars.get(j).negate()));
else {
final LNGVector<Literal> l1 = new LNGVector<>(vars.size() / 2);
final LNGVector<Literal> l2 = new LNGVector<>(vars.size() / 2);
Expand All @@ -107,11 +107,11 @@ private void encodeIntern(final LNGVector<Literal> vars) {
l1.push(vars.get(i));
for (; i < vars.size(); ++i)
l2.push(vars.get(i));
final Variable newVariable = f.newCCVariable();
final Variable newVariable = this.f.newCCVariable();
l1.push(newVariable);
l2.push(newVariable.negate());
encodeIntern(l1);
encodeIntern(l2);
this.encodeIntern(l1);
this.encodeIntern(l2);
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/test/java/org/logicng/cardinalityconstraints/CCAMOTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public class CCAMOTest {
private static final CCAtMostOne product = new CCAMOProduct(f);
private static final CCAtMostOne binary = new CCAMOBinary(f);
private static final CCAtMostOne nested = new CCAMONested(f);
private static final CCAtMostOne commander3 = new CCAMOCommander(f);
private static final CCAtMostOne commander7 = new CCAMOCommander(f, 7);


@Test
Expand All @@ -64,6 +66,8 @@ public void testCC0() {
Assert.assertTrue(product.build(new LinkedList<Variable>()).empty());
Assert.assertTrue(binary.build(new LinkedList<Variable>()).empty());
Assert.assertTrue(nested.build(new LinkedList<Variable>()).empty());
Assert.assertTrue(commander3.build(new LinkedList<Variable>()).empty());
Assert.assertTrue(commander7.build(new LinkedList<Variable>()).empty());
}

@Test
Expand All @@ -74,6 +78,8 @@ public void testCC1() {
Assert.assertTrue(product.build(vars).empty());
Assert.assertTrue(binary.build(vars).empty());
Assert.assertTrue(nested.build(vars).empty());
Assert.assertTrue(commander3.build(vars).empty());
Assert.assertTrue(commander7.build(vars).empty());
}

@Test
Expand Down Expand Up @@ -121,6 +127,24 @@ public void testNested() {
testCC(500, nested);
}

@Test
public void testCommander3() {
testCC(2, commander3);
testCC(10, commander3);
testCC(100, commander3);
testCC(250, commander3);
testCC(500, commander3);
}

@Test
public void testCommander7() {
testCC(2, commander7);
testCC(10, commander7);
testCC(100, commander7);
testCC(250, commander7);
testCC(500, commander7);
}

private void testCC(int numLits, final CCAtMostOne encoder) {
final List<Variable> lits = new LinkedList<>();
final Variable[] problemLits = new Variable[numLits];
Expand Down

0 comments on commit 7384fe9

Please sign in to comment.