content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF 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
   *
   * 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.apache.calcite.util;
  
  import org.checkerframework.checker.nullness.qual.Nullable;
  
  import java.util.Objects;
  
  import static java.util.Objects.requireNonNull;
  
  /**
   * Represents one functional dependency (Arrow) between two sets of columns,
   * where each column is identified by its ordinal index.
   *
   * <p>{@link Arrow} models the functional dependency such that the values of the
   * {@link #determinants} columns uniquely determine the values of the
   * {@link #dependents} columns. In other words, if two rows have the same values
   * for all determinant columns, they must also have the same values for all
   * dependent columns. Both {@link #determinants} and {@link #dependents} are
   * ImmutableBitSet column ordinals.
   *
   * <p>This structure supports arbitrary cardinality for both determinant and
   * dependent column sets, allowing the representation relationships:
   * <ul>
   *   <li>One-to-one: {@code {0} → {1}}
   *   <li>One-to-many: {@code {0} → {1, 2}}
   *   <li>Many-to-one: {@code {0, 1} → {2}}
   *   <li>Many-to-many: {@code {0, 1} → {2, 3}}
   * </ul>
   *
   * <p>Example:
   *
   * <blockquote>
   * <pre>
   * Table schema: [emp_id, name, dept, salary]  // ordinals: 0, 1, 2, 3
   * Arrow: {0} → {1, 2}
   * Functional dependency: emp_id → {name, dept}
   * </pre>
   * </blockquote>
   *
   * <p>This indicates that the employee ID uniquely determines both the name
   * and department attributes.
   */
  public class Arrow {
    // The set of column ordinals that are the determinants in the functional dependency.
    private final ImmutableBitSet determinants;
  
    // The set of column ordinals that are determined by the determinants.
    private final ImmutableBitSet dependents;
  
    private Arrow(ImmutableBitSet determinants, ImmutableBitSet dependents) {
      this.determinants = requireNonNull(determinants, "determinants must not be null");
      this.dependents = requireNonNull(dependents, "dependents must not be null");
    }
  
    /**
     * Create Arrow from determinant set to dependent set.
     */
    public static Arrow of(ImmutableBitSet determinants, ImmutableBitSet dependents) {
      return new Arrow(determinants, dependents);
    }
  
    /**
     * Create Arrow from single determinant to single dependent.
     */
    public static Arrow of(int determinant, int dependent) {
      return Arrow.of(ImmutableBitSet.of(determinant), ImmutableBitSet.of(dependent));
    }
  
    public ImmutableBitSet getDeterminants() {
      return determinants;
    }
  
    public ImmutableBitSet getDependents() {
      return dependents;
    }
  
    /**
     * Returns true if this Arrow is trivial (dependents ⊆ determinants).
     */
    public boolean isTrivial() {
      return determinants.contains(dependents);
    }
  
    @Override public boolean equals(@Nullable Object o) {
      if (this == o) {
        return true;
      }
      if (!(o instanceof Arrow)) {
        return false;
      }
      Arrow that = (Arrow) o;
      return determinants.equals(that.determinants)
          && dependents.equals(that.dependents);
    }
  
    @Override public int hashCode() {
      return Objects.hash(determinants, dependents);
    }
  
    @Override public String toString() {
      return determinants + " -> " + dependents;
    }
  }
  