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.*
import fuookami.ospf.kotlin.utils.math.value_range.*

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"]!!),
            Interval.valueOf(element["lowerInterval"]!!.jsonPrimitive.content.replaceFirstChar {
                if (it.isLowerCase()) it.titlecase(
                    Locale.getDefault()
                ) else it.toString()
            }),
            Interval.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: Interval,
    val upperInterval: Interval,
    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: Interval = Interval.Closed,
            upperInterval: Interval = Interval.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: Interval,
            upperInterval: Interval,
            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: Interval = Interval.Closed
        ): ValueRange where T : RealNumber, T : NumberField {
            val constants = (T::class.companionObjectInstance!! as RealNumberConstants)
            return ValueRange(
                ValueWrapper.NegativeInfinity(constants),
                ValueWrapper.Value(upperBound, constants),
                Interval.Open,
                upperInterval,
                constants
            )
        }

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

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

        operator fun  invoke(
            lowerBound: T,
            _inf: GlobalInfinity,
            lowerInterval: Interval,
            constants: RealNumberConstants
        ): ValueRange where T : RealNumber, T : NumberField {
            return ValueRange(
                ValueWrapper.Value(lowerBound, constants),
                ValueWrapper.Infinity(constants),
                lowerInterval,
                Interval.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),
                Interval.Open,
                Interval.Open,
                constants
            )
        }

        operator fun  invoke(
            constants: RealNumberConstants
        ): ValueRange where T : RealNumber, T : NumberField {
            return ValueRange(
                ValueWrapper.NegativeInfinity(constants),
                ValueWrapper.Infinity(constants),
                Interval.Open,
                Interval.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 == Interval.Closed
                && upperInterval == Interval.Closed
                && !lowerBound.isInfinityOrNegativeInfinity
                && !upperBound.isInfinityOrNegativeInfinity
                && lowerBound eq upperBound
    }

    val empty by lazy {
        if (lowerInterval == Interval.Closed && upperInterval == Interval.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) {
            Interval.Open -> lowerBound ls wrapper
            Interval.Closed -> lowerBound leq wrapper
        } && when (upperInterval) {
            Interval.Open -> upperBound gr wrapper
            Interval.Closed -> upperBound geq wrapper
        }
    }

    operator fun contains(value: ValueRange): Boolean {
        return when (lowerInterval) {
            Interval.Open -> lowerBound ls value.lowerBound
            Interval.Closed -> lowerBound leq value.lowerBound
        } && when (upperInterval) {
            Interval.Open -> upperBound gr value.upperBound
            Interval.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.toFlt64() neq other._lowerBound.toFlt64()) return false
        if (_upperBound.toFlt64() neq other._upperBound.toFlt64()) 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