code: ///////////////////////////////////////////////////////////////////////////
  //                   __                _      _   ________               //
  //                  / /   ____  ____ _(_)____/ | / / ____/               //
  //                 / /   / __ \/ __ `/ / ___/  |/ / / __                 //
  //                / /___/ /_/ / /_/ / / /__/ /|  / /_/ /                 //
  //               /_____/\____/\__, /_/\___/_/ |_/\____/                  //
  //                           /____/                                      //
  //                                                                       //
  //               The Next Generation Logic Library                       //
  //                                                                       //
  ///////////////////////////////////////////////////////////////////////////
  //                                                                       //
  //  Copyright 2015-20xx 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.                       //
  //                                                                       //
  ///////////////////////////////////////////////////////////////////////////
  
  package org.logicng.cardinalityconstraints;
  
  import org.logicng.configurations.Configuration;
  import org.logicng.configurations.ConfigurationType;
  
  /**
   * The configuration for a cardinality constraint encoder.
   * @version 2.0.0
   * @since 1.1
   */
  public final class CCConfig extends Configuration {
  
      /**
       * The encoder for at-most-one and exactly-one constraints.
       */
      public enum AMO_ENCODER {
          PURE, LADDER, PRODUCT, NESTED, COMMANDER, BINARY, BIMANDER, BEST
      }
  
      /**
       * The encoder for at-most-k constraints.
       */
      public enum AMK_ENCODER {
          TOTALIZER, MODULAR_TOTALIZER, CARDINALITY_NETWORK, BEST
      }
  
      /**
       * The encoder for at-least-k constraints.
       */
      public enum ALK_ENCODER {
          TOTALIZER, MODULAR_TOTALIZER, CARDINALITY_NETWORK, BEST
      }
  
      /**
       * The encoder for exactly-k constraints.
       */
      public enum EXK_ENCODER {
          TOTALIZER, CARDINALITY_NETWORK, BEST
      }
  
      /**
       * The group size for the Bimander encoding.
       */
      public enum BIMANDER_GROUP_SIZE {
          HALF, SQRT, FIXED
      }
  
      final AMO_ENCODER amoEncoder;
      final AMK_ENCODER amkEncoder;
      final ALK_ENCODER alkEncoder;
      final EXK_ENCODER exkEncoder;
      final BIMANDER_GROUP_SIZE bimanderGroupSize;
      final int bimanderFixedGroupSize;
      final int nestingGroupSize;
      final int productRecursiveBound;
      final int commanderGroupSize;
  
      /**
       * Returns a new builder for the configuration.
       * @return the builder
       */
      public static Builder builder() {
          return new Builder();
      }
  
      /**
       * Constructs a new cardinality constraint encoder configuration from a given builder.
       * @param builder the builder
       */
      private CCConfig(final Builder builder) {
          super(ConfigurationType.CC_ENCODER);
          this.amoEncoder = builder.amoEncoder;
          this.amkEncoder = builder.amkEncoder;
          this.alkEncoder = builder.alkEncoder;
          this.exkEncoder = builder.exkEncoder;
          this.bimanderGroupSize = builder.bimanderGroupSize;
          this.bimanderFixedGroupSize = builder.bimanderFixedGroupSize;
          this.nestingGroupSize = builder.nestingGroupSize;
          this.productRecursiveBound = builder.productRecursiveBound;
          this.commanderGroupSize = builder.commanderGroupSize;
      }
  
      @Override
      public String toString() {
          final StringBuilder sb = new StringBuilder("CCConfig{").append(System.lineSeparator());
          sb.append("amoEncoder=").append(this.amoEncoder).append(System.lineSeparator());
          sb.append("amkEncoder=").append(this.amkEncoder).append(System.lineSeparator());
          sb.append("alkEncoder=").append(this.alkEncoder).append(System.lineSeparator());
          sb.append("exkEncoder=").append(this.exkEncoder).append(System.lineSeparator());
          sb.append("bimanderGroupSize=").append(this.bimanderGroupSize).append(System.lineSeparator());
          sb.append("bimanderFixedGroupSize=").append(this.bimanderFixedGroupSize).append(System.lineSeparator());
          sb.append("nestingGroupSize=").append(this.nestingGroupSize).append(System.lineSeparator());
          sb.append("productRecursiveBound=").append(this.productRecursiveBound).append(System.lineSeparator());
          sb.append("commanderGroupSize=").append(this.commanderGroupSize).append(System.lineSeparator());
          sb.append("}").append(System.lineSeparator());
          return sb.toString();
      }
  
      /**
       * The builder for a cardinality constraint encoder configuration.
       */
      public static class Builder {
          private AMO_ENCODER amoEncoder = AMO_ENCODER.BEST;
          private AMK_ENCODER amkEncoder = AMK_ENCODER.BEST;
          private ALK_ENCODER alkEncoder = ALK_ENCODER.BEST;
          private EXK_ENCODER exkEncoder = EXK_ENCODER.BEST;
          private BIMANDER_GROUP_SIZE bimanderGroupSize = BIMANDER_GROUP_SIZE.SQRT;
          private int bimanderFixedGroupSize = 3;
          private int nestingGroupSize = 4;
          private int productRecursiveBound = 20;
          private int commanderGroupSize = 3;
  
          private Builder() {
              // Initialize only via factory
          }
  
          /**
           * Sets the encoder for at-most-one constraints. The default value is {@code BEST}.
           * @param amoEncoder the at-most-one encoder
           * @return the builder
           */
          public Builder amoEncoding(final AMO_ENCODER amoEncoder) {
              this.amoEncoder = amoEncoder;
              return this;
          }
  
          /**
           * Sets the encoder for at-most-k constraints. The default value is {@code BEST}.
           * @param amkEncoder the at-most-k encoder
           * @return the builder
           */
          public Builder amkEncoding(final AMK_ENCODER amkEncoder) {
              this.amkEncoder = amkEncoder;
              return this;
          }
  
          /**
           * Sets the encoder for at-least-k constraints. The default value is {@code BEST}.
           * @param alkEncoder the at-least-k encoder
           * @return the builder
           */
          public Builder alkEncoding(final ALK_ENCODER alkEncoder) {
              this.alkEncoder = alkEncoder;
              return this;
          }
  
          /**
           * Sets the encoder for exactly-k constraints. The default value is {@code BEST}.
           * @param exkEncoder the exactly-k encoder
           * @return the builder
           */
          public Builder exkEncoding(final EXK_ENCODER exkEncoder) {
              this.exkEncoder = exkEncoder;
              return this;
          }
  
          /**
           * Sets the group size for the bimander encoding. The default value is {@code SQRT}.
           * @param bimanderGroupSize the bimander encoding group size
           * @return the builder
           */
          public Builder bimanderGroupSize(final BIMANDER_GROUP_SIZE bimanderGroupSize) {
              this.bimanderGroupSize = bimanderGroupSize;
              return this;
          }
  
          /**
           * Sets the fixed group size for the bimander encoding. The default value is 3.  This setting is only used if
           * the bimander group size is set to {@code FIXED}.
           * @param bimanderFixedGroupSize the bimander encoding fixed group size
           * @return the builder
           */
          public Builder bimanderFixedGroupSize(final int bimanderFixedGroupSize) {
              this.bimanderFixedGroupSize = bimanderFixedGroupSize;
              return this;
          }
  
          /**
           * Sets the group size for the nesting encoding. The default value is 4.
           * @param nestingGroupSize the group size for the nesting encoding
           * @return the builder
           */
          public Builder nestingGroupSize(final int nestingGroupSize) {
              this.nestingGroupSize = nestingGroupSize;
              return this;
          }
  
          /**
           * Sets the recursive bound for the product encoding. The default value is 20.
           * @param productRecursiveBound the recursive bound for the product encoding
           * @return the builder
           */
          public Builder productRecursiveBound(final int productRecursiveBound) {
              this.productRecursiveBound = productRecursiveBound;
              return this;
          }
  
          /**
           * Sets the group size for the nesting encoding. The default value is 4.
           * @param commanderGroupSize the group size for the nesting encoding
           * @return the builder
           */
          public Builder commanderGroupSize(final int commanderGroupSize) {
              this.commanderGroupSize = commanderGroupSize;
              return this;
          }
  
          /**
           * Builds the cardinality constraint encoder configuration.
           * @return the configuration
           */
          public CCConfig build() {
              return new CCConfig(this);
          }
      }
  }
  