Conversation
lib/rules.js
Outdated
| export const NEGATION = defineRuleString('--#a', '#a') | ||
|
|
||
| export const REARRANGE_COEFF = defineRuleString('#b * #a', '#a #b', {a: query.isNumber, b: isPolynomialTerm}) | ||
|
|
There was a problem hiding this comment.
This shouldn't be included b/c it's part of the other diff.
lib/rules.js
Outdated
| } | ||
| } | ||
| } | ||
| ) |
lib/rules.js
Outdated
| export const QUOTIENT_RULE = defineRuleString('#a^#p / #a^#q', '#a^(#p - #q)') | ||
|
|
||
| // e.g. x^2 * x^2 -> x^4 | ||
| export const MULTIPLY_POLYNOMIALS = defineRule( |
There was a problem hiding this comment.
mathsteps has no MULTIPLY_POLYNOMIALS... it has a set of steps. We should implement the steps in https://github.com/socraticorg/mathsteps/blob/master/lib/ChangeTypes.js#L60-L69 unless there's a strong reason why we shouldn't.
lib/rules.js
Outdated
| // COLLECT AND COMBINE | ||
| export {default as COLLECT_LIKE_TERMS} from './rules/collect-like-terms' | ||
|
|
||
| export const FRACTIONAL_POLYNOMIALS = defineRule( |
There was a problem hiding this comment.
This is from the other PR as well. It shouldn't be part of this PR.
| //['x^2 * x', 'x^2 * x^1'], | ||
| //['x^2 * 2 * x * x', ''], | ||
| //['x + 2 * x', ''] | ||
| ]) |
k4b7
left a comment
There was a problem hiding this comment.
Do we need both ADD_EXPONENT_OF_ONE_HELPER and ADD_EXPONENT_OF_ONE. I feel like ADD_EXPONENT_OF_ONE_HELPER is simpler and should do everything that we need for this rule.
test/rules_test.js
Outdated
| ['x^2 * 2 * x * x', ''], | ||
| ['x + 2 * x', ''] | ||
| ['x^2 * 2 * x * x', 'x^2 * 2 * x^1 * x^1'], | ||
| ['2x + 3x^2 * x y z', '2 x + 3 x^2 * (x^1 * y^1 * z^1)'], |
There was a problem hiding this comment.
We should maintain the implicit flag on x y z. I would expect the output of this test to be:
2 x^1 + 3 x^2 * x^1 y^1 z^1
The first term should have a ^1 added as well, shouldn't it?
lib/rules.js
Outdated
| 'mul', | ||
| node.args.map(arg => { | ||
| if (canApplyRule(ADD_EXPONENT_OF_ONE_HELPER, arg)) { | ||
| console.log("1st") |
lib/rules.js
Outdated
| } | ||
| } | ||
| }) | ||
| return arg |
There was a problem hiding this comment.
Can you put this in an else block?
| if (query.isMul(node)) { | ||
| node.args.some(arg => { | ||
| hasConstantVariable = query.isIdentifier(arg) | ||
| }) |
There was a problem hiding this comment.
This is a confusing construct... the following would be clearer:
const hasConstantVar = query.isMul(node) && node.args.some(query.isIdentifier)
lib/rules.js
Outdated
| } | ||
|
|
||
| return (hasConstantVariable) ? | ||
| {node} : null |
There was a problem hiding this comment.
For ternaries please put them on a single line or the following:
return hasConstantVariable
? {node}
: null
lib/rules.js
Outdated
| return build.applyNode('pow', [arg, build.numberNode(1)]) | ||
| } | ||
| return arg | ||
| }), {implicit: true} |
|
The helper rule does it for a single polynomial, specially when they're an implicit multiplication of terms (e.g |
test/rules_test.js
Outdated
| ['x^2 * x^1', '(1 * 1) (x^2 * x^1)'], | ||
| ['3x^2 * x^2', '(3 * 1) (x^2 * x^2)'], | ||
| ['x^3 * 2y^2', '(1 * 2) (x^3 * y^2)'], | ||
| ['x^3 + 2x + 3x^1 * 5x^1', 'x^3 + 2 x + (3 * 5) (x^1 * x^1)'], |
There was a problem hiding this comment.
Nice test cases. I was thinking it'd be nice to be able to check similar inputs which fail to meet the rule's criteria. I've added a task for it #36.
There was a problem hiding this comment.
Can you add a test case involving the product of three polynomials that are the same?
| ['3x^2 * x^2', '3 x^4'], | ||
| ['x^3 * 2y^2', '2 (x^3 y^2)'], | ||
| ['x^3 + 2x + 3x^1 * 5x^1', 'x^3 + 2 x + 15 x^2'], | ||
| ]) |
There was a problem hiding this comment.
This does a couple of steps:
- multiplying the coefficients
- actually doing evaluating the product
Mathsteps still wants all of the steps. I feel like we need to take a step back and think about we can combine multiple steps. We could use MULTIPLY_COEFFICIENTS + SIMPLIFY_ARITHMETIC, but we currently don't have a way to tell SIMPLIFY_ARITHMETIC that we want it to simplify only the nodes that MULTIPLY_COEFFICIENTS manipulated.
|
|
||
| // e.g. x^2 * x -> x^2 * x^1 | ||
| // export const ADD_EXPONENT_OF_ONE = ... | ||
| export const ADD_EXPONENT_OF_ONE = defineRule( |
There was a problem hiding this comment.
This rule could be implemented without the helper once we address #23. Can you add a TODO here?
lib/rules.js
Outdated
| if (query.isIdentifier(arg)){ | ||
| return build.applyNode('pow', [arg, build.numberNode(1)]) | ||
| } | ||
| return arg |
There was a problem hiding this comment.
Can you use an else block here or change this to ternary statement?
lib/rules.js
Outdated
| const {constants, coefficientMap} = getCoefficientsAndConstants(node) | ||
| isMulOfPolynomials = Object.keys(coefficientMap).length > 1 | ||
| || Object.keys(coefficientMap) | ||
| .some(key => coefficientMap[key].length > 1) |
There was a problem hiding this comment.
This is kind of confusing. The coefficientMap is designed for collecting like terms, but makes this task more complicated. Instead try using getVariableFactors.
There was a problem hiding this comment.
getVariableFactors doesn't really help in the case of :
2x + 3x^2 * x y z => 2 x + 3 x^2 * x^1 y^1 z^1
It returns []
lib/rules.js
Outdated
| // e.g. 3x^2 * 2x^2 -> (3 * 2)(x^2 * x^2) | ||
| export const MULTIPLY_COEFFICIENTS = defineRule( | ||
| (node) => { | ||
| return canApplyRule(ADD_EXPONENT_OF_ONE, node) ? {node} : null |
There was a problem hiding this comment.
Shouldn't ADD_EXPONENT_OF_ONE only be matching things like x or x * x? This matching function though seems to be accepting x^2 which I would expect ADD_EXPONENT_OF_ONE to ignore.
There was a problem hiding this comment.
I guess ADD_EXPONENT_OF_ONE_HELPER does what you want. ADD_EXPONENT_OF_ONE looks through the given expression and applies the helper where necessary.
lib/__test__/rule-list.test.js
Outdated
| ]) | ||
|
|
||
| suite('multiplying coefficients', rules.MULTIPLY_COEFFICIENTS, [ | ||
| ['x^2 * y^2', '(1 * 1) (x^2 * y^2)'], |
There was a problem hiding this comment.
This feels like a really result. We end up with a more complicated expression that actually contains the original expression. Maybe check with Gen to see if we actually want this.
There was a problem hiding this comment.
Looking at the tests in collectAndCombineSearch.test.js mathsteps doesn't bother showing the 1 coefficients.
['x^2 * x * x',
['x^2 * x^1 * x^1',
'x^(2 + 1 + 1)',
'x^4'],
],
['y * y^3',
['y^1 * y^3',
'y^(1 + 3)',
'y^4'],
],
['2x * x^2 * 5x',
['(2 * 5) * (x * x^2 * x)',
'10 * (x * x^2 * x)',
'10x^4'],
'10x^4'
],
There was a problem hiding this comment.
I'm okay with deferring the work to get this behavior until we move this code over to mathsteps. Can you add a TODO so that we can remind ourselves of this difference in behavior?
There was a problem hiding this comment.
Fixed weird behavior in new commit.
| ['x^2y^2z^2 * 2x^2', '(1 * 2) (x^2 * y^2 * z^2 * x^2)'], | ||
| ['3x^2 * x^2', '(3 * 1) (x^2 * x^2)'], | ||
| ['x^3 * y^2', '(1 * 1) (x^3 * y^2)'], | ||
| ['x^2 * y^2', 'x^2 * y^2'], |
There was a problem hiding this comment.
This might need tweak when it gets moved over to mathsteps b/c this should not be a change step b/c nothing changed but right now as long as rewriteNode returns a non-null value we assume that a change has occurred. We can take care of tweaking like that in mathsteps though.
| ? build.implicitMul(build.mul(...coeffs), poly) | ||
| : coeffs.length == 1 | ||
| ? build.implicitMul(coeffs[0], poly) | ||
| : poly |
There was a problem hiding this comment.
Please no nested ternaries. They're hard to understand and even harder understand with this formatting.
Added rule for multiplying polynomials.
x^2 * x^1', '1 x^3