Giter Site home page Giter Site logo

unitsofmeasurement / unit-api Goto Github PK

View Code? Open in Web Editor NEW
178.0 17.0 41.0 9.88 MB

Units of Measurement API

Home Page: http://unitsofmeasurement.github.io/unit-api/

License: Other

D 0.02% Java 99.98%
java units jcp jsr measurement measure standard iot api units-of-measurement

unit-api's People

Contributors

andi-huber avatar codacy-badger avatar daniel-dos avatar desruisseaux avatar gitter-badger avatar keilw avatar markxiaotao avatar michael-simons avatar natoscott avatar oliver-loeffler avatar teobais avatar waffle-iron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

unit-api's Issues

Classpath Discovery

As discussed it seems a useful SPI feature to discover available

  • Quantity implementations
  • Prefix implementations
    on the classpath or module path.

Solving Unit-1 is-equivalent-to Unit-2

Quick Facts

  • Two Units (of the same quantity) are equivalent if by replacing one with the other you achieve equivalent numerical results when doing quantity calculus.
  • Instances of Unit must hold an instance of UnitConverter.
  • UnitConverters represent transformations.
  • UnitConverters allow composition, such that composing 2 UnitConverters is equivalent to composing their transformation functions.
  • Two UnitConverters of same type can be equivalent but are not in general, e.g. they may not be equivalent because of different prefix.

Suppose we have UnitConverter types A,B,C.
Let S be the set of UnitConverter types available.

S:= {A,B,C}

Now if we pick any x and any y from S we need to know

  1. whether x commutes with y, such that a composition x.y is equivalent to y.x
    x.y =?= y.x
  2. whether there are any simplification rules x.y -> x or x.y -> y or similar.
  3. whether one instance of x is equivalent to another instance of x

Given this information we are ready to state a Word Problem [1] for any given pair of Units, for example:

Suppose we know A commutes with B, but C does not commute with any other
A.B == B.A
A.C != C.A
B.C != C.B

Suppose we know C composes with C, such that C.C can be simplified to another C
C.C -> C

Suppose we have a UnitConverter p created by composition of types A, B and C (namely a0, b0 and c0).
p:= b0.a0.c0 (with type composition B.A.C)

Suppose we have a UnitConverter q created by another composition of types A, B and C (namely a2, b2, c1 and c2).
q:= a2.b2.c1.c2 (with type composition A.B.C.C)

We would then apply Term Rewriting rules to the type compositions of p and q until we find that these are equivalent (or not). Ideally we have such rules that produce a normal form.
p: B.A.C -> A.B.C
q: A.B.C.C -> A.B.C

Given
p: a0.b0.c0
q: a2.b2.(c1.c2)

then p is-equivalent-to q, only if all these hold true
a0 is-equivalent-to a2
b0 is-equivalent-to b2
c0 is-equivalent-to c1.c2

If the Term Rewriting rules are carefully designed to always produce a normal form, then the Unit-1 is-equivalent-to Unit-2 problem is decidable. Otherwise it's not for the general case.

[1] https://en.wikipedia.org/wiki/Word_problem_(mathematics)

Needs #39

Create Quantity from Unit as part of API

As a consumer of this API I find it frustrating that I have to propagate extra references just to create a quantity of a given unit. I would much prefer to only have to pass around instances of Unit to be able to actually work with that unit in a useful way.

I find it strange that the QuantityFactory interface need exist at all. Why is there no Unit.getQuantity(Number) method instead? Perhaps I am missing some sensible and important reason but I think the reason for this omission at least deserves some documentation.

Javadoc corrections

This issues list some Javadoc statements that may need to be fixed.

ServiceProvider.getQuantityFactory(Class)

Javadoc said "Return a factory for this Quantity". I think that we mean "Returns a factory for the given Quantity type". Also the javadoc for the @param tag should be "the quantity type".

Quantity.divide(Quantity)

