All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fuookami.ospf.kotlin.utils.math.ValueRange.kt Maven / Gradle / Ivy

There is a newer version: 1.0.29
Show newest version
package fuookami.ospf.kotlin.utils.math

import java.util.*
import kotlin.reflect.full.*
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.json.*
import fuookami.ospf.kotlin.utils.concept.*
import fuookami.ospf.kotlin.utils.math.ordinary.*
import fuookami.ospf.kotlin.utils.operator.*

private data object IntervalTypeSerializer : KSerializer {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("IntervalType", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: IntervalType) {
        encoder.encodeString(value.toString().lowercase(Locale.getDefault()))
    }

    override fun deserialize(decoder: Decoder): IntervalType {
        return IntervalType.valueOf(decoder.decodeString()
            .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() })
    }
}

@Serializable(with = IntervalTypeSerializer::class)
enum class IntervalType {
    Open {
        override val lowerSign = "("
        override val upperSign = ")"
        override fun union(rhs: IntervalType) = rhs
        override fun intersect(rhs: IntervalType) = Open
    },
    Closed {
        override val lowerSign = "["
        override val upperSign = "]"
        override fun union(rhs: IntervalType) = Closed
        override fun intersect(rhs: IntervalType) = rhs
    };

    abstract val lowerSign: String
    abstract val upperSign: String
    abstract infix fun union(rhs: IntervalType): IntervalType
    abstract infix fun intersect(rhs: IntervalType): IntervalType
}

private typealias GlobalInfinity = Infinity
private typealias GlobalNegativeInfinity = NegativeInfinity

class ValueWrapperSerializer(
    private val valueSerializer: KSerializer,
    internal val constants: RealNumberConstants
) : KSerializer> where T : RealNumber, T : NumberField {
    companion object {
        @Suppress("UNCHECKED_CAST")
        @OptIn(InternalSerializationApi::class)
        inline operator fun  invoke(): ValueWrapperSerializer where T : RealNumber, T : NumberField {
            val serializer = T::class.serializer()
            val constants = (T::class.companionObjectInstance!! as RealNumberConstants)
            return ValueWrapperSerializer(serializer, constants)
        }
    }

    @OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
    override val descriptor: SerialDescriptor = buildSerialDescriptor("ValueWrapper", PolymorphicKind.SEALED) {
        element("Value", valueSerializer.descriptor)
        element("Infinity", PrimitiveSerialDescriptor("Infinity", PrimitiveKind.DOUBLE))
        element("NegativeInfinity", PrimitiveSerialDescriptor("NegativeInfinity", PrimitiveKind.DOUBLE))
    }

    override fun serialize(encoder: Encoder, value: ValueWrapper) {
        require(encoder is JsonEncoder)
        val element = when (value) {
            is ValueWrapper.Value -> encoder.json.encodeToJsonElement(valueSerializer, value.value)
            is ValueWrapper.Infinity -> encoder.json.encodeToJsonElement(Double.POSITIVE_INFINITY)
            is ValueWrapper.NegativeInfinity -> encoder.json.encodeToJsonElement(Double.NEGATIVE_INFINITY)
        }
        encoder.encodeJsonElement(element)
    }

    override fun deserialize(decoder: Decoder): ValueWrapper {
        require(decoder is JsonDecoder)
        val element = decoder.decodeJsonElement()
        return when (element.jsonPrimitive.doubleOrNull) {
            Double.POSITIVE_INFINITY -> {
                ValueWrapper.Infinity(constants)
            }

            Double.NEGATIVE_INFINITY -> {
                ValueWrapper.NegativeInfinity(constants)
            }

            else -> {
                ValueWrapper.Value(decoder.json.decodeFromJsonElement(valueSerializer, element), constants)
            }
        }
    }
}

