-
Notifications
You must be signed in to change notification settings - Fork 276
Enhancement: Multiply denominators with terms #88
Conversation
Looking sweet! Thanks so much for this big change and also all the little changes you're making to make the codebase cleaner 🌟 I'm feeling a bit sick today, so I'll take a more thorough look early this week. I also hope to chat about this a bit with Ahmed, who wrote the original equations code. |
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.
Thank you!!
I made a whole bunch of comments:
- a bunch are gratitude for helpful things you did 😄
- a bunch are also formatting/documentation related
- some are small changes for you to make
For the most part I think this approach is right. My one concern is around the additions to cancelling out- the is existing code is already is a bit more messy than average, so I'm happy to discuss what we can do a bit more once you've read over the comments.
You're the first contributor to make a change this big - thanks so much for your time, and for your patience in waiting for me to have the time to review it ;D
I'm also in general really excited for this change because we'll be able to solve a whole bunch more equations thanks to you!
lib/Symbols.js
Outdated
@@ -28,7 +28,7 @@ Symbols.getLastSymbolTerm = function(node, symbolName) { | |||
if(isSymbolTerm(node, symbolName)) { | |||
return node; | |||
} | |||
// Otherwise, it's a sum of terms. Look through the operands for a term | |||
// If it's a sum of terms, look through the operands for a term |
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.
thanks :)
lib/Symbols.js
Outdated
return new Node.PolynomialTerm(node).getCoeffNode(); | ||
} catch (e) { | ||
if (e.message.startsWith('denominator must be constant node')) { | ||
// Not sure what this should return for a case such as 1/(2x) |
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.
probably just return null like below - unless you want to use part of the 1/(2x) term somehow
and even if the error isn't "denominator must be constant node..." you would also want to return null right?
we should probably better define what "symbol term" and "non symbol term" mean for things like 1/2x, depending on whatever's useful for solving equations -- and then yeah I think moving this stuff to an equation specific file would make more sense
lib/Symbols.js
Outdated
// Returns if `node` is a polynomial term with symbol `symbolName` | ||
function isSymbolTerm(node, symbolName) { | ||
if (Node.PolynomialTerm.isPolynomialTerm(node)) { | ||
const polyTerm = new Node.PolynomialTerm(node); | ||
if (polyTerm.getSymbolName() === symbolName) { | ||
return true; | ||
} | ||
} else if (hasDenominatorSymbol(node, symbolName)) { | ||
return 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.
missing semi colon! can you run the linter with npm lint
to make sure you're not missing other stuff?
also, generally we put else
on new line, so:
return true;
}
}
else if (hasDenominatorSymbol(node, symbolName)) {
(I just added this to #44)
lib/Symbols.js
Outdated
} | ||
return false; | ||
} | ||
|
||
function hasDenominatorSymbol(node, symbolName) { | ||
if (Node.Type.isOperator(node) && node.op === '/') { | ||
return Symbols.getSymbolsInExpression(node).size > 0; |
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.
you should use symbolName
here to make sure that the symbol in the expression is indeed the symbol we were looking for
lib/node/PolynomialTerm.js
Outdated
@@ -158,6 +90,7 @@ PolynomialTerm.isPolynomialTerm = function( | |||
node, onlyImplicitMultiplication=false) { | |||
try { | |||
// will throw error if node isn't poly term | |||
// |
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.
(extra line)
lib/node/PolynomialTerm.js
Outdated
@@ -179,4 +112,88 @@ function negativeCoefficient(node) { | |||
return node; | |||
} | |||
|
|||
function parseNode(node, onlyImplicitMultiplication) { |
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 docstring, now that it's its own function?
@@ -20,6 +20,52 @@ class CancelOutStatus { | |||
// e.g. (2x^2 * 5) / 2x^2 => 5 / 1 | |||
// Returns a Node.Status object | |||
function cancelLikeTerms(node) { | |||
// Cancel out terms if the term being multiplied | |||
// is the same as the denominator | |||
if (Node.Type.isOperator(node) && node.op === '*') { |
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 merge in master (now with #91) and change this to isOperator(node, '*')
? thanks!
@@ -20,6 +20,52 @@ class CancelOutStatus { | |||
// e.g. (2x^2 * 5) / 2x^2 => 5 / 1 | |||
// Returns a Node.Status object | |||
function cancelLikeTerms(node) { | |||
// Cancel out terms if the term being multiplied |
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 think this comment isn't super clear about what 'the term being multiplied' is
can you add an example?
if (Node.Type.isOperator(node) && node.op === '*') { | ||
let newNode = clone(node); | ||
let leftNode = newNode.args[0]; | ||
let rightNode = newNode.args[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.
what if the roles you gave left node and right node are reversed? e.g. the right node is a fraction or sum that cancels out with the left node?
also, how do you know there's only two things being multiplied by each other? there can be any number of terms in a multiplication
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 actually surprised you need this - I think that multiplyFractions
will turn (2+x) * (3+x)/(2+x)
into ((2+x)(3+x))/(2+x)
which should then just cancel out with the existing code... but if you had to add this stuff, there's probably something missing here that needs to be added. Not sure if what you have fills the hole quite right, but let's talk about it more!
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.
The code on master doesn't cancel out terms for (2+x) * (3+x)/(2+x)
, which was what prompted these changes. Currently it would distribute out the (2+x). Without canceling, my changes caused an infinite loop by multiplying the denominator, distributing out, multiplying the denominator, etc.
Regarding the left node / right node positioning, I had made an assumption based on what would happen during equations steps, but you're right that it misses out on if an equation starts as (2+x) * (3+x)/(2+x)
. I'll work on resolving this in the next commit
From what I can tell that scenario wouldn't occur during equation solving though. Instead of multiplying by an inverted fraction, the steps would multiply by the denominator and then divide by the numerator
// being multiplied | ||
if (Node.Type.isOperator(leftNode) && leftNode.op === '+') { | ||
let allMatchingDenominators = true; | ||
for (let i = 0; i < leftNode.args.length; i++) { |
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.
you could use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every here, I think
e0274dd
to
8eb739b
Compare
I'm actually starting to think that this enhancement is a bit premature. There's a lot of functionality that I seem to need out of cancelLikeTerms that should probably be done first before working on the equation solving. For multiplication across, these things need to be handled first I'm also not sure how the current approach would deal with factorization and canceling: I think I'll pull out some of the generic changes here out into a separate pull request, but I'm going to pause progress on this PR and maybe look into canceling terms separately when I have some time. I feel like that's going to be a considerable beast on its own |
I honestly think we can merge a lot of the stuff in this PR :) if in
(aside, For factoring, we haven't done any factoring stuff yet but it's on the horizon! There's a lot of cases where your code would be helpful without needing factoring, and I think it's quite reasonable to add this functionality now and wait for factoring later. tl;dr, I think we should:
what do you think? |
|
Sure, I'll try flipping those methods tomorrow and see where I get |
@kevinbarabash very true. We don't have anything that stores information like that yet. Do you think adding it to the |
@evykassirer a new |
hey @arbylee - did you get a chance to try it? how'd it go? :) |
Hey @evykassirer, I did try removing the cancelLikeTerms changes and flipping multiplyFractionsSearch and breakUpNumeratorSearch. It ended up breaking a few test cases, and I haven't had enough time to look through them (I moved this past weekend). I've updated the branch if you want to have a look |
thanks! I'll take a look and see what makes sense to fix here and what makes sense to fix in other issues this change is a nice goldmine of revealing bugs ;D |
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.
ah, okay I see what you mean about not really being able to merge this until those other things are fixed... otherwise none of it works haha!
I opened issues for the bugs, for exactly what needs to be fixed. Feel free to take them on, or we can wait until someone else can do them and then come back to this.
I also added some changes you can make in the meantime.
Hope you're settling into your new place nicely!
lib/Symbols.js
Outdated
@@ -49,7 +49,13 @@ Symbols.getLastSymbolTerm = function(node, symbolName) { | |||
// e.g. 4x^2 + 2x + y with `symbolName=x` would return y | |||
Symbols.getLastNonSymbolTerm = function(node, symbolName) { | |||
if (isSymbolTerm(node, symbolName)) { | |||
return new Node.PolynomialTerm(node).getCoeffNode(); | |||
try { |
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.
actually this might be clearer to do a check for if it's a polynomial term instead of the throw catch - that's commonly used with the PolynomialTerm
constructor actually
lib/Symbols.js
Outdated
@@ -63,6 +69,30 @@ Symbols.getLastNonSymbolTerm = function(node, symbolName) { | |||
return null; | |||
}; | |||
|
|||
// Iterates through a node and returns the last term that has a | |||
// symbolName in its denominator |
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.
it actually returns the denominator, not the term, right?
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.
Yes you're right
lib/Symbols.js
Outdated
@@ -71,7 +101,17 @@ function isSymbolTerm(node, symbolName) { | |||
return true; | |||
} | |||
} | |||
else if (hasDenominatorSymbol(node, symbolName)) { |
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.
why did you add this to isSymbolTerm
?
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.
It's been a while now so I'm trying to remember. I believe I had changed isSymbolTerm to return true if there was a symbol in the denominator, and there's logic that would then call getLastSymbolTerm. And then getLastSymbolTerm relies on this isSymbolTerm function
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.
Jumping back to this because it should probably be discussed (and have code/comments updated appropriately). Prior to this change, isSymbolTerm
specifically was checking only for polynomial symbol terms. So a term like 1/x
would not be considered a symbol term because it's not a polynomial term. This change makes it so that terms with a symbol in the denominator are considered symbol terms as well.
In turn, this affects getLastNonSymbolTerm
and getLastSymbolTerm
which both use isSymbolTerm
. I'm not sure if this change is going against the intentions of the Symbols object. If it is, then I'll need to find some other way to get a symbol term in a denominator
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 makes sense to me! Agreed re: updating the comments to explain this
test/Symbols.test.js
Outdated
|
||
tests.forEach(t => runTest(Symbols.getLastDenominatorSymbolTerm, t[0], t[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.
extra line here (you only need one new line at the bottom of a file)
test/Symbols.test.js
Outdated
tests.forEach(t => runTest(Symbols.getLastSymbolTerm, t[0], t[1])); | ||
}); | ||
|
||
describe('getLastDenominatorSymbolTerm', function() { |
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.
👍
@@ -58,6 +58,12 @@ describe('solveEquation for =', function () { | |||
['2(x+3)/3 = 2', 'x = 0'], | |||
['( u )/( 0.3) = 4u + 6.28', 'u = -9.42'], | |||
['- q - 4.36= ( 2.2q )/( 1.8)', 'q = -1.962'], | |||
//['2/x = 1', 'x = 2'], TODO: fixme | |||
//['2/(4x) = 1', 'x = 1/2'], TODO: bombs out |
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 also related because (2 / (4x)) * 4x = 4x
doesn't get cancelled out
I can see that we'll have to fix that first before we can actually test any of this (or have this functionality work at all)
@@ -58,6 +58,12 @@ describe('solveEquation for =', function () { | |||
['2(x+3)/3 = 2', 'x = 0'], | |||
['( u )/( 0.3) = 4u + 6.28', 'u = -9.42'], | |||
['- q - 4.36= ( 2.2q )/( 1.8)', 'q = -1.962'], | |||
//['2/x = 1', 'x = 2'], TODO: fixme | |||
//['2/(4x) = 1', 'x = 1/2'], TODO: bombs out | |||
//['2/(8 - 4x) = 1/2', 'x = 1'], TODO: fixme |
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.
same thing... :(
(2 / (8 - 4x)) * (8 - 4x) = (1/2) * (8 - 4x)
4 - 2x = (2 / (8 - 4x)) * 8 + (2 / (8 - 4x)) * -4x
(4 - 2x) - 4 = ((2 / (8 - 4x)) * 8 + (2 / (8 - 4x)) * -4x) - 4
(-2x) / -2 = (((2 / (8 - 4x)) * 8 + (2 / (8 - 4x)) * -4x) - 4) / -2
....
//['2/x = 1', 'x = 2'], TODO: fixme | ||
//['2/(4x) = 1', 'x = 1/2'], TODO: bombs out | ||
//['2/(8 - 4x) = 1/2', 'x = 1'], TODO: fixme | ||
//['2/(1 + 1 + 4x) = 1/3', 'x = 1'], TODO: fixme |
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.
and again
(2 / (4x + 2)) * (4x + 2) = (1/3) * (4x + 2)
4x / 3 + 2/3 = (2 / (4x + 2)) * 4x + (2 / (4x + 2)) * 2
(4x / 3 + 2/3) * 3 = ((2 / (4x + 2)) * 4x + (2 / (4x + 2)) * 2) * 3
//['2/(4x) = 1', 'x = 1/2'], TODO: bombs out | ||
//['2/(8 - 4x) = 1/2', 'x = 1'], TODO: fixme | ||
//['2/(1 + 1 + 4x) = 1/3', 'x = 1'], TODO: fixme | ||
//['(3 + x) / (x^2 + 3) = 1', '-x^2 + x = 0'], TODO: bombs out |
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 problem is different! it's a bad distribution
(3 / (x^2 + 3) + x / (x^2 + 3)) * (x^2 + 3)
turns into
(3 / (x^2 + 3) * x^2 + 9 / (x^2 + 3) + x / (x^2 + 3) * x^2 + 3x / (x^2 + 3))
I think distribution should check to see if one of the multiplying things is also a list of fractions, and if only one of them is, then multiply the other one into its numerators. I'll make this a separate issue #138
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.
eventually it'd be nice to not split the numerator like that, but I'm not sure when we'd want and when we wouldn't
//['2/(8 - 4x) = 1/2', 'x = 1'], TODO: fixme | ||
//['2/(1 + 1 + 4x) = 1/3', 'x = 1'], TODO: fixme | ||
//['(3 + x) / (x^2 + 3) = 1', '-x^2 + x = 0'], TODO: bombs out | ||
//['6/x + 8/2x = 10', '(-10x) + 4x^2 = -6'], TODO: fixme |
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 an interesting case where x * 6/x
isn't multiplied to get (x * 6) / x
, which would cancel out
one solution is just to have better cancelling code that doesn't need it to be a fraction.
another (easier for now) solution would be to add a case for a symbol times a symbol in the denominator (i.e. we don't want 9/2 * x
to multiply to 9x / 2
, but we would want 9/x * x
to multiply to 9
)
... anyways I'll open an issue #139 for this too
(btw 8/2x
is parsed as 8/2 x
ie 4x
, not as 8 / 2x
)
also @arbylee do you want some mathsteps stickers as a thank you for your contributions? 😸 if you're interested, email mathsteps@socratic.org with your mailing address and I can send them over! |
86505eb
to
b8a625d
Compare
@evykassirer Rebased and pushed with just the comment change for now. I'll have a look at some of the issues raised to see where I can help. And yes, I'd love some mathsteps stickers 😄 |
b8a625d
to
b66688c
Compare
Hi @arbylee, I'd love to get this into master, what can I do to support you? |
I think a 'high priority' tag would do the trick! I'd also use it for things that are blocked but we want to do soon |
So all blocking issues are taken care of now. @evykassirer how should we proceed? I could familiarize myself with this pull and try to fix the conflicts? Not sure if @arbylee is around to help? |
If this is urgent for Socratic you could take it over right away, but if you have stuff to work on and can give @arbylee until next week to see this and finish if they want, I think that'd be ideal. Your call though, I know this was a pretty big thing |
I've rebased and I think addressed the remaining change requests on this. For the test case @ldworkin mentioned, I've only set it to |
Awesome, this looks great @arbylee. I'll make a separate note/issue to address that test case. @evykassirer thoughts on merging?! |
kevin mentioned earlier
(see above for more context) we should open an issue for this thing so we can address it once we make the NodeStatus more complicated and able to support constraints |
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.
ahhhh amazing thanks!!! just commented on a style nit, and one case I think you're missing, after that looks ready to go! So excited for this change :D
lib/Symbols.js
Outdated
@@ -47,7 +47,9 @@ Symbols.getLastSymbolTerm = function(node, symbolName) { | |||
// e.g. 4x^2 + 2x + y with `symbolName=x` would return y | |||
Symbols.getLastNonSymbolTerm = function(node, symbolName) { | |||
if (isSymbolTerm(node, symbolName)) { | |||
return new Node.PolynomialTerm(node).getCoeffNode(); | |||
if (Node.PolynomialTerm.isPolynomialTerm(node)) { |
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 would probably be cleaner as if (isSymbolTerm(node, symbolName) && Node.PolynomialTerm.isPolynomialTerm(node))
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.
That would actually change the behavior of the function, but I've cleaned it up to be more obvious
lib/Symbols.js
Outdated
// symbolName in its denominator | ||
// e.g. 1/(2x) with `symbolName=x` would return 2x | ||
// e.g. 1/(x+2) with `symbolName=x` would return x+2 | ||
// e.g. 1/(x+2) + (x+1)/(2x+3) with `symbolName=x` would return 2x+3 |
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 curious - does it return 2x+3 or does it wrap it in parens like (2x+3) ?
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.
It is wrapped in parens, updated
lib/Symbols.js
Outdated
// e.g. false for 5x | ||
function hasDenominatorSymbol(node, symbolName) { | ||
if (Node.Type.isOperator(node) && node.op === '/') { | ||
const allSymbols = Symbols.getSymbolsInExpression(node); |
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 think this will return true for x/2
too, so should this line be calling Symbols.getSymbolsInExpression
only on the denominator?
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.
You're right. I've corrected that now
// pass for now | ||
// Ensures that a symbol is not in the denominator by multiplying | ||
// both sides by the denominator if there is a symbol present. | ||
EquationOperations.removeSymbolFromDenominator = function(equation, symbolName) { |
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.
🎉
const leftNode = equation.leftNode; | ||
const denominator = Symbols.getLastDenominatorWithSymbolTerm(leftNode, symbolName); | ||
if (denominator) { | ||
return performTermOperationOnEquation( |
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.
test/Symbols.test.js
Outdated
['x/(x+3)', 'x / (x + 3)'], | ||
]; | ||
|
||
tests.forEach(t => runTest(Symbols.getLastSymbolTerm, t[0], t[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.
can you pass 'x' in too, and then also have some tests where there are multiple symbols and you are looking for one of them? e.g. '1/x + y', y
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.
Added some test cases with other variables
test/Symbols.test.js
Outdated
['1/x', 'x'], | ||
['1/(x+2)', '(x + 2)'], | ||
['1/(x+2) + 3x', '(x + 2)'], | ||
['1/(x+2) + 3x/(1+x)', '(1 + 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.
can you add 2 + 2/x + x/2
to test that case I raised above?
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.
Done. There was even an existing issue with how symbols were being parsed that was made obvious with this particular test case. I've added a commit to recursively parse the nodes for symbols. It was previously only comparing 2 + 2/x
and x/2
as the only two nodes, instead of checking 2
and 2/x
individually
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.
yay! glad we caught that :D
['2/(8 - 4x) = 1/2', 'x = 1'], | ||
['2/(1 + 1 + 4x) = 1/3', 'x = 1'], | ||
['(3 + x) / (x^2 + 3) = 1', 'x = [0, 1]'], | ||
['6/x + 8/2x = 10', NO_STEPS], |
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 TODO for this just so it's clear that this isn't what we want?
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 realized that the test I wanted from this was actually missing parens in 8/(2x)
. I've added that and adjusted the test result.
I didn't leave the previous test case without parens because it started to look similar to the test cases in the other TODO related to complex numbers. I can add it back with a comment if you think it's a separate scenario
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.
@ldworkin how do you want to track this? You said "I'll make a separate note/issue to address that test case."
is it in your Asana board? or can we open an issue here? should we just put the TODO in the code? I'm fine as long as it's being noted somewhere :) so we remember
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.
It's in our Asana
bc08502
to
845f5b1
Compare
So excited for this, thanks for all your work, @arbylee !! |
Dammit, this change a21240d broke something! Investigating, will try to fix. |
Ok, I ended up reverting that change. I need to revisit the logic there. So this should be good -- not sure why it says there are still conflicts/failing checks, I think if we merge the latest master into it, it will be all good. |
This reverts commit 2a35214.
These functions don't necessarily return just polynomial terms anymore since isSymbol now returns true if there is a term in the denominator such as 1/x, which is not a polynomial term
The parsed nodes were previously comparing something like: 2 + 2/x + x/2 as 2 nodes. One node of `2 + 2/x` being added to `x/2` We needed to drill down to check `2` and `2/x` and `x/2` as individual nodes
42a0604
to
1708900
Compare
lib/Symbols.js
Outdated
@@ -76,10 +83,13 @@ Symbols.getLastDenominatorWithSymbolTerm = function(node, symbolName) { | |||
// Otherwise, it's a sum of terms. e.g. 1/x + 1(2+x) | |||
// Look through the operands for a | |||
// denominator term with `symbolName` | |||
else if (Node.Type.isOperator(node) && node.op === '+') { | |||
else if (Node.Type.isOperator(node, '+')) { |
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.
✨
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.
🎉 so excited about this, thanks @arbylee
Attempt to resolve #51 and implement removeSymbolFromDenominator.
This change also needed to enhance the cancelLikeTerms logic. Cancelling needed to account for denominators matching what was being multiplied. Otherwise if they didn't cancel out, it would continue trying to multiply the denominator across until the equation reaches the length limit. Let me know any feedback