UNPKG

@qudtlib/core

Version:

Data model for QUDTLib

164 lines (163 loc) 6.11 kB
import { arrayDeduplicate, arrayEqualsIgnoreOrdering, checkInteger, compareUsingEquals, isNullish, } from "./utils.js"; import { DimensionVector } from "./dimensionVector.js"; /** * Combines a {@link Unit} and an exponent; some Units are a combination of {@link FactorUnit}s. If * a unit is such a 'derived unit', its {@link Unit#getFactorUnits()} method returns a non-empty Set * of FactorUnits. * */ export class FactorUnit { constructor(unit, exponent) { checkInteger(exponent, "exponent"); this.exponent = exponent; this.unit = unit; } /** * Perform mathematical simplification on factor units. Only simplifies units with exponents of the same sign. * * For example, * ``` * N / M * M -> N per M^2 * ``` * * @param factorUnits the factor units to simplify * @return the simplified factor units. */ static contractExponents(factorUnits) { const ret = []; const factorUnitsByKind = factorUnits.reduce((mapping, cur) => { const kind = cur.getKind(); const prevUnit = mapping.get(kind); if (prevUnit) { mapping.set(kind, FactorUnit.combine(prevUnit, cur)); } else { mapping.set(kind, cur); } return mapping; }, new Map()); for (const fu of factorUnitsByKind.values()) { ret.push(fu); } return ret; } static reduceExponents(factorUnits) { const ret = []; const exponentsByUnit = factorUnits.reduce((mapping, cur) => { const unit = cur.unit; const prevExponent = mapping.get(unit); if (prevExponent) { mapping.set(unit, prevExponent + cur.exponent); } else { mapping.set(unit, cur.exponent); } return mapping; }, new Map()); for (const [unit, exponent] of exponentsByUnit.entries()) { if (Math.abs(exponent) > 0) { ret.push(new FactorUnit(unit, exponent)); } } return ret; } pow(by) { checkInteger(by, "by"); return new FactorUnit(this.unit, this.exponent * by); } getExponentCumulated(cumulatedExponent) { checkInteger(cumulatedExponent, "cumulatedExponent"); return this.exponent * cumulatedExponent; } isCompatibleWith(other) { return (this.exponent === other.exponent && this.unit.isConvertible(other.unit)); } getConversionMultiplier(other) { if (!this.isCompatibleWith(other)) { throw `${this.toString()} is not compatible with ${other.toString()}`; } return this.unit.getConversionMultiplier(other.unit).pow(this.exponent); } equals(other) { return (!!other && this.exponent === other.exponent && this.unit.equals(other.unit)); } toString() { return (this.unit.toString() + (this.exponent === 1 ? "" : "^" + this.exponent)); } static combine(left, right) { if (!left) { return right; } if (!right) { return left; } if (!left.unit.equals(right.unit)) { throw `Cannot combine UnitFactors of different units (left: ${left.unit.toString()}, right:${right.unit.toString()}`; } return new FactorUnit(left.unit, left.exponent + right.exponent); } /** * Combines unit IRI and sign of exponent in one string. */ getKind() { return (this.unit.iri + (this.exponent === 0 ? "0" : this.exponent > 0 ? "1" : "-1")); } getLeafFactorUnitsWithCumulativeExponents() { const leafFactorUnits = this.unit.getLeafFactorUnitsWithCumulativeExponents(); if (!!leafFactorUnits?.length) { return leafFactorUnits.map((fu) => fu.pow(this.exponent)); } return [this]; } normalize() { return this.unit.normalize().pow(this.exponent); } getAllPossibleFactorUnitCombinations() { const subResult = this.unit.getAllPossibleFactorUnitCombinations(); const result = subResult.map((fus) => fus.map((fu) => fu.pow(this.exponent))); return arrayDeduplicate(result, (left, right) => arrayEqualsIgnoreOrdering(left, right, compareUsingEquals)); } static getAllPossibleFactorUnitCombinations(factorUnits) { const numFactors = factorUnits.length; const subResults = factorUnits.map((fu) => fu.getAllPossibleFactorUnitCombinations()); const subResultLengths = subResults.map((s) => s.length); const currentIndices = []; currentIndices.length = numFactors; currentIndices.fill(0); const results = []; // cycle through all possible combinations of results per factor unit and combine them do { const curResult = []; let countUp = true; for (let i = 0; i < numFactors; i++) { curResult.push(...subResults[i][currentIndices[i]]); if (countUp) { currentIndices[i]++; if (currentIndices[i] >= subResultLengths[i]) { currentIndices[i] = 0; } else { countUp = false; } } } results.push(FactorUnit.contractExponents(curResult)); results.push(FactorUnit.reduceExponents(curResult)); } while (!currentIndices.every((val) => val === 0)); return arrayDeduplicate(results, (left, right) => arrayEqualsIgnoreOrdering(left, right, compareUsingEquals)); } getDimensionVector() { if (isNullish(this.unit.dimensionVectorIri)) { return undefined; } const dv = new DimensionVector(this.unit.dimensionVectorIri); return dv.multiply(this.exponent); } static ofUnit(unit) { return new FactorUnit(unit, 1); } } //# sourceMappingURL=factorUnit.js.map