package com.airbnb.aerosolve.core.transforms;

import com.airbnb.aerosolve.core.FeatureVector;
import com.airbnb.aerosolve.core.util.Util;

import java.util.Map;

import com.typesafe.config.Config;

public class FloatCrossFloatTransform extends Transform {
  private String fieldName1;
  private double bucket;
  private double cap;
  private String fieldName2;
  private String outputName;

  @Override
  public void configure(Config config, String key) {
    fieldName1 = config.getString(key + ".field1");
    bucket = config.getDouble(key + ".bucket");
    if (config.hasPath(key + ".cap")) {
      cap = config.getDouble(key + ".cap");
    } else {
      cap = 1e10;
    }
    fieldName2 = config.getString(key + ".field2");
    outputName = config.getString(key + ".output");
  }

  @Override
  public void doTransform(FeatureVector featureVector) {
    Map<String, Map<String, Double>> floatFeatures = featureVector.floatFeatures;

    if (floatFeatures == null || floatFeatures.isEmpty()) {
      return;
    }

    Map<String, Double> map1 = floatFeatures.get(fieldName1);

    if (map1 == null || map1.isEmpty()) {
      return;
    }

    Map<String, Double> map2 = floatFeatures.get(fieldName2);

    if (map2 == null || map2.isEmpty()) {
      return;
    }

    Map<String, Double> output = Util.getOrCreateFloatFeature(outputName, floatFeatures);

    for (Map.Entry<String, Double> entry1 : map1.entrySet()) {
      String float1Key = entry1.getKey();
      Double float1Value = entry1.getValue();

      if (float1Value > cap) {
        float1Value = cap;
      }

      Double float1Quantized = LinearLogQuantizeTransform.quantize(float1Value, bucket);

      for (Map.Entry<String, Double> entry2 : map2.entrySet()) {
        String float2Key = entry2.getKey();
        Double float2Value = entry2.getValue();

        String outputKey = float1Key + "=" + float1Quantized + "^" + float2Key;

        output.put(outputKey, float2Value);
      }
    }
  }
}

package com.airbnb.aerosolve.core.transforms;

import com.airbnb.aerosolve.core.FeatureVector;
import com.airbnb.aerosolve.core.util.Util;

import java.util.Map;

import com.typesafe.config.Config;

/**
 * Takes the floats in fieldName1, quantizes them into buckets, converts them to strings, then
 * crosses them with the floats in fieldName2 and then stores the result in a new float feature
 * output specified by outputName.
 */
public class FloatCrossFloatTransform extends Transform {
  private String fieldName1;
  private double bucket;
  private double cap;
  private String fieldName2;
  private String outputName;

  @Override
  public void configure(Config config, String key) {
    fieldName1 = config.getString(key + ".field1");
    bucket = config.getDouble(key + ".bucket");
    if (config.hasPath(key + ".cap")) {
      cap = config.getDouble(key + ".cap");
    } else {
      cap = 1e10;
    }
    fieldName2 = config.getString(key + ".field2");
    outputName = config.getString(key + ".output");
  }

  @Override
  public void doTransform(FeatureVector featureVector) {
    Map<String, Map<String, Double>> floatFeatures = featureVector.floatFeatures;

    if (floatFeatures == null || floatFeatures.isEmpty()) {
      return;
    }

    Map<String, Double> map1 = floatFeatures.get(fieldName1);

    if (map1 == null || map1.isEmpty()) {
      return;
    }

    Map<String, Double> map2 = floatFeatures.get(fieldName2);

    if (map2 == null || map2.isEmpty()) {
      return;
    }

    Map<String, Double> output = Util.getOrCreateFloatFeature(outputName, floatFeatures);

    for (Map.Entry<String, Double> entry1 : map1.entrySet()) {
      String float1Key = entry1.getKey();
      Double float1Value = entry1.getValue();

      if (float1Value > cap) {
        float1Value = cap;
      }

      Double float1Quantized = LinearLogQuantizeTransform.quantize(float1Value, bucket);

      for (Map.Entry<String, Double> entry2 : map2.entrySet()) {
        String float2Key = entry2.getKey();
        Double float2Value = entry2.getValue();

        String outputKey = float1Key + "=" + float1Quantized + "^" + float2Key;

        output.put(outputKey, float2Value);
      }
    }
  }
}

Add descriptive comment to float cross float transform