blob: 31f3898816d4dd5b2bbb1a124435e3c1fde5c3b4 [file] [log] [blame]
/*
* 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.datasketches;
import static java.lang.Math.abs;
import static java.lang.Math.exp;
import static java.lang.Math.log;
import static java.lang.Math.min;
import static java.lang.Math.pow;
import static java.lang.Math.round;
import static org.apache.datasketches.Util.powerSeriesNextDouble;
import static org.apache.datasketches.Util.pwr2SeriesNext;
import java.util.Random;
public class MonotonicPoints {
public static Random rand = new Random();
/**
* Generates a double[] of monotonic points that are uniformly spaced.
* @param x1 one endpoint
* @param x2 the other endpoint
* @param points to be returned
* @param useLog set this true if you want the sequence to be logarithmically spaced. If
* true, x1 and x2 must be greater than zero.
* @return double array
*/
public static double[] evenlySpaced(final double x1, final double x2, final int points,
final boolean useLog) {
if (points <= 0) {
throw new IllegalArgumentException("points must be > 0");
}
final double[] out = new double[points];
out[0] = x1;
if (points == 1) {
return out;
}
if (points == 2) {
out[1] = x2;
return out;
}
// 3 or more
if (useLog) {
if (x2 <= 0 || x1 <= 0) {
throw new IllegalArgumentException("x1 and x2 must be > 0.");
}
final double logMin = log(x1);
final double delta = log(x2 / x1) / (points - 1);
for (int i = 1; i < points; i++) {
out[i] = exp(mXplusY(delta, i, logMin));
}
} else { // linear
final double delta = (x2 - x1) / (points - 1);
for (int i = 1; i < points; i++) {
out[i] = mXplusY(delta, i, x1);
}
}
return out;
}
/**
* Generates a double[] of monotonic points that are uniform random spaced.
* @param x1 one endpoint
* @param x2 the other endpoint
* @param points to be returned
* @param useLog set this true if you want the sequence to be logarithmically spaced. If
* true, x1 and x2 must be greater than zero.
* @return double array
*/
public static double[] uniformRandom(final double x1, final double x2, final int points,
final boolean useLog) {
if (points <= 0) {
throw new IllegalArgumentException("points must be > 0");
}
final double[] out = new double[points];
if (useLog) {
if (x2 <= 0 || x1 <= 0) {
throw new IllegalArgumentException("x1 and x2 must be > 0.");
}
final double logX1 = log(x1);
final double delta = log(x2) - logX1;
for (int i = 0; i < points; i++) {
out[i] = exp(mXplusY(delta, rand.nextDouble(), logX1));
}
} else {
final double delta = x2 - x1;
for (int i = 0; i < points; i++) {
out[i] = mXplusY(delta, rand.nextDouble(), x1);
}
}
return out;
}
/**
* Scales a value v in the range 0 to 1 into the range min to max.
*
* @param v
* the given value of x in the range 0 to 1.
* @param min
* the minimum endpoint of the resulting range
* @param max
* the maximum endpoint of the resulting range
* @return scaled x
*/
public static double scale(final double v, final double min, final double max) {
final double delta = abs(min - max);
final double actMin = min(min, max);
return mXplusY(delta, v, actMin);
}
public static final double linXlinYline(final double slope, final double x, final double x0,
final double y0) {
return mXplusY(slope, x - x0, y0);
}
public static final double logXlogYline(final double slope, final double x, final double x0,
final double y0) {
return exp(mXplusY(slope, log(x / x0), log(y0)));
}
public static final double mXplusY(final double m, final double x, final double y) {
return m * x + y;
}
/**
* Counts the actual number of plotting points between lgStart and lgEnd assuming the given PPO
* and a logBase of 2.
* This is not a simple linear function due to points that may be skipped in the low range.
* @param lgStart Log2 of the starting value
* @param lgEnd Log2 of the ending value
* @param ppo the number of logarithmically evenly spaced points per octave.
* @return the actual number of plotting points between lgStart and lgEnd.
*/
public static final int countPoints(final int lgStart, final int lgEnd, final int ppo) {
int p = 1 << lgStart;
final int end = 1 << lgEnd;
int count = 0;
while (p <= end) {
p = pwr2SeriesNext(ppo, p);
count++;
}
return count;
}
/**
* Counts the actual number of plotting points between lgStart and lgEnd assuming the given PPO
* and a logBase of 2.
* This is not a simple linear function due to points that may be skipped in the low range.
* @param log10Start Log10 of the starting value
* @param log10End Log10 of the ending value
* @param ppb the number of logarithmically evenly spaced points per base = 10.
* @return the actual number of plotting points between lgStart and lgEnd.
*/
public static final int countLog10Points(final int log10Start, final int log10End, final int ppb) {
long p = round(pow(10, log10Start));
final long end = round(pow(10, log10End));
int count = 0;
while (p <= end) {
p = (long)powerSeriesNextDouble(ppb, p, true, 10.0);
count++;
}
return count;
}
}