All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.simiacryptus.mindseye.art.photo.MultivariateFrameOfReference Maven / Gradle / Ivy

/*
 * Copyright (c) 2019 by Andrew Charneski.
 *
 * The author 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 com.simiacryptus.mindseye.art.photo;

import com.simiacryptus.mindseye.art.photo.affinity.ContextAffinity;
import org.ejml.simple.SimpleMatrix;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class MultivariateFrameOfReference {
  @Nullable
  public final SimpleMatrix invCov;
  public final SimpleMatrix means;
  public final SimpleMatrix rms;
  public final SimpleMatrix cov;
  public final int dimension;

  public MultivariateFrameOfReference(@Nonnull MultivariateFrameOfReference a, @Nonnull MultivariateFrameOfReference b, double mixing) {
    this(a, b, mixing, 1e-4);
  }

  public MultivariateFrameOfReference(@Nonnull MultivariateFrameOfReference a, @Nonnull MultivariateFrameOfReference b, double mixing,
                                      double epsilon) {
    means = ContextAffinity.mix(b.means, a.means, mixing);
    rms = ContextAffinity.mix(b.rms, a.rms, mixing);
    cov = ContextAffinity.mix(b.cov, a.cov, mixing);
    this.dimension = a.dimension;
    this.invCov = safeInvert(cov, epsilon);
  }

  public MultivariateFrameOfReference(@Nonnull Supplier> fn, int channels) {
    this(fn, channels, 1e-4);
  }

  public MultivariateFrameOfReference(@Nonnull Supplier> fn, int channels, double epsilon) {
    this.dimension = channels;
    means = ContextAffinity.means(fn, this.dimension);
    rms = ContextAffinity.magnitude(means, fn, channels);
    cov = ContextAffinity.covariance(means, rms, fn, channels);
    this.invCov = safeInvert(cov, epsilon);
  }

  @Nullable
  public static SimpleMatrix safeInvert(@Nonnull SimpleMatrix cov, double epsilon) {
    SimpleMatrix invCov;
    try {
      invCov = cov.plus(SimpleMatrix.identity(cov.numCols()).scale(epsilon)).invert();
    } catch (Throwable e) {
      invCov = null;
    }
    return invCov;
  }

  public double[] adjust(@Nonnull double[] pixel) {
    return IntStream.range(0, pixel.length).mapToDouble(c -> (pixel[c] - this.means.get(c)) / this.rms.get(c))
        .toArray();
  }

  public double dist(@Nonnull double[] vector) {
    final SimpleMatrix v = ContextAffinity.toMatrix(vector);
    return null == invCov ? v.dot(v) : v.dot(invCov.mult(v));
  }

  public SimpleMatrix rawCov() {
    return rms.transpose().mult(cov.mult(rms));
  }

  public double dist(@Nonnull MultivariateFrameOfReference right) {
    final SimpleMatrix sigma0 = this.rawCov();
    final SimpleMatrix sigma1 = right.rawCov();
    final SimpleMatrix sigma_ = new MultivariateFrameOfReference(this, right, 0.5).rawCov();
    final SimpleMatrix mu_diff = this.means.minus(right.means);
    final SimpleMatrix invert = safeInvert(sigma_, 1e-4);
    final double offset = null == invert ? mu_diff.dot(mu_diff) : mu_diff.dot(invert.mult(mu_diff.transpose()));
    final double volume = sigma_.determinant() / Math.sqrt(sigma0.determinant() * sigma1.determinant());
    return offset / 8 + Math.log(volume) / 2;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy