function solver (args) {
const {constraints, assignments} = args
let scope = Object.assign({}, assignments)
let filtered = constraints.filter(d => !d.includes('assume') && !d.includes('declare') && !d.includes('describe'))
const vars = {}
constraints.filter(d => d.includes("declare")).forEach(d => {
const tuple = d.replace('declare', '').replace('(', '').replace(')', '').split(',')
if (tuple.length == 2) {
const v = tuple[0].trim()
const val = tuple[1].trim()
vars[v] = val
}
})
const subst = d => {
Object.keys(scope).forEach(v => {
if (d.variables().includes(v)) {
d = d.sub(v, scope[v])
}
})
return d
}
const reduce = (unsolved, d) => {
const vars = d.variables()
if (vars.length == 1) {
const solFound = d.solveFor(vars[0])
if (solFound.length == 0) {
throw(`${d.toString()} cannot be solved`)
}
const sol = solFound[0].evaluate().text()
if (scope[vars[0]] && scope[vars[0]] !== sol ) {
throw ("we are in trouble", scope[vars[0]], sol)
}
scope[vars[0]] = sol
} else {
unsolved.push(d)
}
return unsolved
}
const step = array => array.map(subst).reduce(reduce, [])
const run = (array) => {
let curr_resolved = 0
let i = 0;
let last = Object.keys(scope).length-1
while (Object.keys(scope).length !== last) {
last = Object.keys(scope).length
i++
array = step(array)
}
return array
}
let res = run( filtered.map(d => nerdamer(d)) )
return {constraints: res.map(d => d.text()).filter( d => d != "0"), assignments: scope, vars: vars}
}