Javadoc said "Returns the product of this Quantity divided by the Quantity specified". I guess that we mean "Returns the quotient ...".

SystemOfUnitsService.getSystemOfUnits(String)

Javadoc for @return tag said "the given system of units". I think that we mean "the system of units for the given name".

Unit.alternate(String)

UnitFormat.label(String) said that it throws an IllegalArgumentException for illegal symbol, but Unit.alternate(String) does not said what happen in such case. I presume that in the @throws tag, the "if the specified symbol is already associated to a different unit" statement could be replaced by "if the specified symbol is not valid or is already associated to a different unit".

QuantityFormat.parse()

Parses a portion of the specified CharSequence from the specified position to produce an object.
Should be "... to produde a quantity." in both cases

How to retrieve prefixes?

Based on input and concerns by @desruisseaux in #83 please allow me to cast another vote to clarify how we offer Prefix retrieval from SystemOfUnitsService?

Actually DefaultSystemOfUnitsService in the RI implementing the interface is of no value, because all the implementations like SISystemService in si-units have to do the same because it's enforced by the interface. Even if (in this case the RI already defines the only "SI Prefix") the module does not define its own prefixes.
Either the RI must get an AbstractSystemOfUnitsService similar to AbstractSystemOfUnits, allowing all RI-based modules to derive from it, or the one-liner could go directly into SystemOfUnitsService as default method. Those can always be overriden by implementations that do not rely on enum-based prefixes, so there's nothing lost, but no implementation that uses enums would need any boiler-plate code. It is just a single line of code that every implementation can override if it has to.

Clarify behavior of Quantity arithmetic on shifted units

Clarify the behavior of Q₁ + Q₂ or Q * n (with n a unitless number) when the unit of measurement of Q, Q₁ or Q₂ is "shifted". Example of shifted units are:

  • Temperature in Celsius, with °C defined as K - 273.15 K.
  • Density sigma-t, with σT defined as ρ - 1000 kg/m³ (used in oceanography).
  • Other shifted units in other scientific domains?

Taking temperature in °C as an example, addition can happen in at least two different contexts:

  • T₁ + T₂ : there is some legitimate uses for such additions, but they are rare.
  • T + ΔT : a more common case.

In the T₁ + T₂ case, both quantities must be converted to K before addition. So 20°C + 10°C = 303.15°C because T₂ = 283.15 K. In the T + ΔT case, 10°C is an increment (ΔT). So in this later case 20°C + 10°C = 30°C.

In current API, there is no way to know if a number is an absolute quantity or an increment. So there is no way to know if we are in the T₁ + T₂ case or in the T + ΔT case. If we want to differentiate those quantities, we may need to:

  • Add a new method in UnitConverter: deltaConvert(double), which convert the given value without applying the offset. This is similar to deltaTransform in java.awt.geom.AffineTransform.
  • Introduce a new interface: Increment<Q extends Quantity<Q>>.
  • Defines arithmetic rules as below: in any arithmetic operation like M₁ + M₂ or M * n, implementation SHALL do the following steps at least conceptually (implementations are allowed to avoid conversions in some cases provided that the numerical result is the same):
    • All M values SHALL be converted to system units before addition or multiplication.
      • Conversions of Quantity instances shall be done with UnitConverter.convert(…).
      • Conversions of Increment instances shall be done with UnitConverter.deltaConvert(…).
    • Result type is defined by the following table:
      • Quantity + Quantity = Quantity
      • Quantity + Increment = Quantity
      • Increment + Quantity = Quantity
      • Increment + Increment = Increment
      • Quantity * n = Quantity
      • Increment * n = Increment
    • Result value is converted back to the unit of measurement of the first operand (M₁).
      • Using UnitConverter.convert(…) if the result type is Quantity.
      • Using UnitConverter.deltaConvert(…) if the result type is Increment.

Requires #98
Requires #99

Does Prefix need a UnitConverter?