sealed class ValueWrapper(
    val constants: RealNumberConstants
) : Cloneable, Copyable>, Ord>, Eq>,
    Plus, ValueWrapper>, Minus, ValueWrapper>,
    Times, ValueWrapper>, Div, ValueWrapper>
        where T : RealNumber, T : NumberField {
    companion object {
        @Throws(IllegalArgumentException::class)
        @Suppress("UNCHECKED_CAST")
        inline operator fun  invoke(
            value: T
        ): ValueWrapper where T : RealNumber, T : NumberField {
            val constants = (T::class.companionObjectInstance!! as RealNumberConstants)
            return when (value) {
                constants.infinity -> Infinity(constants)
                constants.negativeInfinity -> NegativeInfinity(constants)
                constants.nan -> throw IllegalArgumentException("Illegal argument NaN for value range!!!")
                else -> Value(value, constants)
            }
        }

        @Suppress("UNCHECKED_CAST")
        inline operator fun  invoke(
            _inf: GlobalInfinity
        ): ValueWrapper where T : RealNumber, T : NumberField {
            val constants = (T::class.companionObjectInstance!! as RealNumberConstants)
            return Infinity(constants)
        }

        @Suppress("UNCHECKED_CAST")
        inline operator fun  invoke(
            _negInf: GlobalNegativeInfinity
        ): ValueWrapper where T : RealNumber, T : NumberField {
            val constants = (T::class.companionObjectInstance!! as RealNumberConstants)
            return NegativeInfinity(constants)
        }
    }

    val isInfinity get() = this is Infinity
    val isNegativeInfinity get() = this is NegativeInfinity
    val isInfinityOrNegativeInfinity by lazy { isInfinity && isNegativeInfinity }

    abstract operator fun plus(rhs: T): ValueWrapper
    abstract operator fun minus(rhs: T): ValueWrapper
    abstract operator fun times(rhs: T): ValueWrapper
    abstract operator fun div(rhs: T): ValueWrapper

    abstract fun toFlt64(): Flt64

    fun unwrap(): T {
        return (this as Value).value
    }

    fun unwrapOrNull(): T? {
        return when (this) {
            is Value -> {
                this.value
            }

            is Infinity -> {
                constants.infinity
            }

            is NegativeInfinity -> {
                constants.negativeInfinity
            }
        }
    }

    class Value(val value: T, constants: RealNumberConstants) :
        ValueWrapper(constants) where T : RealNumber, T : NumberField {
        init {
            assert(value != constants.infinity)
            assert(value != constants.negativeInfinity)
            assert(value != constants.nan)
        }

        override fun copy() = Value(value.copy(), constants)
        public override fun clone() = copy()

        override fun partialEq(rhs: ValueWrapper): Boolean = when (rhs) {
            is Value -> value.eq(rhs.value)
            else -> false
        }

        override fun partialOrd(rhs: ValueWrapper) = when (rhs) {
            is Value -> value.ord(rhs.value)
            is Infinity -> orderOf(-1)
            is NegativeInfinity -> orderOf(1)
        }

        override fun plus(rhs: T): ValueWrapper = Value(value + rhs, constants)
        override fun plus(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> Value(value + rhs.value, constants)
            is Infinity -> Infinity(constants)
            is NegativeInfinity -> NegativeInfinity(constants)
        }

        override fun minus(rhs: T): ValueWrapper = Value(value - rhs, constants)
        override fun minus(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> Value(value - rhs.value, constants)
            is Infinity -> NegativeInfinity(constants)
            is NegativeInfinity -> Infinity(constants)
        }

        override fun times(rhs: T): ValueWrapper = Value(value * rhs, constants)
        override fun times(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> Value(value * rhs.value, constants)
            is Infinity -> if (value < constants.zero) {
                NegativeInfinity(constants)
            } else if (value > constants.zero) {
                Infinity(constants)
            } else {
                Value(constants.zero, constants)
            }

            is NegativeInfinity -> if (value < constants.zero) {
                Infinity(constants)
            } else if (value > constants.zero) {
                NegativeInfinity(constants)
            } else {
                Value(constants.zero, constants)
            }
        }

        override fun div(rhs: T): ValueWrapper = Value(value / rhs, constants)
        override fun div(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> Value(value / rhs.value, constants)
            is Infinity -> if (value < constants.zero) {
                Value(-constants.epsilon, constants)
            } else if (value > constants.zero) {
                Value(constants.epsilon, constants)
            } else {
                Value(constants.zero, constants)
            }

            is NegativeInfinity -> if (value < constants.zero) {
                Value(constants.epsilon, constants)
            } else if (value > constants.zero) {
                Value(-constants.epsilon, constants)
            } else {
                Value(constants.zero, constants)
            }
        }

        override fun toString() = "$value"
        override fun toFlt64() = value.toFlt64()
    }

    class Infinity(constants: RealNumberConstants) :
        ValueWrapper(constants) where T : RealNumber, T : NumberField {
        override fun copy() = Infinity(constants)
        public override fun clone() = copy()

        override fun partialEq(rhs: ValueWrapper): Boolean = rhs is Infinity
        override fun partialOrd(rhs: ValueWrapper) = when (rhs) {
            is Infinity -> orderOf(0)
            else -> orderOf(1)
        }

        @Throws(IllegalArgumentException::class)
        override fun plus(rhs: T): ValueWrapper = when (rhs) {
            rhs.constants.nan -> throw IllegalArgumentException("Invalid plus between inf and nan!!!")
            rhs.constants.negativeInfinity -> throw IllegalArgumentException("Invalid plus between inf and -inf!!!")
            else -> Infinity(constants)
        }

        @Throws(IllegalArgumentException::class)
        override fun plus(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> Infinity(constants)
            is Infinity -> Infinity(constants)
            is NegativeInfinity -> throw IllegalArgumentException("Invalid plus between inf and -inf!!!")
        }

        @Throws(IllegalArgumentException::class)
        override fun minus(rhs: T): ValueWrapper = when (rhs) {
            rhs.constants.nan -> throw IllegalArgumentException("Invalid minus between inf and nan!!!")
            rhs.constants.infinity -> throw IllegalArgumentException("Invalid minus between inf and inf!!!")
            else -> Infinity(constants)
        }

        @Throws(IllegalArgumentException::class)
        override fun minus(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> Infinity(constants)
            is Infinity -> throw IllegalArgumentException("Invalid minus between inf and inf!!!")
            is NegativeInfinity -> Infinity(constants)
        }

        @Throws(IllegalArgumentException::class)
        override fun times(rhs: T): ValueWrapper = when (rhs) {
            rhs.constants.nan -> throw IllegalArgumentException("Invalid times between inf and nan!!!")
            rhs.constants.negativeInfinity -> NegativeInfinity(constants)
            rhs.constants.infinity -> Infinity(constants)
            rhs.constants.zero -> Value(constants.zero, constants)
            else -> if (rhs < rhs.constants.zero) {
                NegativeInfinity(constants)
            } else {
                Infinity(constants)
            }
        }

        @Throws(IllegalArgumentException::class)
        override fun times(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> if (rhs.value < rhs.constants.zero) {
                NegativeInfinity(constants)
            } else if (rhs.value > rhs.constants.zero) {
                Infinity(constants)
            } else {
                Value(constants.zero, constants)
            }

            is Infinity -> Infinity(constants)
            is NegativeInfinity -> NegativeInfinity(constants)
        }

        @Throws(IllegalArgumentException::class)
        override fun div(rhs: T): ValueWrapper = when (rhs) {
            rhs.constants.nan -> throw IllegalArgumentException("Invalid div between inf and nan!!!")
            rhs.constants.infinity -> throw IllegalArgumentException("Invalid div between inf and inf!!!")
            rhs.constants.negativeInfinity -> throw IllegalArgumentException("Invalid div between inf and -inf!!!")
            rhs.constants.zero -> throw IllegalArgumentException("Invalid div between inf and 0!!!")
            else -> if (rhs < rhs.constants.zero) {
                NegativeInfinity(constants)
            } else {
                Infinity(constants)
            }
        }

        @Throws(IllegalArgumentException::class)
        override fun div(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> if (rhs.value < rhs.constants.zero) {
                NegativeInfinity(constants)
            } else if (rhs.value > rhs.constants.zero) {
                Infinity(constants)
            } else {
                throw IllegalArgumentException("Invalid div between inf and 0!!!")
            }

            is Infinity -> throw IllegalArgumentException("Invalid div between inf and inf!!!")
            is NegativeInfinity -> throw IllegalArgumentException("Invalid div between inf and -inf!!!")
        }

        override fun toString() = "inf"
        override fun toFlt64() = Flt64.infinity
    }

    class NegativeInfinity(constants: RealNumberConstants) :
        ValueWrapper(constants) where T : RealNumber, T : NumberField {
        override fun copy() = Infinity(constants)
        public override fun clone() = copy()

        override fun partialEq(rhs: ValueWrapper): Boolean = rhs is NegativeInfinity
        override fun partialOrd(rhs: ValueWrapper) = when (rhs) {
            is NegativeInfinity -> orderOf(0)
            else -> orderOf(-1)
        }

        @Throws(IllegalArgumentException::class)
        override fun plus(rhs: T): ValueWrapper = when (rhs) {
            rhs.constants.nan -> throw IllegalArgumentException("Invalid plus between inf and nan!!!")
            rhs.constants.infinity -> throw IllegalArgumentException("Invalid plus between -inf and inf!!!")
            else -> NegativeInfinity(constants)
        }

        @Throws(IllegalArgumentException::class)
        override fun plus(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> NegativeInfinity(constants)
            is Infinity -> throw IllegalArgumentException("Invalid plus between -inf and inf!!!")
            is NegativeInfinity -> NegativeInfinity(constants)
        }

        @Throws(IllegalArgumentException::class)
        override fun minus(rhs: T): ValueWrapper = when (rhs) {
            rhs.constants.nan -> throw IllegalArgumentException("Invalid minus between -inf and nan!!!")
            rhs.constants.negativeInfinity -> throw IllegalArgumentException("Invalid minus between -inf and -inf!!!")
            else -> NegativeInfinity(constants)
        }

        @Throws(IllegalArgumentException::class)
        override fun minus(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> NegativeInfinity(constants)
            is Infinity -> NegativeInfinity(constants)
            is NegativeInfinity -> throw IllegalArgumentException("Invalid minus between -inf and -inf!!!")
        }

        @Throws(IllegalArgumentException::class)
        override fun times(rhs: T): ValueWrapper = when (rhs) {
            rhs.constants.nan -> throw IllegalArgumentException("Invalid times between -inf and nan!!!")
            rhs.constants.negativeInfinity -> Infinity(constants)
            rhs.constants.infinity -> NegativeInfinity(constants)
            rhs.constants.zero -> Value(constants.zero, constants)
            else -> if (rhs < rhs.constants.zero) {
                Infinity(constants)
            } else {
                NegativeInfinity(constants)
            }
        }

        @Throws(IllegalArgumentException::class)
        override fun times(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> if (rhs.value < rhs.constants.zero) {
                Infinity(constants)
            } else if (rhs.value > rhs.constants.zero) {
                NegativeInfinity(constants)
            } else {
                Value(constants.zero, constants)
            }

            is Infinity -> NegativeInfinity(constants)
            is NegativeInfinity -> Infinity(constants)
        }

        @Throws(IllegalArgumentException::class)
        override fun div(rhs: T): ValueWrapper = when (rhs) {
            rhs.constants.nan -> throw IllegalArgumentException("Invalid div between -inf and nan!!!")
            rhs.constants.negativeInfinity -> throw IllegalArgumentException("Invalid div between -inf and -inf!!!")
            rhs.constants.infinity -> throw IllegalArgumentException("Invalid div between -inf and inf!!!")
            rhs.constants.zero -> throw IllegalArgumentException("Invalid div between -inf and 0!!!")
            else -> if (rhs < rhs.constants.zero) {
                Infinity(constants)
            } else {
                NegativeInfinity(constants)
            }
        }

        @Throws(IllegalArgumentException::class)
        override fun div(rhs: ValueWrapper): ValueWrapper = when (rhs) {
            is Value -> if (rhs.value < rhs.constants.zero) {
                Infinity(constants)
            } else if (rhs.value > rhs.constants.zero) {
                NegativeInfinity(constants)
            } else {
                throw IllegalArgumentException("Invalid div between -inf and 0!!!")
            }

            is Infinity -> throw IllegalArgumentException("Invalid div between -inf and inf!!!")
            is NegativeInfinity -> throw IllegalArgumentException("Invalid div between -inf and -inf!!!")
        }

        override fun toString() = "-inf"
        override fun toFlt64() = Flt64.negativeInfinity
    }
}

