summaryrefslogtreecommitdiff
path: root/src/main/java/sevenUnits/utils/ObjectProduct.java
diff options
context:
space:
mode:
authorAdrien Hopkins <adrien.p.hopkins@gmail.com>2024-08-22 10:12:37 -0500
committerAdrien Hopkins <adrien.p.hopkins@gmail.com>2024-08-22 11:45:37 -0500
commit6f1bbc1024eae98f1815ab5f9e9cb3399f5eef9c (patch)
tree86a14f6866323d7aeaae231b91d72b3aa5bd6cb4 /src/main/java/sevenUnits/utils/ObjectProduct.java
parent2c2b97f964327f14ce09b0b935a46aec77526560 (diff)
Allow fractional exponents
Diffstat (limited to 'src/main/java/sevenUnits/utils/ObjectProduct.java')
-rw-r--r--src/main/java/sevenUnits/utils/ObjectProduct.java87
1 files changed, 59 insertions, 28 deletions
diff --git a/src/main/java/sevenUnits/utils/ObjectProduct.java b/src/main/java/sevenUnits/utils/ObjectProduct.java
index 5a29d79..4ed70be 100644
--- a/src/main/java/sevenUnits/utils/ObjectProduct.java
+++ b/src/main/java/sevenUnits/utils/ObjectProduct.java
@@ -35,6 +35,12 @@ import java.util.function.Function;
*/
public class ObjectProduct<T> implements Nameable {
/**
+ * If {@link #toExponentRounded}'s rounding changes exponents by more than
+ * this value, a warning will be printed to standard error.
+ */
+ private static final double ROUND_WARN_THRESHOLD = 1e-12;
+
+ /**
* Returns an empty ObjectProduct of a certain type
*
* @param <T> type of objects that can be multiplied
@@ -44,7 +50,7 @@ public class ObjectProduct<T> implements Nameable {
public static final <T> ObjectProduct<T> empty() {
return new ObjectProduct<>(new HashMap<>());
}
-
+
/**
* Gets an {@code ObjectProduct} from an object-to-integer mapping
*
@@ -57,7 +63,7 @@ public class ObjectProduct<T> implements Nameable {
final Map<T, Integer> map) {
return new ObjectProduct<>(new HashMap<>(map));
}
-
+
/**
* Gets an ObjectProduct that has one of the inputted argument, and nothing
* else.
@@ -73,7 +79,7 @@ public class ObjectProduct<T> implements Nameable {
map.put(object, 1);
return new ObjectProduct<>(map);
}
-
+
/**
* The objects that make up the product, mapped to their exponents. This map
* treats zero as null, and is immutable.
@@ -81,12 +87,12 @@ public class ObjectProduct<T> implements Nameable {
* @since 2019-10-16
*/
final Map<T, Integer> exponents;
-
+
/**
* The object's name and symbol
*/
private final NameSymbol nameSymbol;
-
+
/**
* Creates a {@code ObjectProduct} without a name/symbol.
*
@@ -96,7 +102,7 @@ public class ObjectProduct<T> implements Nameable {
ObjectProduct(final Map<T, Integer> exponents) {
this(exponents, NameSymbol.EMPTY);
}
-
+
/**
* Creates the {@code ObjectProduct}.
*
@@ -110,7 +116,7 @@ public class ObjectProduct<T> implements Nameable {
e -> !Integer.valueOf(0).equals(e.getValue())));
this.nameSymbol = nameSymbol;
}
-
+
/**
* Calculates the quotient of two products
*
@@ -125,17 +131,17 @@ public class ObjectProduct<T> implements Nameable {
final Set<T> objects = new HashSet<>();
objects.addAll(this.getBaseSet());
objects.addAll(other.getBaseSet());
-
+
// get a list of all exponents
final Map<T, Integer> map = new HashMap<>(objects.size());
for (final T key : objects) {
map.put(key, this.getExponent(key) - other.getExponent(key));
}
-
+
// create the product
return new ObjectProduct<>(map);
}
-
+
// this method relies on the use of ZeroIsNullMap
@Override
public boolean equals(final Object obj) {
@@ -146,7 +152,7 @@ public class ObjectProduct<T> implements Nameable {
final ObjectProduct<?> other = (ObjectProduct<?>) obj;
return Objects.equals(this.exponents, other.exponents);
}
-
+
/**
* @return immutable map mapping objects to exponents
* @since 2019-10-16
@@ -154,7 +160,7 @@ public class ObjectProduct<T> implements Nameable {
public Map<T, Integer> exponentMap() {
return this.exponents;
}
-
+
/**
* @return a set of all of the base objects with non-zero exponents that make
* up this dimension.
@@ -163,7 +169,7 @@ public class ObjectProduct<T> implements Nameable {
*/
public final Set<T> getBaseSet() {
final Set<T> dimensions = new HashSet<>();
-
+
// add all dimensions with a nonzero exponent - zero exponents shouldn't
// be there in the first place
for (final T dimension : this.exponents.keySet()) {
@@ -171,10 +177,10 @@ public class ObjectProduct<T> implements Nameable {
dimensions.add(dimension);
}
}
-
+
return dimensions;
}
-
+
/**
* Gets the exponent for a specific dimension.
*
@@ -186,17 +192,17 @@ public class ObjectProduct<T> implements Nameable {
public int getExponent(final T dimension) {
return this.exponents.getOrDefault(dimension, 0);
}
-
+
@Override
public NameSymbol getNameSymbol() {
return this.nameSymbol;
}
-
+
@Override
public int hashCode() {
return Objects.hash(this.exponents);
}
-
+
/**
* @return true if this product is a single object, i.e. it has one exponent
* of one and no other nonzero exponents
@@ -214,7 +220,7 @@ public class ObjectProduct<T> implements Nameable {
}
return oneCount == 1 && !twoOrMore;
}
-
+
/**
* Multiplies this product by another
*
@@ -229,17 +235,17 @@ public class ObjectProduct<T> implements Nameable {
final Set<T> objects = new HashSet<>();
objects.addAll(this.getBaseSet());
objects.addAll(other.getBaseSet());
-
+
// get a list of all exponents
final Map<T, Integer> map = new HashMap<>(objects.size());
for (final T key : objects) {
map.put(key, this.getExponent(key) + other.getExponent(key));
}
-
+
// create the product
return new ObjectProduct<>(map);
}
-
+
/**
* Returns this product, but to an exponent
*
@@ -254,7 +260,32 @@ public class ObjectProduct<T> implements Nameable {
}
return new ObjectProduct<>(map);
}
-
+
+ /**
+ * Returns this product to an exponent, where every dimension is rounded to
+ * the nearest integer.
+ *
+ * This function will send a warning (via {@link System.err}) if the rounding
+ * significantly changes the value.
+ *
+ * @since 2024-08-22
+ */
+ public ObjectProduct<T> toExponentRounded(final double exponent) {
+ final Map<T, Integer> map = new HashMap<>(this.exponents);
+ for (final T key : this.exponents.keySet()) {
+ final double newExponent = this.getExponent(key) * exponent;
+ if (Math.abs(
+ newExponent - Math.round(newExponent)) > ROUND_WARN_THRESHOLD) {
+ System.err.printf(
+ "Exponent Rounding Warning: Dimension exponents must be integers, so %d ^ %g = %g was rounded to %d.\n",
+ this.getExponent(key), exponent, newExponent,
+ Math.round(newExponent));
+ }
+ map.put(key, (int) Math.round(newExponent));
+ }
+ return new ObjectProduct<>(map);
+ }
+
/**
* Converts this product to a string using the objects'
* {@link Object#toString()} method (or {@link Nameable#getShortName} if
@@ -271,7 +302,7 @@ public class ObjectProduct<T> implements Nameable {
.toString(o -> o instanceof Nameable ? ((Nameable) o).getShortName()
: o.toString());
}
-
+
/**
* Converts this product to a string. The objects that make up this product
* are represented by {@code objectToString}
@@ -283,7 +314,7 @@ public class ObjectProduct<T> implements Nameable {
public String toString(final Function<T, String> objectToString) {
final List<String> positiveStringComponents = new ArrayList<>();
final List<String> negativeStringComponents = new ArrayList<>();
-
+
// for each base object that makes up this object, add it and its exponent
for (final T object : this.getBaseSet()) {
final int exponent = this.exponents.get(object);
@@ -297,15 +328,15 @@ public class ObjectProduct<T> implements Nameable {
objectToString.apply(object), -exponent));
}
}
-
+
final String positiveString = positiveStringComponents.isEmpty() ? "1"
: String.join(" * ", positiveStringComponents);
final String negativeString = negativeStringComponents.isEmpty() ? ""
: " / " + String.join(" * ", negativeStringComponents);
-
+
return positiveString + negativeString;
}
-
+
/**
* @return named version of this {@code ObjectProduct}, using data from
* {@code nameSymbol}