-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiplying polynomials #34
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove all changes that are already part #32. Also, MULTIPLY_POLYNOMIALS
should be split up.
lib/rules.js
Outdated
@@ -80,6 +81,8 @@ export const EVALUATE_POWER = defineRuleString( | |||
// e.g. -(-3) -> 3 | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be included b/c it's part of the other diff.
lib/rules.js
Outdated
} | ||
} | ||
} | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation
lib/rules.js
Outdated
@@ -196,6 +235,70 @@ export const PRODUCT_RULE = defineRuleString('#a^#b_0 * ...', '#a^(#b_0 + ...)') | |||
// e.g. x^5 / x^3 -> x^(5 - 3) | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -226,6 +329,39 @@ export const DISTRIBUTE_NEGATIVE_ONE = | |||
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is from the other PR as well. It shouldn't be part of this PR.
test/rules_test.js
Outdated
//['x^2 * x', 'x^2 * x^1'], | ||
//['x^2 * 2 * x * x', ''], | ||
//['x + 2 * x', ''] | ||
]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix test cases and uncomment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
lib/rules.js
Outdated
} | ||
} | ||
}) | ||
return arg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you put this in an else
block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
lib/rules.js
Outdated
if (query.isMul(node)) { | ||
node.args.some(arg => { | ||
hasConstantVariable = query.isIdentifier(arg) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{implicit: node.implicit}
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test case involving the product of three polynomials that are the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
test/rules_test.js
Outdated
['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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
lib/rules.js
Outdated
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rule could be implemented without the helper once we address #23. Can you add a TODO here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use an else
block here or change this to ternary statement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -380,6 +386,31 @@ describe('rules', () => { | |||
['x^-a / x^-b', 'x^(-a - -b)'], | |||
]) | |||
|
|||
suite('multiplying coefficients', rules.MULTIPLY_COEFFICIENTS, [ | |||
['x^2 * y^2', '(1 * 1) (x^2 * y^2)'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed weird behavior in new commit.
lib/__test__/rule-list.test.js
Outdated
['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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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