open class ValueRangeSerializer(
    private val valueSerializer: ValueWrapperSerializer
) : KSerializer> where T : RealNumber, T : NumberField {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("ValueRange") {
        element("lowerBound")
        element("upperBound")
        element("lowerInterval")
        element("upperInterval")
    }

    override fun serialize(encoder: Encoder, value: ValueRange) {
        require(encoder is JsonEncoder)
        encoder.encodeJsonElement(
            buildJsonObject {
                put("lowerBound", encoder.json.encodeToJsonElement(valueSerializer, value.lowerBound))
                put("upperBound", encoder.json.encodeToJsonElement(valueSerializer, value.upperBound))
                put("lowerInterval", value.lowerInterval.toString().lowercase(Locale.getDefault()))
                put("upperInterval", value.upperInterval.toString().lowercase(Locale.getDefault()))
            }
        )
    }

    @OptIn(ExperimentalSerializationApi::class)
    override fun deserialize(decoder: Decoder): ValueRange {
        require(decoder is JsonDecoder)
        val element = decoder.decodeJsonElement()
        require(element is JsonObject)
        require(descriptor.elementNames.all { it in element })
        return ValueRange(
            decoder.json.decodeFromJsonElement(valueSerializer, element["lowerBound"]!!),
            decoder.json.decodeFromJsonElement(valueSerializer, element["upperBound"]!!),
            IntervalType.valueOf(element["lowerInterval"]!!.jsonPrimitive.content.replaceFirstChar {
                if (it.isLowerCase()) it.titlecase(
                    Locale.getDefault()
                ) else it.toString()
            }),
            IntervalType.valueOf(element["upperInterval"]!!.jsonPrimitive.content.replaceFirstChar {
                if (it.isLowerCase()) it.titlecase(
                    Locale.getDefault()
                ) else it.toString()
            }),
            valueSerializer.constants
        )
    }
}