Based on discussions in #85 and hints, we may consider offering default prefixes like MetricPrefix or BinaryPrefix in the API, what should make up the Prefix?

Currently Prefix among String methods declares

/**
   * Returns the corresponding {@link UnitConverter}.
   *
   * @return the unit converter.
   */
  public UnitConverter getConverter();

While the implementations of UnitConverter like RationalConverter or MultiplyConverter are not exactly rocket-science, pulling them into the API would blow it up quite significantly. And although V2 aims at Java SE we should not outrule very special converters in specific environments.

So the question is, does the Prefix need a UnitConverter or would a member variable like value or factor be sufficient?

The old BinaryPrefix in uom-lib-common retrofitted as an enum now, too shows how this may look like in the API if we went for it. I am not casting a vote yet, I am unbiased and could see it in either place.

Rename Converter.isLinear() or change its specification

The Converter.isLinear() definition given in Javadoc basically restricts "linear" conversions to this formula:

y = a*x

The definition given in Converter.isLinear() does not allow the following formula, despite that formula being usually considered linear too:

y = a*x + b

So conversions between Celsius and Kelvin (or between Celsius and Fahrenheit) are not linear according the definition given in Converter.isLinear() javadoc, which I found surprising. It seems to me that the "isLinear" name is not appropriate for that method. Maybe "isScale" would have been more accurate.

Needs #95

Fix Maven badge

The Maven badge on Heroku is constantly broken.
Use something else like Shields.io

Provide a more general purpose MeasurementFormatException

Right now the API defines only ParserException for many errors in the context of parsing or formatting. Sometimes the information available does not meet all arguments ParserException may take like the exact position of a parsing error. If a problem occurs when formatting, ParserException sounds a bit misleading. Ideally a format-related but more general purpose exception should be introduced. Something like MeasurementFormatException or similar. The current ParserException could extend such exception.

Also see #46

implement Serializable

Hello,

it would be really nice if the API implements Serializable so that Quantity and Unit can be transfered over the wire

What should be the minimum Java version?

Should the API keep CLDC 8 (Java SE 7) as the minimum version in future, or jump to SE 8 giving it a few advantages like default methods in interfaces or static constants where applicable on an interface, not just classes?

Build a Java 9 Multi-Release API JAR

Also see unitsofmeasurement/indriya#25 the Multi-Release JAR should be available for the API. If the API JAR is built with Java 9 in a traditional way, it ends up with JVM Version 53, not compatible with Java 8 (V 52) any more. Ideally the API should still be at least Java 8 compatible with module-info and other Java 9 or 10 features in the correct structure.

Rename ParserException to MeasurementParseException

A rather generic ParserException can be found at least in JDK Nashorn, but otherwise both the JDK and other JSRs either call it ParseException (like java.text.ParseException) or *ParseException (like MonetaryParseException, DateTimeParseException, etc.)

It is not the most urgent case, but with other proposals like #39 that also would require adding a new name and deprecate the old one, it's worth do mention this as well. A new exception could be called MeasurementParseException.

Add QuantityFormat to API

Since both Quantity and Unit are mandatory core parts and first class citizens of the API, formatting should also be offered for a Quantity, not just its Unit part.
https://github.com/unitsofmeasurement/unit-ri/blob/master/src/main/java/tec/units/ri/format/QuantityFormat.java
or its Java SE equivalent are part of the official implementations. There is not a great deal in making an abstract base class or interface available for Quantity as well.

In addition a minor SPI change would require either a QuantityFormatService or potentially a combined FormatService providing access to both of them.

Provide default methods for certain operations of Unit?

At the moment at least

  • divide(Unit)
