Search code examples
clojureclojure-core.logic

Minimize/maximize possible in clojure / core.logic?


I'm looking for an idiomatic constraint satisfaction solver that can maximize or minimize a goal function, rather than producing a list of matching solutions.

To be precise, I'm more interested in minimization (e.g., of gasoline consumption on a route that must also satisfy other constraints), but the question is:

I'm currently looking at core.logic and am under the impression that the module will not do either max or min. As far as I understand, that functionality would usually be specifically denoted as CLP. Core.logic does mention CLP(FD) (https://github.com/clojure/core.logic/wiki/Features), but looking at the description, I keep having serious doubts.

Could someone please comment on this - as my going through the entire Reasoned Schemer book would be too much, I guess?


Solution

  • The original question is not very specific about what kind optimization problem it wants to solve. Usually, the type of optimization problem will determine which solver is adequate.

    However, many optimization problems that arise in engineering consist of objective functions with linear and quadratic terms, linear constraints, real and integer variables. The ojAlgo library is great for those problems. For example, if we want to minimize f(x, y) = x + 2y with x and y being integers, and three linear constraints x >= 2, y >= 3 and x + y >= 14.2, here is how to solve this problem using ojAlgo in Clojure:

    (ns playground.ojalgo
      (:import [org.ojalgo.optimisation ExpressionsBasedModel]))
    
    (defn demo []
      (let [model (ExpressionsBasedModel.)
            ;; Declare variables
    
            ;; X has lower limit 2
            x (-> (.addVariable model)
                  (.lower 2)
                  (.integer true))
    
            ;; Y has lower limit 3
            y (-> (.addVariable model)
                  (.lower 3)
                  (.integer true))]
    
        ;; Objective function: Minimize x + 2y
        (-> (.addExpression model)
            (.set x 1.0)
            (.set y 2.0)
            (.weight 1.0)) ;; <-- Terms in the objective function
                           ;;     need a weight.
    
        ;; Linear constraint: x + y >= 14.2
        (-> (.addExpression model)
            (.set x 1.0)
            (.set y 1.0)
            (.lower 14.2))
    
        (let [result (.minimise model)]
          (println "Result" result)
          (println "Objective function value: " (.getValue result))
          (println "Optimal X value: " (.getValue x))
          (println "Optimal Y value: " (.getValue y)))))
    

    Which will display

    Result #object[org.ojalgo.optimisation.Optimisation$Result 0xb755873 OPTIMAL 18.0 @ { 12, 3 }]
    Objective function value:  18.0
    Optimal X value:  12M
    Optimal Y value:  3M
    

    Chances are your problem (vaguely worded as "gasoline consumption on a route that must also satisfy other constraints") can be expressed in a format that this solver can handle. But with no more details, it is hard to provide a more accurate answer than this.

    To use ojAlgo, you need to add the [org.ojalgo/ojalgo "48.1.0"] dependency to your Leiningen project.clj.