Skip to content
Permalink
Browse files
GEOMETRY-126: replacing usage of commons-numbers LinearCombination wi…
…th Sum; adding VectorXD.Sum classes
  • Loading branch information
darkma773r committed Jun 22, 2021
1 parent f557766 commit 3d138dc6019eb2d18bb9d063e443e57a165ff9c6
Showing 28 changed files with 535 additions and 485 deletions.
@@ -56,7 +56,7 @@ public EnclosingBall<Vector3D> ballOnSupport(final List<Vector3D> support) {
}
final Vector3D vB = support.get(1);
if (support.size() < 3) {
return new EnclosingBall<>(Vector3D.linearCombination(0.5, vA, 0.5, vB),
return new EnclosingBall<>(vA.lerp(vB, 0.5),
0.5 * vA.distance(vB),
Arrays.asList(vA, vB));
}
@@ -41,7 +41,7 @@ public EnclosingBall<Vector2D> ballOnSupport(final List<Vector2D> support) {
}
final Vector2D vB = support.get(1);
if (support.size() < 3) {
return new EnclosingBall<>(Vector2D.linearCombination(0.5, vA, 0.5, vB),
return new EnclosingBall<>(vA.lerp(vB, 0.5),
0.5 * vA.distance(vB),
Arrays.asList(vA, vB));
}
@@ -184,10 +184,10 @@ void testRandom() {
for (int i = 0; i < 100; ++i) {
final double d = 25 * random.nextDouble();
final double refRadius = 10 * random.nextDouble();
final Vector3D refCenter = Vector3D.linearCombination(d, Vector3D.of(sr.nextVector()));
final Vector3D refCenter = Vector3D.of(sr.nextVector()).multiply(d);
final List<Vector3D> support = new ArrayList<>();
for (int j = 0; j < 5; ++j) {
support.add(Vector3D.linearCombination(1.0, refCenter, refRadius, Vector3D.of(sr.nextVector())));
support.add(Vector3D.Sum.of(refCenter).addScaled(refRadius, Vector3D.of(sr.nextVector())).get());
}

// act
@@ -119,14 +119,14 @@ void testLargeSamples() {
// define the reference sphere we want to compute
final double d = 25 * random.nextDouble();
final double refRadius = 10 * random.nextDouble();
final Vector3D refCenter = Vector3D.linearCombination(d, Vector3D.of(sr.nextVector()));
final Vector3D refCenter = Vector3D.of(sr.nextVector()).multiply(d);
// set up a large sample inside the reference sphere
final int nbPoints = random.nextInt(1000);

final List<Vector3D> points = new ArrayList<>();
for (int i = 0; i < nbPoints; ++i) {
final double r = refRadius * random.nextDouble();
points.add(Vector3D.linearCombination(1.0, refCenter, r, Vector3D.of(sr.nextVector())));
points.add(Vector3D.Sum.of(refCenter).addScaled(r, Vector3D.of(sr.nextVector())).get());
}

// act/assert
@@ -138,10 +138,10 @@ void testRandom() {
for (int i = 0; i < 500; ++i) {
final double d = 25 * random.nextDouble();
final double refRadius = 10 * random.nextDouble();
final Vector2D refCenter = Vector2D.linearCombination(d, Vector2D.of(sr.nextVector()));
final Vector2D refCenter = Vector2D.of(sr.nextVector()).multiply(d);
final List<Vector2D> support = new ArrayList<>();
for (int j = 0; j < 3; ++j) {
support.add(Vector2D.linearCombination(1.0, refCenter, refRadius, Vector2D.of(sr.nextVector())));
support.add(Vector2D.Sum.of(refCenter).addScaled(refRadius, Vector2D.of(sr.nextVector())).get());
}

// act
@@ -0,0 +1,51 @@
/*
* 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.commons.geometry.euclidean;

import java.util.function.Consumer;
import java.util.function.Supplier;

/** Class representing a sum of Euclidean vectors.
* @param <V> Vector implementation type
*/
public abstract class EuclideanVectorSum<V extends EuclideanVector<V>>
implements Supplier<V>, Consumer<V> {

/** Add a vector to this instance. This method is an alias for {@link #add(EuclideanVector)}.
* @param vec vector to add
*/
@Override
public void accept(final V vec) {
add(vec);
}

/** Add a vector to this instance.
* @param vec vector to add
* @return this instance
*/
public abstract EuclideanVectorSum<V> add(V vec);

/** Add a scaled vector to this instance. In general, the result produced by this method
* will be more accurate than if the vector was scaled first and then added directly. In other
* words, {@code sum.addScale(scale, vec)} will generally produce a better result than
* {@code sum.add(vec.multiply(scale))}.
* @param scale scale factor
* @param vec vector to scale and add
* @return this instance
*/
public abstract EuclideanVectorSum<V> addScaled(double scale, V vec);
}
@@ -18,6 +18,7 @@

import org.apache.commons.geometry.core.Vector;
import org.apache.commons.numbers.core.Norm;
import org.apache.commons.numbers.core.Sum;

/** This class consists exclusively of static vector utility methods.
*/
@@ -142,4 +143,38 @@ public static double normSq(final double x1, final double x2) {
public static double normSq(final double x1, final double x2, final double x3) {
return (x1 * x1) + (x2 * x2) + (x3 * x3);
}

/** Compute the linear combination \(a_1 b_1 + a_2 b_2 \) with high accuracy.
* @param a1 first factor of the first term
* @param b1 second factor of the first term
* @param a2 first factor of the second term
* @param b2 second factor of the seconf term
* @return linear combination.
* @see Sum
*/
public static double linearCombination(final double a1, final double b1,
final double a2, final double b2) {
return Sum.create()
.addProduct(a1, b1)
.addProduct(a2, b2).getAsDouble();
}

/** Compute the linear combination \(a_1 b_1 + a_2 b_2 + a_3 b_3 \) with high accuracy.
* @param a1 first factor of the first term
* @param b1 second factor of the first term
* @param a2 first factor of the second term
* @param b2 second factor of the seconf term
* @param a3 first factor of the third term
* @param b3 second factor of the third term
* @return linear combination.
* @see Sum
*/
public static double linearCombination(final double a1, final double b1,
final double a2, final double b2,
final double a3, final double b3) {
return Sum.create()
.addProduct(a1, b1)
.addProduct(a2, b2)
.addProduct(a3, b3).getAsDouble();
}
}
@@ -21,8 +21,8 @@

import org.apache.commons.geometry.core.internal.SimpleTupleFormat;
import org.apache.commons.geometry.euclidean.EuclideanVector;
import org.apache.commons.geometry.euclidean.EuclideanVectorSum;
import org.apache.commons.geometry.euclidean.internal.Vectors;
import org.apache.commons.numbers.core.LinearCombination;
import org.apache.commons.numbers.core.Precision;

/** This class represents vectors and points in one-dimensional Euclidean space.
@@ -121,7 +121,9 @@ public Unit directionTo(final Vector1D v) {
/** {@inheritDoc} */
@Override
public Vector1D lerp(final Vector1D p, final double t) {
return linearCombination(1.0 - t, this, t, p);
return Sum.create()
.addScaled(1.0 - t, this)
.addScaled(t, p).get();
}

/** {@inheritDoc} */
@@ -320,86 +322,6 @@ public static Vector1D parse(final String str) {
return SimpleTupleFormat.getDefault().parse(str, Vector1D::new);
}

/** Returns a vector consisting of the linear combination of the inputs.
* <p>
* A linear combination is the sum of all of the inputs multiplied by their
* corresponding scale factors.
* </p>
*
* @param a scale factor for first vector
* @param c first vector
* @return vector calculated by {@code a * c}
*/
public static Vector1D linearCombination(final double a, final Vector1D c) {
return new Vector1D(a * c.x);
}

/** Returns a vector consisting of the linear combination of the inputs.
* <p>
* A linear combination is the sum of all of the inputs multiplied by their
* corresponding scale factors.
* </p>
*
* @param a1 scale factor for first vector
* @param v1 first vector
* @param a2 scale factor for second vector
* @param v2 second vector
* @return vector calculated by {@code (a1 * v1) + (a2 * v2)}
*/
public static Vector1D linearCombination(final double a1, final Vector1D v1,
final double a2, final Vector1D v2) {

return new Vector1D(
LinearCombination.value(a1, v1.x, a2, v2.x));
}

/** Returns a vector consisting of the linear combination of the inputs.
* <p>
* A linear combination is the sum of all of the inputs multiplied by their
* corresponding scale factors.
* </p>
*
* @param a1 scale factor for first vector
* @param v1 first vector
* @param a2 scale factor for second vector
* @param v2 second vector
* @param a3 scale factor for third vector
* @param v3 third vector
* @return vector calculated by {@code (a1 * v1) + (a2 * v2) + (a3 * v3)}
*/
public static Vector1D linearCombination(final double a1, final Vector1D v1,
final double a2, final Vector1D v2,
final double a3, final Vector1D v3) {

return new Vector1D(
LinearCombination.value(a1, v1.x, a2, v2.x, a3, v3.x));
}

/** Returns a vector consisting of the linear combination of the inputs.
* <p>
* A linear combination is the sum of all of the inputs multiplied by their
* corresponding scale factors.
* </p>
*
* @param a1 scale factor for first vector
* @param v1 first vector
* @param a2 scale factor for second vector
* @param v2 second vector
* @param a3 scale factor for third vector
* @param v3 third vector
* @param a4 scale factor for fourth vector
* @param v4 fourth vector
* @return vector calculated by {@code (a1 * v1) + (a2 * v2) + (a3 * v3) + (a4 * v4)}
*/
public static Vector1D linearCombination(final double a1, final Vector1D v1,
final double a2, final Vector1D v2,
final double a3, final Vector1D v3,
final double a4, final Vector1D v4) {

return new Vector1D(
LinearCombination.value(a1, v1.x, a2, v2.x, a3, v3.x, a4, v4.x));
}

/**
* Represent unit vectors.
* This allows optimizations to be performed for certain operations.
@@ -494,4 +416,71 @@ private static Unit tryCreateNormalized(final double x, final boolean throwOnFai
return null;
}
}

/** Class used to create high-accuracy sums of vectors. Each vector component is
* summed using an instance of {@link org.apache.commons.numbers.core.Sum}.
*
* <p>This class is mutable and not thread-safe.
* @see org.apache.commons.numbers.core.Sum
*/
public static final class Sum extends EuclideanVectorSum<Vector1D> {

/** X component sum. */
private final org.apache.commons.numbers.core.Sum xsum;

/** Construct a new instance with the given initial value.
* @param initial initial value
*/
Sum(final Vector1D initial) {
this.xsum = org.apache.commons.numbers.core.Sum.of(initial.x);
}

/** {@inheritDoc} */
@Override
public Sum add(final Vector1D vec) {
xsum.add(vec.x);
return this;
}

/** {@inheritDoc} */
@Override
public Sum addScaled(final double scale, final Vector1D vec) {
xsum.addProduct(scale, vec.x);
return this;
}

/** {@inheritDoc} */
@Override
public Vector1D get() {
return Vector1D.of(xsum.getAsDouble());
}

/** Create a new instance with an initial value set to the {@link Vector1D#ZERO zero vector}.
* @return new instance set to zero
*/
public static Sum create() {
return new Sum(Vector1D.ZERO);
}

/** Construct a new instance with an initial value set to the argument.
* @param initial initial sum value
* @return new instance
*/
public static Sum of(final Vector1D initial) {
return new Sum(initial);
}

/** Construct a new instance from multiple values.
* @param first first vector
* @param more additional vectors
* @return new instance
*/
public static Sum of(final Vector1D first, final Vector1D... more) {
final Sum s = new Sum(first);
for (final Vector1D v : more) {
s.add(v);
}
return s;
}
}
}

0 comments on commit 3d138dc

Please sign in to comment.