/**
   * Returns the quotient of this unit with the one specified.
   *
   * @param that
   *          the unit divisor.
   * @return <code>this.multiply(that.inverse())</code>
   */
  @Override
  public final Unit<?> divide(Unit<?> that) {
    return this.multiply(that.inverse());
  }
  • isSystemUnit()
 /**
   * Indicates if this unit belongs to the set of coherent SI units (unscaled SI units).
   * 
   * The base and coherent derived units of the SI form a coherent set, designated the set of coherent SI units. The word coherent is used here in the
   * following sense: when coherent units are used, equations between the numerical values of quantities take exactly the same form as the equations
   * between the quantities themselves. Thus if only units from a coherent set are used, conversion factors between units are never required.
   * 
   * @return <code>equals(toSystemUnit())</code>
   */
  @Override
  public boolean isSystemUnit() {
    Unit<Q> si = this.toSystemUnit();
    return (this == si) || this.equals(si);
  }

in AbstractUnit have no calls or dependency on a concrete implementation class.

Like parts of the JDK (e.g. java.time.temporal.TemporalAmount) do in similar cases, these methods could be implemented as default in the Unit interface.

Retrieve prefixes by class instead of string in SystemOfUnitsService

Currently SystemOfUnitsService returns Collection<Prefix> getPrefixes(String name); as of #81.

Let's try to retrieve it using the enum class (e.g. MetricPrefix) directly, so something like return Collections.<Prefix>unmodifiableSet(EnumSet.allOf(MetricPrefix.class)); would take the Class of a particular Prefix implementation. If we used a default method in the API, every Prefix should be based on enums, otherwise we may leave that to implementations like Indriya.

Provide default method only it can fulfill the method contract

In Unit-API development branch, some default method implementations have been added in the interfaces. I suggest to do so only when the default implementation can fulfill the method contract. In particular:

  • UnitConverter.isIdentity() should not return false by default. The method contract said that a value of false means that the unit converter is not identity. The default method can hardly detect that by itself.
  • UnitConverter.isLinear() should not return isIdentity() by default. This would be okay only when this method returns true. In the vast majority of cases, this default method would return false because the converter is not the identity one, but it still linear.

Note that the above does not necessarily apply to AbstractConverter in the reference implementation. In that later case, the strategy to define those default methods in an abstract class is an implementation choice. Since the person who define AbstractConverter is the same that the one who define the concrete classes on top of it, we can presume that (s)he know what (s)he is doing. But in the Unit-API case, the group defining UnitConverter is not the same than the group who will implement it.

Make isLocaleSensitive() default in UnitFormat

The new API method isLocaleSensitive() in QuantityFormat is declared as default. Since 2.0 is based on Java SE 8 and a majority of implementations are not locale-sensitive, we should also consider that for UnitFormat.

Dimension interoperability

