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

fuookami.ospf.kotlin.framework.solver.ParallelCombinatorialLinearSolver.kt Maven / Gradle / Ivy

There is a newer version: 1.0.31
Show newest version
package fuookami.ospf.kotlin.framework.solver

import kotlinx.coroutines.*
import org.apache.logging.log4j.kotlin.*
import fuookami.ospf.kotlin.utils.math.*
import fuookami.ospf.kotlin.utils.error.*
import fuookami.ospf.kotlin.utils.functional.*
import fuookami.ospf.kotlin.core.frontend.model.*
import fuookami.ospf.kotlin.core.frontend.model.mechanism.*
import fuookami.ospf.kotlin.core.backend.intermediate_model.*
import fuookami.ospf.kotlin.core.backend.solver.*
import fuookami.ospf.kotlin.core.backend.solver.output.*

class ParallelCombinatorialLinearSolver(
    private val solvers: List>,
    private val mode: ParallelCombinatorialMode = ParallelCombinatorialMode.Best
): LinearSolver {
    private val logger = logger()

    companion object {
        @JvmName("constructBySolvers")
        operator fun invoke(
            solvers: Iterable,
            mode: ParallelCombinatorialMode = ParallelCombinatorialMode.Best
        ): ParallelCombinatorialLinearSolver {
            return ParallelCombinatorialLinearSolver(solvers.map { lazy { it } }, mode)
        }

        @JvmName("constructBySolverExtractors")
        operator fun invoke(
            solvers: Iterable<() -> LinearSolver>,
            mode: ParallelCombinatorialMode = ParallelCombinatorialMode.Best
        ): ParallelCombinatorialLinearSolver {
            return ParallelCombinatorialLinearSolver(solvers.map { lazy { it() } }, mode)
        }
    }

    override val name by lazy { "ParallelCombinatorial(${solvers.joinToString(",") { it.value.name }})" }

    override suspend fun invoke(model: LinearTriadModelView): Ret {
        return when (mode) {
            ParallelCombinatorialMode.First -> {
                var result: SolverOutput? = null
                val lock = Any()
                try {
                    coroutineScope {
                        val promises = solvers.map {
                            launch(Dispatchers.Default) {
                                when (val ret = it.value.invoke(model)) {
                                    is Ok -> {
                                        logger.info { "Solver ${it.value.name} found a solution." }
                                        synchronized(lock) {
                                            result = ret.value
                                            cancel()
                                        }
                                    }

                                    is Failed -> {
                                        logger.warn { "Solver ${it.value.name} failed with error ${ret.error.code}: ${ret.error.message}" }
                                    }
                                }
                            }
                        }
                        promises.forEach { it.join() }
                        if (result != null) {
                            Ok(result!!)
                        } else {
                            Failed(ErrorCode.SolverNotFound, "No solver valid.")
                        }
                    }
                } catch (e: Exception) {
                    if (result != null) {
                        Ok(result!!)
                    } else {
                        Failed(ErrorCode.OREngineSolvingException)
                    }
                }
            }

            ParallelCombinatorialMode.Best -> {
                coroutineScope {
                    val promises = solvers.map {
                        async(Dispatchers.Default) {
                            val result = it.value.invoke(model)
                            when (result) {
                                is Ok -> {
                                    logger.info { "Solver ${it.value.name} found a solution." }
                                }

                                is Failed -> {
                                    logger.warn { "Solver ${it.value.name} failed with error ${result.error.code}: ${result.error.message}" }
                                }
                            }
                            result
                        }
                    }
                    val results = promises.map { it.await() }
                    val successResults = results.mapNotNull {
                        when (it) {
                            is Ok -> {
                                it.value
                            }

                            is Failed -> {
                                null
                            }
                        }
                    }
                    if (successResults.isNotEmpty()) {
                        val bestResult = when (model.objective.category) {
                            ObjectCategory.Minimum -> {
                                successResults.minBy { it.obj }
                            }

                            ObjectCategory.Maximum -> {
                                successResults.maxBy { it.obj }
                            }
                        }
                        Ok(bestResult)
                    } else {
                        Failed(ErrorCode.SolverNotFound, "No solver valid.")
                    }
                }
            }
        }
    }

    override suspend fun invoke(model: LinearTriadModelView, solutionAmount: UInt64): Ret>> {
        return when (mode) {
            ParallelCombinatorialMode.First -> {
                var result: Pair>? = null
                val lock = Any()
                try {
                    coroutineScope {
                        val promises = solvers.map {
                            launch(Dispatchers.Default) {
                                when (val ret = it.value.invoke(model, solutionAmount)) {
                                    is Ok -> {
                                        logger.info { "Solver ${it.value.name} found a solution." }
                                        synchronized(lock) {
                                            result = ret.value
                                            cancel()
                                        }
                                    }

                                    is Failed -> {
                                        logger.warn { "Solver ${it.value.name} failed with error ${ret.error.code}: ${ret.error.message}" }
                                    }
                                }
                            }
                        }
                        promises.forEach { it.join() }
                        if (result != null) {
                            Ok(result!!)
                        } else {
                            Failed(ErrorCode.SolverNotFound, "No solver valid.")
                        }
                    }
                } catch (e: Exception) {
                    if (result != null) {
                        Ok(result!!)
                    } else {
                        Failed(ErrorCode.OREngineSolvingException)
                    }
                }
            }

            ParallelCombinatorialMode.Best -> {
                coroutineScope {
                    val promises = solvers.map {
                        async(Dispatchers.Default) {
                            val result = it.value.invoke(model, solutionAmount)
                            when (result) {
                                is Ok -> {
                                    logger.info { "Solver ${it.value.name} found a solution." }
                                }

                                is Failed -> {
                                    logger.warn { "Solver ${it.value.name} failed with error ${result.error.code}: ${result.error.message}" }
                                }
                            }
                            result
                        }
                    }
                    val results = promises.map { it.await() }
                    val successResults = results.mapNotNull {
                        when (it) {
                            is Ok -> {
                                it.value
                            }

                            is Failed -> {
                                null
                            }
                        }
                    }
                    if (successResults.isNotEmpty()) {
                        val bestResult = when (model.objective.category) {
                            ObjectCategory.Minimum -> {
                                successResults.minBy { it.first.obj }
                            }

                            ObjectCategory.Maximum -> {
                                successResults.maxBy { it.first.obj }
                            }
                        }
                        Ok(bestResult)
                    } else {
                        Failed(ErrorCode.SolverNotFound, "No solver valid.")
                    }
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy