Created
September 26, 2021 08:22
-
-
Save jngbng/69f341f818bb6b88cecb9c364f5bcb17 to your computer and use it in GitHub Desktop.
logic programming 2 (feat. 문제적 남자)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns core-logic.core | |
(:require [clojure.core.logic :as logic] | |
[clojure.core.logic.fd :as fd])) | |
;;; 출처: https://blog.taylorwood.io/2018/05/10/clojure-logic.html | |
(defn- productsumo | |
"Sigma (vars_i * denoms_i) = sum 을 만족하는가." | |
[vars denoms sum] | |
(logic/fresh [vhead vtail | |
dhead dtail | |
product tail-sum] | |
(logic/conde ;; or 로 읽으면 된다. | |
;; vars가 빈 리스트라면, sum도 0이어야 한다. | |
[(logic/emptyo vars) (logic/== sum 0)] | |
;; 아니라면 재귀호출 | |
[;; vars의 첫번째를 vhead라 하고, 나머지를 vtail 이라 하자. | |
(logic/conso vhead vtail vars) | |
;; 마찬가지로 denoms의 첫번째를 dhead라 하고, 나머지를 dtail 이라 하자. | |
(logic/conso dhead dtail denoms) | |
;; product = vhead * dhead | |
(fd/* vhead dhead product) | |
;; tail-sum = sum - product | |
(fd/- sum product tail-sum) | |
;; tail들로 연산을 하면 tail-sum이 되어야 함. | |
(productsumo vtail dtail tail-sum)]))) | |
(defn- strictly-increasing? | |
"coll의 값들이 증가하는 순서로 정렬되어 있나? | |
forall i j, i < j -> coll[i] < coll[j]" | |
[coll] | |
(logic/everyg (fn [[i j]] | |
(fd/< i j)) | |
(partition 2 1 coll))) | |
(defn- in* | |
"lvar-coll의 범위를 모두 interval로 설정" | |
[lvar-coll interval] | |
(logic/everyg (fn [lv] | |
(fd/in lv interval)) | |
lvar-coll)) | |
(defn solution-n [num-groups] | |
(let [total-qty1 50 | |
total-qty2 30 | |
total-qty3 10 | |
min-total-qty (min total-qty1 | |
total-qty2 | |
total-qty3) | |
;; 묶음별 수량 | |
qtys (repeatedly num-groups logic/lvar) | |
;; 묶음별 가격 | |
prices (repeatedly num-groups logic/lvar) | |
;; 첫째의 묶음별 판매량 | |
sales1 (repeatedly num-groups logic/lvar) | |
;; 둘째의 묶음별 판매량 | |
sales2 (repeatedly num-groups logic/lvar) | |
;; 셋째의 묶음별 판매량 | |
sales3 (repeatedly num-groups logic/lvar)] | |
(logic/run* [q] | |
(logic/fresh [earn] | |
;; 원하는 결과값. | |
(logic/== q {:price (map (fn [qty price] | |
{:qty qty | |
:price price}) | |
qtys | |
prices) | |
:sales [sales1 | |
sales2 | |
sales3]}) | |
;; 묶음별 수량 범위: 1 <= qty <= min-total-qty | |
(in* qtys (fd/interval 1 min-total-qty)) | |
;; strictly-increasing? qty1 < qty2 < ... | |
(strictly-increasing? qtys) | |
;; 가격 범위: 적당히 설정 | |
(in* prices (fd/interval 1 30)) | |
;; 가격은 서로 다르다. | |
(fd/distinct prices) | |
;; 수식을 고려하여 가능한 범위 설정 | |
(in* sales1 (fd/interval 1 total-qty1)) | |
(in* sales2 (fd/interval 1 total-qty2)) | |
(in* sales3 (fd/interval 1 total-qty3)) | |
;; 수량 조건 | |
(productsumo sales1 qtys total-qty1) | |
(productsumo sales2 qtys total-qty2) | |
(productsumo sales3 qtys total-qty3) | |
;; 가격 조건 | |
(productsumo sales1 prices earn) | |
(productsumo sales2 prices earn) | |
(productsumo sales3 prices earn))))) | |
(first (solution-n 3)) | |
;;; returns | |
{:price ({:qty 1, :price 3} {:qty 2, :price 1} {:qty 3, :price 19}), | |
:sales [(1 23 1) (5 11 1) (2 1 2)]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment