Merge pull request #1783 from siiky/fix/lam-1296/coin-change

LAM-1296 fix: `coin-change`
This commit is contained in:
Rafael Taranto 2025-02-04 09:11:57 +00:00 committed by GitHub
commit 5dcbf7a60a
2 changed files with 10 additions and 32 deletions

View file

@ -116,14 +116,8 @@ const getSolution_old = (units, amount, mode) => {
const solver = sumService.subsetSum(billList, amount.toNumber()) const solver = sumService.subsetSum(billList, amount.toNumber())
const solution = _.countBy(Math.floor, solver.next().value) const solution = _.countBy(Math.floor, solver.next().value)
return _.reduce( return Object.entries(solution)
(acc, value) => { .map(([denomination, provisioned]) => [_.toNumber(denomination), provisioned])
acc.push({ denomination: _.toNumber(value), provisioned: solution[value] })
return acc
},
[],
_.keys(solution)
)
} }
const getSolution = (units, amount) => { const getSolution = (units, amount) => {
@ -135,24 +129,13 @@ const getSolution = (units, amount) => {
const solutionToOriginalUnits = (solution, units) => { const solutionToOriginalUnits = (solution, units) => {
const billsToAssign = (count, left) => _.clamp(0, count)(_.isNaN(left) || _.isNil(left) ? 0 : left) const billsToAssign = (count, left) => _.clamp(0, count)(_.isNaN(left) || _.isNil(left) ? 0 : left)
const billsLeft = Object.fromEntries(solution)
const billsLeft = _.flow( return units.map(
_.map(([denomination, provisioned]) => [BN(denomination), provisioned]),
_.reduce((acc, value) => {
acc[value[0]] = (acc[value[0]] || BN(0)).plus(value[1])
return acc
},
{}
)
)(solution)
return _.map(
({ count, name, denomination }) => { ({ count, name, denomination }) => {
const provisioned = billsToAssign(count, billsLeft[denomination]) const provisioned = billsToAssign(count, billsLeft[denomination])
billsLeft[denomination] -= provisioned billsLeft[denomination] -= provisioned
return { name, denomination, provisioned } return { name, denomination, provisioned }
}, }
units
) )
} }
@ -160,13 +143,13 @@ function makeChange(outCassettes, amount) {
const ss_solution = getSolution_old(outCassettes, amount, BILL_LIST_MODES.VALUE_ROUND_ROBIN) const ss_solution = getSolution_old(outCassettes, amount, BILL_LIST_MODES.VALUE_ROUND_ROBIN)
const cc_solution = getSolution(outCassettes, amount) const cc_solution = getSolution(outCassettes, amount)
if (!!ss_solution !== !!cc_solution) { if (!cc.check(cc_solution, amount.toNumber())) {
logger.error(new Error(`subset-sum and coin-change don't agree on solvability -- subset-sum:${!!ss_solution} coin-change:${!!cc_solution}`)) logger.error(new Error("coin-change provided a bad solution"))
return solutionToOriginalUnits(ss_solution, outCassettes) return solutionToOriginalUnits(ss_solution, outCassettes)
} }
if (!cc.check(cc_solution, amount.toNumber())) { if (!!ss_solution !== !!cc_solution) {
logger.error(new Error("coin-change provided a bad solution")) logger.error(new Error(`subset-sum and coin-change don't agree on solvability -- subset-sum:${!!ss_solution} coin-change:${!!cc_solution}`))
return solutionToOriginalUnits(ss_solution, outCassettes) return solutionToOriginalUnits(ss_solution, outCassettes)
} }

View file

@ -24,11 +24,6 @@ const prepare_denominations = denominations =>
const max_denomination_multiplicity = (denom, count, target) => const max_denomination_multiplicity = (denom, count, target) =>
Math.min(count, Math.floor(target / denom)) Math.min(count, Math.floor(target / denom))
const has_divisor = (didx, denominations, target) =>
denominations
.slice(didx)
.some(({ denom }) => (target % denom) === 0)
/* /*
* @returns null if there's no solution set; * @returns null if there's no solution set;
* false if there's no solution; * false if there's no solution;
@ -78,7 +73,7 @@ const solve = (model, target) => {
* of the denominations, or if the target is not divisible by any of the * of the denominations, or if the target is not divisible by any of the
* denominations * denominations
*/ */
if (target > csum || !has_divisor(didx, denominations, target)) if (target > csum)
return memo_set(memo, target, denom, false) return memo_set(memo, target, denom, false)
let solution = memo_get(memo, target, denom) let solution = memo_get(memo, target, denom)