| /** |
| ******************************************************************************** |
| * Copyright (c) 2015-2019 Robert Bosch GmbH and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Robert Bosch GmbH - initial API and implementation |
| ******************************************************************************** |
| */ |
| |
| package org.eclipse.app4mc.amalthea.model; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.function.BinaryOperator; |
| |
| import org.apache.commons.math3.distribution.NormalDistribution; |
| import org.eclipse.emf.common.util.ECollections; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.InternalEObject; |
| import org.eclipse.emf.ecore.util.EcoreEList; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| |
| /** |
| * This class provides static methods that implement operations of the Amalthea |
| * EMF model. |
| * <p> |
| * The methods are called from several generated model objects. |
| */ |
| public class AmaltheaServices { |
| |
| // Suppress default constructor |
| private AmaltheaServices() { |
| throw new IllegalStateException("Utility class"); |
| } |
| |
| private static final BigInteger INT_8 = BigInteger.valueOf(8); |
| private static final BigInteger INT_2_POW_10 = BigInteger.valueOf(2).pow(10); |
| private static final BigInteger INT_2_POW_20 = BigInteger.valueOf(2).pow(20); |
| private static final BigInteger INT_2_POW_30 = BigInteger.valueOf(2).pow(30); |
| private static final BigInteger INT_2_POW_40 = BigInteger.valueOf(2).pow(40); |
| private static final BigInteger INT_10_POW_3 = BigInteger.TEN.pow(3); |
| private static final BigInteger INT_10_POW_6 = BigInteger.TEN.pow(6); |
| private static final BigInteger INT_10_POW_9 = BigInteger.TEN.pow(9); |
| private static final BigInteger INT_10_POW_12 = BigInteger.TEN.pow(12); |
| private static final BigDecimal DEC_10_POW_3 = BigDecimal.TEN.pow(3); |
| private static final BigDecimal DEC_10_POW_6 = BigDecimal.TEN.pow(6); |
| private static final BigDecimal DEC_10_POW_9 = BigDecimal.TEN.pow(9); |
| private static final BigDecimal DEC_10_POW_12 = BigDecimal.TEN.pow(12); |
| private static final String ARG_NULL_MESSAGE = "Argument is null, expected: %s"; |
| private static final String ARG_OBJECT_MESSAGE = "Object argument is null, expected: EObject"; |
| private static final String ARG_CLASS_MESSAGE = "Class argument is null, expected: Class<T extends EObject>"; |
| private static final String ARG_QUANTITY_MESSAGE = "Invalid %s object: value and unit must be set"; |
| private static final String ARG_BOUNDS_MESSAGE = "Invalid bounds: lower bound > upper bound"; |
| private static final String ARG_POSITIVE_VALUE_MESSAGE = "Invalid number, expected: value > 0"; |
| private static final String DATA_SIZE = DataSize.class.getSimpleName(); |
| private static final String DATA_RATE = DataRate.class.getSimpleName(); |
| private static final String TIME = Time.class.getSimpleName(); |
| private static final String FREQUENCY = Frequency.class.getSimpleName(); |
| private static final String VOLTAGE = Voltage.class.getSimpleName(); |
| private static final String NUMBER = Number.class.getSimpleName(); |
| |
| private static void checkDataSizeArgument(final DataSize size) { |
| checkArgument(size != null, ARG_NULL_MESSAGE, DATA_SIZE); |
| checkArgument(size.getValue() != null, ARG_QUANTITY_MESSAGE, DATA_SIZE); |
| checkArgument(size.getUnit() != DataSizeUnit._UNDEFINED_, ARG_QUANTITY_MESSAGE, DATA_SIZE); |
| } |
| |
| private static void checkDataRateArgument(final @NonNull DataRate rate) { |
| checkArgument(rate != null, ARG_NULL_MESSAGE, DATA_RATE); |
| checkArgument(rate.getValue() != null, ARG_QUANTITY_MESSAGE, DATA_RATE); |
| checkArgument(rate.getUnit() != DataRateUnit._UNDEFINED_, ARG_QUANTITY_MESSAGE, DATA_RATE); |
| } |
| |
| private static void checkTimeArgument(final @NonNull Time time) { |
| checkArgument(time != null, ARG_NULL_MESSAGE, TIME); |
| checkArgument(time.getValue() != null, ARG_QUANTITY_MESSAGE, TIME); |
| checkArgument(time.getUnit() != TimeUnit._UNDEFINED_, ARG_QUANTITY_MESSAGE, TIME); |
| } |
| |
| public static final List<TimeUnit> TIME_UNIT_LIST = Collections |
| .unmodifiableList(Arrays.asList(TimeUnit.PS, TimeUnit.NS, TimeUnit.US, TimeUnit.MS, TimeUnit.S)); |
| |
| public static <T extends EObject> T getContainerOfType(final @NonNull EObject object, final @NonNull Class<T> type) { |
| checkArgument(object != null, ARG_OBJECT_MESSAGE); |
| checkArgument(type != null, ARG_CLASS_MESSAGE); |
| |
| for (EObject parent = object.eContainer(); parent != null; parent = parent.eContainer()) { |
| if (type.isInstance(parent)) |
| return type.cast(parent); |
| } |
| return type.cast(null); |
| } |
| |
| public static BigInteger convertToBit(final @NonNull DataSize size) { |
| checkDataSizeArgument(size); |
| |
| BigInteger bitBase = size.getValue(); |
| BigInteger byteBase = size.getValue().multiply(INT_8); |
| |
| switch (size.getUnit()) { |
| case BIT: |
| return bitBase; |
| case KBIT: |
| return bitBase.multiply(INT_10_POW_3); |
| case MBIT: |
| return bitBase.multiply(INT_10_POW_6); |
| case GBIT: |
| return bitBase.multiply(INT_10_POW_9); |
| case TBIT: |
| return bitBase.multiply(INT_10_POW_12); |
| |
| case KIBIT: |
| return bitBase.multiply(INT_2_POW_10); |
| case MIBIT: |
| return bitBase.multiply(INT_2_POW_20); |
| case GIBIT: |
| return bitBase.multiply(INT_2_POW_30); |
| case TIBIT: |
| return bitBase.multiply(INT_2_POW_40); |
| |
| case B: |
| return byteBase; |
| case KB: |
| return byteBase.multiply(INT_10_POW_3); |
| case MB: |
| return byteBase.multiply(INT_10_POW_6); |
| case GB: |
| return byteBase.multiply(INT_10_POW_9); |
| case TB: |
| return byteBase.multiply(INT_10_POW_12); |
| |
| case KI_B: |
| return byteBase.multiply(INT_2_POW_10); |
| case MI_B: |
| return byteBase.multiply(INT_2_POW_20); |
| case GI_B: |
| return byteBase.multiply(INT_2_POW_30); |
| case TI_B: |
| return byteBase.multiply(INT_2_POW_40); |
| |
| default: |
| return BigInteger.ZERO; // should never happen |
| } |
| } |
| |
| public static BigInteger convertToBitPerSecond(final @NonNull DataRate rate) { |
| checkDataRateArgument(rate); |
| |
| BigInteger bitBase = rate.getValue(); |
| BigInteger byteBase = rate.getValue().multiply(INT_8); |
| |
| switch (rate.getUnit()) { |
| case BIT_PER_SECOND: |
| return bitBase; |
| case KBIT_PER_SECOND: |
| return bitBase.multiply(INT_10_POW_3); |
| case MBIT_PER_SECOND: |
| return bitBase.multiply(INT_10_POW_6); |
| case GBIT_PER_SECOND: |
| return bitBase.multiply(INT_10_POW_9); |
| case TBIT_PER_SECOND: |
| return bitBase.multiply(INT_10_POW_12); |
| |
| case KIBIT_PER_SECOND: |
| return bitBase.multiply(INT_2_POW_10); |
| case MIBIT_PER_SECOND: |
| return bitBase.multiply(INT_2_POW_20); |
| case GIBIT_PER_SECOND: |
| return bitBase.multiply(INT_2_POW_30); |
| case TIBIT_PER_SECOND: |
| return bitBase.multiply(INT_2_POW_40); |
| |
| case BPER_SECOND: |
| return byteBase; |
| case KB_PER_SECOND: |
| return byteBase.multiply(INT_10_POW_3); |
| case MB_PER_SECOND: |
| return byteBase.multiply(INT_10_POW_6); |
| case GB_PER_SECOND: |
| return byteBase.multiply(INT_10_POW_9); |
| case TB_PER_SECOND: |
| return byteBase.multiply(INT_10_POW_12); |
| |
| case KI_BPER_SECOND: |
| return byteBase.multiply(INT_2_POW_10); |
| case MI_BPER_SECOND: |
| return byteBase.multiply(INT_2_POW_20); |
| case GI_BPER_SECOND: |
| return byteBase.multiply(INT_2_POW_30); |
| case TI_BPER_SECOND: |
| return byteBase.multiply(INT_2_POW_40); |
| |
| default: |
| return BigInteger.ZERO; // should never happen |
| } |
| } |
| |
| /** |
| * This method is used to convert the value of Time/TimeObject element's value |
| * to BigInteger in Pico Seconds |
| * |
| * @param time Time object |
| * @return value BigInteger in Pico Seconds |
| */ |
| public static BigInteger convertToPicoSeconds(final @NonNull Time time) { |
| checkTimeArgument(time); |
| |
| @SuppressWarnings("null") |
| @NonNull BigInteger timeValue = time.getValue(); |
| |
| switch (time.getUnit()) { |
| case PS: |
| return timeValue; |
| case NS: |
| return timeValue.multiply(INT_10_POW_3); |
| case US: |
| return timeValue.multiply(INT_10_POW_6); |
| case MS: |
| return timeValue.multiply(INT_10_POW_9); |
| case S: |
| return timeValue.multiply(INT_10_POW_12); |
| |
| default: |
| return BigInteger.ZERO; // should never happen |
| } |
| } |
| |
| /** |
| * This method is used to convert a time with associated time unit |
| * to BigDecimal in seconds |
| * |
| * @param time time as double |
| * @param timeUnit the time unit |
| * @return value BigDecimal in seconds |
| */ |
| public static BigDecimal convertToSeconds(final double time, final @NonNull TimeUnit timeUnit) { |
| checkArgument(timeUnit != TimeUnit._UNDEFINED_, ARG_QUANTITY_MESSAGE, TIME); |
| |
| BigDecimal timeValue = BigDecimal.valueOf(time); |
| switch (timeUnit) { |
| case S: |
| return timeValue; |
| case MS: |
| return timeValue.divide(DEC_10_POW_3); |
| case US: |
| return timeValue.divide(DEC_10_POW_6); |
| case NS: |
| return timeValue.divide(DEC_10_POW_9); |
| case PS: |
| return timeValue.divide(DEC_10_POW_12); |
| |
| default: |
| return BigDecimal.ZERO; // should never happen |
| } |
| } |
| |
| /** |
| * This method is used to convert the value of Time/TimeObject element's value |
| * to BigDecimal in seconds |
| * |
| * @param time Time object |
| * @return value BigDecimal in seconds |
| */ |
| public static BigDecimal convertToSeconds(final @NonNull Time time) { |
| checkArgument(time != null, ARG_NULL_MESSAGE, TIME); |
| |
| @SuppressWarnings("null") |
| @NonNull TimeUnit timeUnit = time.getUnit(); |
| |
| return convertToSeconds(time.getValue().doubleValue(), timeUnit); |
| } |
| |
| public static BigDecimal convertToHertz(final @NonNull Frequency frequency) { |
| checkArgument(frequency != null, ARG_NULL_MESSAGE, FREQUENCY); |
| checkArgument(frequency.getUnit() != FrequencyUnit._UNDEFINED_, ARG_QUANTITY_MESSAGE, FREQUENCY); |
| |
| double freqValue = frequency.getValue(); |
| |
| switch (frequency.getUnit()) { |
| case HZ: |
| return BigDecimal.valueOf(freqValue); |
| case KHZ: |
| return BigDecimal.valueOf(freqValue).multiply(DEC_10_POW_3); |
| case MHZ: |
| return BigDecimal.valueOf(freqValue).multiply(DEC_10_POW_6); |
| case GHZ: |
| return BigDecimal.valueOf(freqValue).multiply(DEC_10_POW_9); |
| |
| default: |
| return BigDecimal.ZERO; // should never happen |
| } |
| } |
| |
| public static BigDecimal convertToMicroVolt(final @NonNull Voltage voltage) { |
| checkArgument(voltage != null, ARG_NULL_MESSAGE, VOLTAGE); |
| checkArgument(voltage.getUnit() != VoltageUnit._UNDEFINED_, ARG_QUANTITY_MESSAGE, VOLTAGE); |
| |
| double voltValue = voltage.getValue(); |
| |
| switch (voltage.getUnit()) { |
| case UV: |
| return BigDecimal.valueOf(voltValue); |
| case MV: |
| return BigDecimal.valueOf(voltValue).multiply(DEC_10_POW_3); |
| case V: |
| return BigDecimal.valueOf(voltValue).multiply(DEC_10_POW_6); |
| |
| default: |
| return BigDecimal.ZERO; // should never happen |
| } |
| } |
| |
| /** |
| * This method is used to compare DataRate objects on the basis of their values |
| * (obtained in bit per second after applying the conversion based on DataRateUnit) |
| * |
| * @param r1 DataRate object |
| * @param r2 DataRate object |
| * @return -1 ,0 or 1 |
| */ |
| public static int compareDataRates(final @NonNull DataRate r1, final @NonNull DataRate r2) { |
| checkDataRateArgument(r1); |
| checkDataRateArgument(r2); |
| |
| if (r1 == r2) { |
| return 0; |
| } |
| |
| BigInteger value1 = convertToBitPerSecond(r1); |
| BigInteger value2 = convertToBitPerSecond(r2); |
| |
| assert value1 != null; |
| assert value2 != null; |
| |
| return value1.compareTo(value2); |
| } |
| |
| /** |
| * This method is used to compare Time objects on the basis of their values |
| * (obtained in pico seconds after applying the conversion based on TimeUnit) |
| * |
| * @param t1 Time object |
| * @param t2 Time object |
| * @return -1 ,0 or 1 |
| */ |
| public static int compareTimes(final @NonNull Time t1, final @NonNull Time t2) { |
| checkTimeArgument(t1); |
| checkTimeArgument(t2); |
| |
| if (t1 == t2) { |
| return 0; |
| } |
| |
| BigInteger value1 = convertToPicoSeconds(t1); |
| BigInteger value2 = convertToPicoSeconds(t2); |
| |
| assert value1 != null; |
| assert value2 != null; |
| |
| return value1.compareTo(value2); |
| } |
| |
| /** |
| * This method takes a time (in value and unit) and adjusts the TimeUnit so that |
| * the value is as small as possible, without losing precision e.g. 1000us is |
| * converted to 1ms |
| * |
| * @param time |
| * @return new Time with adjusted value and unit |
| */ |
| public static @NonNull Time adjustTimeUnit(final @NonNull Time time) { |
| checkTimeArgument(time); |
| |
| if (time.getValue() == BigInteger.ZERO) |
| return createTime(BigInteger.ZERO, TimeUnit.S); |
| |
| int index = TIME_UNIT_LIST.indexOf(time.getUnit()); |
| int maxIndex = TIME_UNIT_LIST.size() - 1; |
| BigInteger value = time.getValue(); |
| BigInteger bigInt1000 = INT_10_POW_3; |
| |
| while (value.mod(bigInt1000) == BigInteger.ZERO && index < maxIndex) { |
| value = value.divide(bigInt1000); |
| index++; |
| } |
| |
| return createTime(value, TIME_UNIT_LIST.get(index)); |
| } |
| |
| public static @NonNull Time addTime(final @NonNull Time t1, final @NonNull Time t2) { |
| checkTimeArgument(t1); |
| checkTimeArgument(t2); |
| |
| return applyToTimes(BigInteger::add, t1, t2); |
| } |
| |
| public static @NonNull Time subtractTime(final @NonNull Time t1, final @NonNull Time t2) { |
| checkTimeArgument(t1); |
| checkTimeArgument(t2); |
| |
| return applyToTimes(BigInteger::subtract, t1, t2); |
| } |
| |
| /** |
| * Divides t1 by t2 |
| * <p> |
| * In case of t2 == 0 the limit t2 -> 0 is used |
| * @param t1 |
| * @param t2 |
| * @return t1 / t2 |
| */ |
| public static double divideTime(final @NonNull Time t1, final @NonNull Time t2) { |
| checkTimeArgument(t1); |
| checkTimeArgument(t2); |
| |
| final BigInteger i1 = convertToPicoSeconds(t1); |
| final BigInteger i2 = convertToPicoSeconds(t2); |
| |
| if (BigInteger.ZERO.equals(i1)) { |
| if (BigInteger.ZERO.equals(i2)) { |
| // use limit: as x approaches 0 of x/x = 1 |
| return 1.0; |
| } else { |
| return 0.0; |
| } |
| } |
| |
| if (BigInteger.ZERO.equals(i2)) { |
| // use limit: as x approaches 0 of i1/x |
| if (i1.signum() == 1) { |
| return Double.POSITIVE_INFINITY; |
| } else { |
| return Double.NEGATIVE_INFINITY; |
| } |
| } |
| |
| return i1.doubleValue() / i2.doubleValue(); |
| } |
| |
| public static @NonNull Time multiply(final @NonNull Time t1, long value) { |
| checkTimeArgument(t1); |
| |
| BigInteger v1 = t1.getValue(); |
| BigInteger v2 = BigInteger.valueOf(value); |
| |
| return createTime(v1.multiply(v2), t1.getUnit()); |
| } |
| |
| public static @NonNull Time multiply(final @NonNull Time t1, double value) { |
| checkTimeArgument(t1); |
| |
| BigDecimal v1 = BigDecimal.valueOf(convertToPicoSeconds(t1).doubleValue()); |
| BigDecimal v2 = BigDecimal.valueOf(value); |
| |
| return createTime(v1.multiply(v2).toBigInteger(), TimeUnit.PS); |
| } |
| |
| private static @NonNull Time applyToTimes(final @NonNull BinaryOperator<BigInteger> func, final @NonNull Time t1, final @NonNull Time t2) { |
| BigInteger v1 = t1.getValue(); |
| BigInteger v2 = t2.getValue(); |
| |
| if (t1.getUnit() == t2.getUnit()) { |
| return createTime(func.apply(v1, v2), t1.getUnit()); |
| } |
| |
| int index1 = TIME_UNIT_LIST.indexOf(t1.getUnit()); |
| int index2 = TIME_UNIT_LIST.indexOf(t2.getUnit()); |
| int minIndex = Math.min(index1, index2); |
| v1 = (index1 > minIndex) ? v1.multiply(BigInteger.TEN.pow((index1 - minIndex) * 3)) : v1; |
| v2 = (index2 > minIndex) ? v2.multiply(BigInteger.TEN.pow((index2 - minIndex) * 3)) : v2; |
| |
| return createTime(func.apply(v1, v2), TIME_UNIT_LIST.get(minIndex)); |
| } |
| |
| private static @NonNull Time createTime(final BigInteger value, final TimeUnit unit) { |
| Time time = AmaltheaFactory.eINSTANCE.createTime(); |
| time.setValue(value); |
| time.setUnit(unit); |
| return time; |
| } |
| |
| /** |
| * Computes the average (mean) of the truncated normal distribution |
| * |
| * <p> |
| * See |
| * <a href="https://en.wikipedia.org/wiki/Truncated_normal_distribution" target= |
| * "_top">Truncated normal distribution (Wikipedia)</a> |
| * </p> |
| * |
| * @param a lower bound (null = not truncated from below) |
| * @param b upper bound (null = not truncated from above) |
| * @param mean mean or expectation of the (unlimited) distribution |
| * @param sd standard deviation |
| * @return Average of the truncated distribution |
| */ |
| public static @NonNull Time getAverageOfTruncatedNormalDistribution(final @Nullable Time a, final @Nullable Time b, final @NonNull Time mean, final @NonNull Time sd) { |
| checkTimeArgument(mean); |
| |
| // simple result for the unlimited distribution |
| if (a == null && b == null) return mean; |
| |
| checkTimeArgument(sd); |
| |
| if (a != null) checkTimeArgument(a); |
| if (b != null) checkTimeArgument(b); |
| if (a != null && b != null) checkArgument(a.compareTo(b) <= 0, ARG_BOUNDS_MESSAGE); |
| |
| // if a == b then return immediately (computation of factor will fail) |
| if (a != null && b != null && a.compareTo(b) == 0) return createTime(a.getValue(), a.getUnit()); |
| |
| Double alpha = null; |
| Double beta = null; |
| if (a != null) { // truncated from below |
| alpha = a.subtract(mean).divide(sd); |
| } |
| if (b != null) { // truncated from above |
| beta = b.subtract(mean).divide(sd); |
| } |
| |
| double factor = computeTruncatedNormalDistFactor(alpha, beta); |
| |
| if (Double.isNaN(factor)) |
| return mean; |
| |
| return addTime(mean, multiply(sd, factor)); |
| } |
| |
| /** |
| * Computes the average (mean) of the truncated normal distribution |
| * |
| * <p> |
| * See |
| * <a href="https://en.wikipedia.org/wiki/Truncated_normal_distribution" target= |
| * "_top">Truncated normal distribution (Wikipedia)</a> |
| * </p> |
| * |
| * @param inputA lower bound (null = not truncated from below) |
| * @param inputB upper bound (null = not truncated from above) |
| * @param mean mean or expectation of the (unlimited) distribution |
| * @param sd standard deviation |
| * @return Average of the truncated distribution |
| */ |
| public static double getAverageOfTruncatedNormalDistribution(final @Nullable Number inputA, final @Nullable Number inputB, double mean, double sd) { |
| // simple result for the unlimited distribution |
| if (inputA == null && inputB == null) return mean; |
| |
| // if a == b then return immediately (computation of factor will fail) |
| if (inputA != null && inputB != null && inputA.equals(inputB)) return inputA.doubleValue(); |
| |
| final Double a = (inputA != null) ? inputA.doubleValue() : null; |
| final Double b = (inputB != null) ? inputB.doubleValue() : null; |
| if (a != null && b != null) checkArgument(a <= b, ARG_BOUNDS_MESSAGE); |
| |
| Double alpha = null; |
| Double beta = null; |
| if (a != null) { // truncated from below |
| alpha = (a - mean) / sd; |
| } |
| if (b != null) { // truncated from above |
| beta = (b - mean) / sd; |
| } |
| |
| double factor = computeTruncatedNormalDistFactor(alpha, beta); |
| |
| return mean + factor * sd; |
| } |
| |
| protected static double computeTruncatedNormalDistFactor(final @Nullable Double alpha, final @Nullable Double beta) { |
| // Standard normal distribution (mean = 0, sd = 1) |
| NormalDistribution normDist = new NormalDistribution(null, 0, 1); |
| |
| // values are initialized for a range from negative infinity to infinity (no |
| // truncation) |
| double pdfAlpha = 0.0; |
| double cdfAlpha = 0.0; |
| double pdfBeta = 0.0; |
| double cdfBeta = 1.0; |
| |
| if (alpha != null) { // truncated from below |
| pdfAlpha = normDist.density(alpha); |
| cdfAlpha = normDist.cumulativeProbability(alpha); |
| } |
| if (beta != null) { // truncated from above |
| pdfBeta = normDist.density(beta); |
| cdfBeta = normDist.cumulativeProbability(beta); |
| } |
| |
| return (pdfAlpha - pdfBeta) / (cdfBeta - cdfAlpha); |
| } |
| |
| public static Time getAverageOfBetaDistribution(final @NonNull Time a, final @NonNull Time b, final double alpha, final double beta) { |
| checkTimeArgument(a); |
| checkTimeArgument(b); |
| checkArgument(a.compareTo(b) <= 0, ARG_BOUNDS_MESSAGE); |
| checkArgument(alpha > 0, ARG_POSITIVE_VALUE_MESSAGE); |
| checkArgument(beta > 0, ARG_POSITIVE_VALUE_MESSAGE); |
| |
| double ratio = 1.0 / (1.0 + (beta / alpha)); // mean in interval [0,1] is 1 / (1 + (beta/alpha)) |
| return addTime(a, multiply(subtractTime(b, a), ratio)); |
| } |
| |
| public static Double getAverageOfBetaDistribution(final @NonNull Number inputA, final @NonNull Number inputB, final double alpha, final double beta) { |
| checkArgument(inputA != null, ARG_NULL_MESSAGE, NUMBER); |
| checkArgument(inputB != null, ARG_NULL_MESSAGE, NUMBER); |
| double a = inputA.doubleValue(); |
| double b = inputB.doubleValue(); |
| checkArgument(a <= b, ARG_BOUNDS_MESSAGE); |
| checkArgument(alpha > 0, ARG_POSITIVE_VALUE_MESSAGE); |
| checkArgument(beta > 0, ARG_POSITIVE_VALUE_MESSAGE); |
| |
| double ratio = 1.0 / (1.0 + (beta / alpha)); // mean in interval [0,1] is 1 / (1 + (beta/alpha)) |
| return a + (b - a) * ratio; |
| } |
| |
| |
| public static EList<QualifiedPort> getInnerPorts(final @NonNull ISystem system) { |
| checkArgument(system != null, ARG_NULL_MESSAGE, "ISystem"); |
| |
| List<QualifiedPort> qualifiedPorts = new ArrayList<>(); |
| for (ComponentInstance inst : system.getComponentInstances()) { |
| if (inst.getType() != null) { |
| for (ComponentPort port : inst.getType().getPorts()) { |
| QualifiedPort qp = AmaltheaFactory.eINSTANCE.createQualifiedPort(); |
| qp.setInstance(inst); |
| qp.setPort(port); |
| qualifiedPorts.add(qp); |
| } |
| } |
| } |
| |
| @SuppressWarnings("null") |
| final @NonNull EReference eReference = AmaltheaPackage.eINSTANCE.getISystem_InnerPorts(); |
| return unmodifiableEcoreEList(system, eReference, qualifiedPorts); |
| } |
| |
| public static EList<HwPort> getInnerPorts(final @NonNull HwStructure struct) { |
| checkArgument(struct != null, ARG_NULL_MESSAGE, "HwStructure"); |
| |
| List<HwPort> ports = new ArrayList<>(); |
| for (HwStructure subStruct : struct.getStructures()) { |
| ports.addAll(subStruct.getPorts()); |
| } |
| for (HwModule module : getAllModules(struct)) { |
| ports.addAll(module.getPorts()); |
| } |
| |
| @SuppressWarnings("null") |
| final @NonNull EReference eReference = AmaltheaPackage.eINSTANCE.getHwStructure_InnerPorts(); |
| return unmodifiableEcoreEList(struct, eReference, ports); |
| } |
| |
| public static EList<HwModule> getAllModules(final @NonNull HwStructure struct) { |
| checkArgument(struct != null, ARG_NULL_MESSAGE, "HwStructure"); |
| |
| List<HwModule> moduleList = new ArrayList<>(); |
| for (HwModule module : struct.getModules()) { |
| moduleList.add(module); |
| if (module instanceof ProcessingUnit) { |
| moduleList.addAll(((ProcessingUnit) module).getCaches()); |
| } |
| } |
| return unmodifiableEList(moduleList); |
| } |
| |
| private static <T> EList<T> unmodifiableEcoreEList(final @NonNull EObject eObject, final @NonNull EReference eReference, |
| final @NonNull List<? extends T> result) { |
| final int size = result.size(); |
| final Object[] values = result.toArray(); |
| return new EcoreEList.UnmodifiableEList<>((InternalEObject) eObject, eReference, size, values); |
| } |
| |
| private static <T> EList<T> unmodifiableEList(final @NonNull List<? extends T> list) { |
| if (list.isEmpty()) { |
| return ECollections.emptyEList(); |
| } else { |
| return ECollections.unmodifiableEList(list); |
| } |
| } |
| |
| } |