data object ValueRangeInt64Serializer : ValueRangeSerializer(ValueWrapperSerializer())
data object ValueRangeUInt64Serializer : ValueRangeSerializer(ValueWrapperSerializer())
data object ValueRangeFlt64Serializer : ValueRangeSerializer(ValueWrapperSerializer())

// todo: Bound

data class ValueRange(
    private val _lowerBound: ValueWrapper,
    private val _upperBound: ValueWrapper,
    val lowerInterval: IntervalType,
    val upperInterval: IntervalType,
    private val constants: RealNumberConstants
) : Cloneable, Copyable>,
    Plus, ValueRange>, Minus, ValueRange>,
    Times, ValueRange>, Div>, Eq>
        where T : RealNumber, T : NumberField {

    companion object {
        @Suppress("UNCHECKED_CAST")
        inline operator fun  invoke(
            lowerBound: T,
            upperBound: T,
            lowerInterval: IntervalType = IntervalType.Closed,
            upperInterval: IntervalType = IntervalType.Closed
        ): ValueRange where T : RealNumber, T : NumberField {
            val constants = (T::class.companionObjectInstance!! as RealNumberConstants)
            return ValueRange(
                ValueWrapper.Value(lowerBound, constants),
                ValueWrapper.Value(upperBound, constants),
                lowerInterval,
                upperInterval,
                constants
            )
        }

        operator fun  invoke(
            lowerBound: T,
            upperBound: T,
            lowerInterval: IntervalType,
            upperInterval: IntervalType,
            constants: RealNumberConstants
        ): ValueRange where T : RealNumber, T : NumberField {
            return ValueRange(
                ValueWrapper.Value(lowerBound, constants),
                ValueWrapper.Value(upperBound, constants),
                lowerInterval,
                upperInterval,
                constants
            )
        }

        @Suppress("UNCHECKED_CAST")
        inline operator fun  invoke(
            _inf: GlobalNegativeInfinity,
            upperBound: T,
            upperInterval: IntervalType = IntervalType.Closed
        ): ValueRange where T : RealNumber, T : NumberField {
            val constants = (T::class.companionObjectInstance!! as RealNumberConstants)
            return ValueRange(
                ValueWrapper.NegativeInfinity(constants),
                ValueWrapper.Value(upperBound, constants),
                IntervalType.Open,
                upperInterval,
                constants
            )
        }

        operator fun  invoke(
            _inf: GlobalNegativeInfinity,
            upperBound: T,
            upperInterval: IntervalType,
            constants: RealNumberConstants
        ): ValueRange where T : RealNumber, T : NumberField {
            return ValueRange(
                ValueWrapper.NegativeInfinity(constants),
                ValueWrapper.Value(upperBound, constants),
                IntervalType.Open,
                upperInterval,
                constants
            )
        }

        @Suppress("UNCHECKED_CAST")
        inline operator fun  invoke(
            lowerBound: T,
            _inf: GlobalInfinity,
            lowerInterval: IntervalType = IntervalType.Closed
        ): ValueRange where T : RealNumber, T : NumberField {
            val constants = (T::class.companionObjectInstance!! as RealNumberConstants)
            return ValueRange(
                ValueWrapper.Value(lowerBound, constants),
                ValueWrapper.Infinity(constants),
                lowerInterval,
                IntervalType.Open,
                constants
            )
        }

        operator fun  invoke(
            lowerBound: T,
            _inf: GlobalInfinity,
            lowerInterval: IntervalType,
            constants: RealNumberConstants
        ): ValueRange where T : RealNumber, T : NumberField {
            return ValueRange(
                ValueWrapper.Value(lowerBound, constants),
                ValueWrapper.Infinity(constants),
                lowerInterval,
                IntervalType.Open,
                constants
            )
        }

        @Suppress("UNCHECKED_CAST")
        inline operator fun  invoke(): ValueRange where T : RealNumber, T : NumberField {
            val constants = (T::class.companionObjectInstance!! as RealNumberConstants)
            return ValueRange(
                ValueWrapper.NegativeInfinity(constants),
                ValueWrapper.Infinity(constants),
                IntervalType.Open,
                IntervalType.Open,
                constants
            )
        }

        operator fun  invoke(
            constants: RealNumberConstants
        ): ValueRange where T : RealNumber, T : NumberField {
            return ValueRange(
                ValueWrapper.NegativeInfinity(constants),
                ValueWrapper.Infinity(constants),
                IntervalType.Open,
                IntervalType.Open,
                constants
            )
        }
    }

    override fun copy() = ValueRange(
        _lowerBound,
        _upperBound,
        lowerInterval,
        upperInterval,
        constants
    )

    public override fun clone() = copy()

    val lowerBound: ValueWrapper
        get() {
            @Throws(IllegalArgumentException::class)
            if (empty) {
                throw IllegalArgumentException("Illegal argument of value range: ${lowerInterval.lowerSign}${_lowerBound}, ${_upperBound}${upperInterval.upperSign}!!!")
            }
            return _lowerBound
        }
    val upperBound: ValueWrapper
        get() {
            @Throws(IllegalArgumentException::class)
            if (empty) {
                throw IllegalArgumentException("Illegal argument of value range: ${lowerInterval.lowerSign}${_lowerBound}, ${_upperBound}${upperInterval.upperSign}!!!")
            }
            return _upperBound
        }
    val mean: ValueWrapper
        get() {
            @Throws(IllegalArgumentException::class)
            if (empty) {
                throw IllegalArgumentException("Illegal argument of value range: ${lowerInterval.lowerSign}${_lowerBound}, ${_upperBound}${upperInterval.upperSign}!!!")
            }
            return (_lowerBound + _upperBound) / constants.two
        }

    val fixed by lazy {
        lowerInterval == IntervalType.Closed
                && upperInterval == IntervalType.Closed
                && !lowerBound.isInfinityOrNegativeInfinity
                && !upperBound.isInfinityOrNegativeInfinity
                && lowerBound eq upperBound
    }

    val empty by lazy {
        if (lowerInterval == IntervalType.Closed && upperInterval == IntervalType.Closed) {
            _lowerBound gr _upperBound
        } else {
            _lowerBound geq _upperBound
        }
    }

    val fixedValue: T? by lazy {
        if (fixed) {
            (lowerBound as ValueWrapper.Value).value
        } else {
            null
        }
    }

    operator fun contains(value: T): Boolean {
        val wrapper = ValueWrapper.Value(value, constants)
        return when (lowerInterval) {
            IntervalType.Open -> lowerBound ls wrapper
            IntervalType.Closed -> lowerBound leq wrapper
        } && when (upperInterval) {
            IntervalType.Open -> upperBound gr wrapper
            IntervalType.Closed -> upperBound geq wrapper
        }
    }

    operator fun contains(value: ValueRange): Boolean {
        return when (lowerInterval) {
            IntervalType.Open -> lowerBound ls value.lowerBound
            IntervalType.Closed -> lowerBound leq value.lowerBound
        } && when (upperInterval) {
            IntervalType.Open -> upperBound gr value.upperBound
            IntervalType.Closed -> upperBound geq value.upperBound
        }
    }

    override fun plus(rhs: ValueRange) = ValueRange(
        lowerBound + rhs.lowerBound,
        upperBound + rhs.upperBound,
        lowerInterval intersect rhs.lowerInterval,
        upperInterval intersect rhs.upperInterval,
        constants
    )

    operator fun plus(rhs: T) = ValueRange(
        lowerBound + rhs,
        upperBound + rhs,
        lowerInterval,
        upperInterval,
        constants
    )

    override fun minus(rhs: ValueRange) = ValueRange(
        lowerBound - rhs.upperBound,
        upperBound - rhs.lowerBound,
        lowerInterval intersect rhs.lowerInterval,
        upperInterval intersect rhs.upperInterval,
        constants
    )

    operator fun minus(rhs: T) = ValueRange(
        lowerBound - rhs,
        upperBound - rhs,
        lowerInterval,
        upperInterval,
        constants
    )

    override fun times(rhs: ValueRange): ValueRange {
        val bounds = listOf(
            Pair(lowerBound * rhs.lowerBound, lowerInterval intersect rhs.lowerInterval),
            Pair(lowerBound * rhs.upperBound, lowerInterval intersect rhs.upperInterval),
            Pair(upperBound * rhs.lowerBound, upperInterval intersect rhs.lowerInterval),
            Pair(upperBound * rhs.upperBound, upperInterval intersect rhs.upperInterval)
        )
        val newLowerBound = bounds.minBy { it.first }
        val newUpperBound = bounds.maxBy { it.first }
        return ValueRange(
            newLowerBound.first,
            newUpperBound.first,
            newLowerBound.second,
            newUpperBound.second,
            constants
        )
    }

    operator fun times(rhs: T) = when {
        rhs < constants.zero -> ValueRange(
            upperBound * rhs,
            lowerBound * rhs,
            lowerInterval,
            upperInterval,
            constants
        )

        else -> ValueRange(
            lowerBound * rhs,
            upperBound * rhs,
            lowerInterval,
            upperInterval,
            constants
        )
    }

    override fun div(rhs: T) = when {
        rhs < constants.zero -> ValueRange(
            upperBound / rhs,
            lowerBound / rhs,
            lowerInterval,
            upperInterval,
            constants
        )

        else -> ValueRange(
            lowerBound / rhs,
            upperBound / rhs,
            lowerInterval,
            upperInterval,
            constants
        )
    }

    override fun partialEq(rhs: ValueRange): Boolean {
        return lowerBound eq rhs.lowerBound
                && upperBound eq rhs.upperBound
                && lowerInterval == rhs.lowerInterval
                && upperInterval == rhs.upperInterval
    }

    infix fun intersect(rhs: ValueRange) = ValueRange(
        max(lowerBound, rhs.lowerBound),
        min(upperBound, rhs.upperBound),
        lowerInterval intersect rhs.lowerInterval,
        upperInterval intersect rhs.upperInterval,
        constants
    )

    fun toFlt64() = ValueRange(
        lowerBound.toFlt64(),
        upperBound.toFlt64(),
        lowerInterval,
        upperInterval
    )

    override fun toString() = "${lowerInterval.lowerSign}$lowerBound, $upperBound${upperInterval.upperSign}"

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as ValueRange<*>

        if (_lowerBound != other._lowerBound) return false
        if (_upperBound != other._upperBound) return false
        if (lowerInterval != other.lowerInterval) return false
        if (upperInterval != other.upperInterval) return false

        return true
    }

    override fun hashCode(): Int {
        var result = _lowerBound.hashCode()
        result = 31 * result + _upperBound.hashCode()
        result = 31 * result + lowerInterval.hashCode()
        result = 31 * result + upperInterval.hashCode()
        return result
    }
}

operator fun  T.times(rhs: ValueRange) where T : RealNumber, T : NumberField = rhs * this




© 2015 - 2024 Weber Informatics LLC | Privacy Policy