If we want cross-implementation interoperability, we may need to define the behavior of Dimension.equals(Object). It would be needed because two Unit instances are considered convertible if all their dimensions are equal. One possible approach would be to normalize dimension symbols (L for length, T for time, etc.) and require Dimension.equals(Object) to compare the symbols. But we could also choose that allowing mix of different Dimension implementation is not a goal, which is all-right (I just don't know if it was a conscientious decision or an accident).

Shall we use ParsePosition in QuantityFormat?

The draft of QuantityFormat is based on earlier implementation only classes for Java SE. Therefore it uses java.text.ParsePosition. Should the API reference java.text although some environments, at least Java ME Embedded do not support it, or shall we no longer care about ME in this version of the API?

Provide certain methods of AbstractQuantity in Quantity as default?

  • toSystemUnit
    While a convenience method, this AbstractQuantity method could be a default method in Quantity, as well:
 /**
   * Convenient method equivalent to {@link #to(javax.measure.Unit) to(this.getUnit().toSystemUnit())}.
   *
   * @return this quantity or a new quantity equivalent to this quantity stated in SI units.
   * @throws ArithmeticException
   *           if the result is inexact and the quotient has a non-terminating decimal expansion.
   */
  public Quantity<Q> toSystemUnit() {
    return to(this.getUnit().getSystemUnit());
  }
  • toString
    Although QuantityFormat adds new formatting options in V2, the default out-of-the-box toString() implementation in AbstractQuantity:
 /**
   * Returns the <code>String</code> representation of this quantity. The string produced for a given quantity is always the same; it is not affected
   * by locale. This means that it can be used as a canonical string representation for exchanging quantity, or as a key for a Hashtable, etc.
   * Locale-sensitive quantity formatting and parsing is handled by the {@link MeasurementFormat} class and its subclasses.
   *
   * @return <code>UnitFormat.getInternational().format(this)</code>
   */
  @Override
  public String toString() {
    return String.valueOf(getValue()) + " " + String.valueOf(getUnit());
  }

Is not likely to change, so we could also offer it on an API level.

What about Unit.annotate()?

At the moment the Unit interface defines alternate() or transform() methods but annotate() is only exposed via the AbstractUnit base class of implementations. Unless it is too little-used and this is meant to be a status-quo, could it also be added to the Unit interface from a future version?

Quantity#inverse() and Unit#inverse() - Naming is ambiguous

The intent of Quantity#inverse() and Unit#inverse() methods might be confused with meaning the 'Additive Inverse'.

In math terminology the term 'inverse' can be applied to any function, without being specific.

The API currently uses inverse() as the 'Multiplicative Inverse', but is not clear about this within the java-doc.

If there's any chance to improve the API, I'd suggest:

  • (For symmetry reasons) adding Quantity#negate() as the 'Additive Inverse' (no change in Unit)
  • Replacing Quantity#inverse() with Quantity#reciprocal() as the 'Multiplicative Inverse'
  • Replacing Unit#inverse() with Unit#reciprocal() as the 'Multiplicative Inverse'

Cheers, Andi!

Would it make sense to add Level to the quantity package here?

Would it make sense to add the Level quantity, currently in systems-quantity here under the quantity package? As unitsofmeasurement/si-units#47 raises a need to factor it out of uom-systems because the NonSI class is meant to complement SI in si-units for Non-SI units accepted with the SI, we should at least move Level to si-quantity, so the question is, whether it makes sense or wastes space to put it into the API? Compared to other new API elements it does not seem to be massive (adding 320 bytes to the JAR) and quantity is an optional package that very resource constraint environments could leave out.

Update JUnit version

Hey guys, I saw that the API are not using the last version of JUnit and as improvement process, I would update the JUnit library.
I can start with the API and after the others projects like indriya

Add collection method to Prefix

While most Prefix implementations use a Java enum, its values() method is only available in the actual implementation. Can we add a method to Prefix that works like SystemOfUnits.getUnits()?

For enum based implementations, it seems rather straightforward via:
return Collections.<Prefix>unmodifiableSet(EnumSet.allOf(MetricPrefix.class));
see https://stackoverflow.com/questions/6528570/converting-from-enumseta-to-setb-when-a-inherits-from-b

Hopefully easier vote on how to call this method?

Retrieving a unit from SystemOfUnit via String representation

Currently SystemOfUnits allows to acces the default (base) unit like:

SystemOfUnits metricSystem = ServiceProvider.current().getSystemOfUnitsService().
   getSystemOfUnits();
Unit<Length> metre = metricSystem.getUnit(Length.class);

For other units it is necessary to look it up from the set of units

Unit<?> metre;
SystemOfUnits metricSystem = ServiceProvider.current().getSystemOfUnitsService().
   getSystemOfUnits();
for (Unit u: metricSystem.getUnits()) {
  if ("m".equals(u.getSymbol()) {
    metre = u;
    break;
  }
}

Although this for loop may be easier and shorter with Lambdas would it make sense to add a method like <? extends Unit<?>> getUnit(String key) to SystemOfUnits? Allowing to access a Unit via its String representation. Whether symbol, name or label (what's used by toString()) is a separate question, first we should decide, if we want this extra method in the 2.0 API.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.