Skip to content
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

Refactor polynomials #323

Merged
merged 42 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
cf05114
refactor: Extract a method which encapsulates how to calculate the ro…
hemalvarambhia Dec 25, 2023
8ebadd3
refactor: Rename Variable, where we clarified the name by using the f…
hemalvarambhia Dec 25, 2023
5146d59
refactor: use strictlyPositive to hide the type of Number being refer…
hemalvarambhia Dec 25, 2023
c114607
refactor: clarified the name of a category.
hemalvarambhia Dec 25, 2023
645b5f5
refactor - recategorised the multiplication tests in preparation for …
hemalvarambhia Dec 25, 2023
43d01c7
test: wrote a test to demonstrate that multiplication is commutative.
hemalvarambhia Dec 25, 2023
ca6a896
refactor: made the test a little more generic.
hemalvarambhia Dec 25, 2023
4ddb4ef
test: made the example a little more complicated (example derived fro…
hemalvarambhia Dec 25, 2023
8089cc2
format: followed arrange, act and assert.
hemalvarambhia Dec 25, 2023
9fd2c1f
refactor: recategorised some tests for addition.
hemalvarambhia Dec 25, 2023
4d7ce1a
refactor: recategorised more tests for the other binary operations.
hemalvarambhia Dec 25, 2023
4a23af2
refactor: replaced multiple assertions with use of assert: equals: wh…
hemalvarambhia Dec 25, 2023
f818335
refactor: Rename Variable, where we give objects names similar to tho…
hemalvarambhia Dec 25, 2023
2bfcd0e
refactor: we equate a product with its expected result directly.
hemalvarambhia Dec 25, 2023
e0c2919
refactor: Rename Variable with domain language.
hemalvarambhia Dec 25, 2023
05ba156
refactor: used the assert: equals message rather than check each coef…
hemalvarambhia Dec 25, 2023
4b7f888
refactor: Rename Variable so it reflects the role played by the object.
hemalvarambhia Dec 27, 2023
fa9b49d
refactor: renamed protocols to make similar code even more similar.
hemalvarambhia Dec 27, 2023
7e46a25
refactor: renamed Protocols to make similar code even more similar.
hemalvarambhia Dec 27, 2023
4b0e6ce
refactor: we can use Polynomial's = message to reduce number of asser…
hemalvarambhia Dec 27, 2023
c56bdc1
refactor: we can use the Polynomial's = method to reduce the number o…
hemalvarambhia Dec 27, 2023
03ae30d
test: added a missing test to demonstrate that polynomial addition is…
hemalvarambhia Dec 27, 2023
31baea4
refactor: used the assert: equals: message to take advantage of Polyn…
hemalvarambhia Dec 27, 2023
c76f8f9
refactor: extracted temp, renamed a temp to tell a better story.
hemalvarambhia Dec 27, 2023
6f02880
test: added a comment describing the example the way a mathematician …
hemalvarambhia Dec 27, 2023
26f762c
refactor: replaced equating constants with equating polynomials.
hemalvarambhia Dec 27, 2023
1d08970
refactor: replaced equating coefficients with equating the polynomial.
hemalvarambhia Dec 27, 2023
84b6af9
refactor: extract temp so we can show the computation being tested cl…
hemalvarambhia Dec 27, 2023
aaefdcf
refactor: replaced equating coefficients with equating Polynomials.
hemalvarambhia Dec 27, 2023
4ddc12b
test: Extract Variable, so that the operation being tested clear.
hemalvarambhia Dec 27, 2023
75c2fd8
refactor: Extract Variable so we can show the operation being tested …
hemalvarambhia Dec 27, 2023
d4fed03
refactor: Extract Variable so we can demonstrate the operation being …
hemalvarambhia Dec 27, 2023
2ba7c68
refactor: replaced assertions on coefficients with a Polynomial.
hemalvarambhia Dec 27, 2023
8320ec0
refactor: Extract variable so we can make the operation being tested …
hemalvarambhia Dec 27, 2023
4b89858
refactor: extracted the expected coefficients to a local variable to …
hemalvarambhia Dec 27, 2023
63b3779
refactor: extracted magic number and integrand to local variables.
hemalvarambhia Dec 28, 2023
a3e7f96
refactor: Rename Variable: the polynomial is the integrand.
hemalvarambhia Dec 28, 2023
ecb00fc
refactor: reduce the number of assertions by equating polynomials rat…
hemalvarambhia Dec 28, 2023
a286790
documentation: added documentation to demonstrate how a mathematician…
hemalvarambhia Dec 30, 2023
efb2a87
fix: corrected the documentation.
hemalvarambhia Dec 30, 2023
eb0a97f
fix: added a missing assertion.
hemalvarambhia Dec 30, 2023
85c2398
refactor: we can use the arbitrary constant in our expected coefficie…
hemalvarambhia Dec 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/Math-Numerical/PMNewtonZeroFinder.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ PMNewtonZeroFinder >> initialize [
^ self
]

{ #category : #operation }
PMNewtonZeroFinder >> rootOf: function [
self setFunction: function;
setDerivative: function derivative.
^ self evaluate.
]

{ #category : #initialization }
PMNewtonZeroFinder >> setDerivative: aBlock [
"Defines the derivative of the function for which zeroes will be found.
Expand Down
15 changes: 6 additions & 9 deletions src/Math-Polynomials/PMPolynomial.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -239,20 +239,17 @@ PMPolynomial >> roots [
{ #category : #information }
PMPolynomial >> roots: aNumber [

| pol roots root rootFinder |
| polynomial roots root rootFinder |
rootFinder := PMNewtonZeroFinder with: aNumber.
hernanmd marked this conversation as resolved.
Show resolved Hide resolved
pol := self class coefficients:
(coefficients reverse collect: [ :each | each asFloat ]).
polynomial := self class coefficients:
(coefficients reverse collect: [ :each | each asFloat ]).
roots := OrderedCollection new: self degree.
[
rootFinder
setFunction: pol;
setDerivative: pol derivative.
root := rootFinder evaluate.
root := rootFinder rootOf: polynomial.
rootFinder hasConverged ] whileTrue: [
roots add: root.
pol := pol deflatedAt: root.
pol degree > 0 ifFalse: [ ^ roots ] ].
polynomial := polynomial deflatedAt: root.
polynomial degree strictlyPositive ifFalse: [ ^ roots ] ].
^ roots
]

Expand Down
252 changes: 150 additions & 102 deletions src/Math-Tests-Polynomials/PMPolynomialTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Class {
#category : #'Math-Tests-Polynomials'
}

{ #category : #comparing }
{ #category : #'testing - comparing' }
PMPolynomialTest >> testIsZero [
| p1 p2 |
p1 := PMPolynomial coefficients: #(0 0 0 0 0).
Expand All @@ -13,32 +13,50 @@ PMPolynomialTest >> testIsZero [
self shouldnt: [ p2 isZero ]
]

{ #category : #'function evaluation' }
{ #category : #'testing - addition' }
PMPolynomialTest >> testPolynomialAddition [
| polynomial |
polynomial := (PMPolynomial coefficients: #(2 -3 1))
+ (PMPolynomial coefficients: #(-3 7 2 1)).
self assert: (polynomial at: 0) equals: -1.
self assert: (polynomial at: 1) equals: 4.
self assert: (polynomial at: 2) equals: 3.
self assert: (polynomial at: 3) equals: 1.

| polynomial expected p q |
p := PMPolynomial coefficients: #( 2 -3 1 ).
q := PMPolynomial coefficients: #( -3 7 2 1 ).
polynomial := p + q.
expected := PMPolynomial coefficients: #( -1 4 3 1 ).
self assert: polynomial equals: expected.
self assert: (polynomial at: 4) equals: 0
]

{ #category : #'function evaluation' }
{ #category : #'testing - addition' }
PMPolynomialTest >> testPolynomialAdditionIsCommutative [

| p q expected |
p := PMPolynomial coefficients: #(1 2 4 8).
q := PMPolynomial coefficients: #(-1 3 7 -4).

expected := PMPolynomial coefficients: #(0 5 11 4).
self assert: p + q equals: expected.
self assert: q + p equals: expected
]

{ #category : #'testing - algebra' }
PMPolynomialTest >> testPolynomialDerivative [
"Code example 2.3"
"
p(x) = x^3 + 2x^2 + 7x - 3, therefore:
p'(x) = 3x^2 + 4x + 7
"

| polynomial |
polynomial := (PMPolynomial coefficients: #(-3 7 2 1)) derivative.
self assert: (polynomial at: 0) equals: 7.
self assert: (polynomial at: 1) equals: 4.
self assert: (polynomial at: 2) equals: 3.
self assert: (polynomial at: 3) equals: 0.
self assert: (polynomial at: 4) equals: 0
| p derivative expectedDerivative |
p := PMPolynomial coefficients: #( -3 7 2 1 ).

derivative := p derivative.

expectedDerivative := PMPolynomial coefficients: #( 7 4 3 ).
self assert: derivative equals: expectedDerivative.
self assert: (derivative at: 3) equals: 0.
self assert: (derivative at: 4) equals: 0
]

{ #category : #'function evaluation' }
{ #category : #'testing - division' }
PMPolynomialTest >> testPolynomialDivision [
| pol1 pol2 polynomial |
pol1 := PMPolynomial coefficients: #(2 -3 1).
Expand All @@ -53,7 +71,7 @@ PMPolynomialTest >> testPolynomialDivision [
self assert: (polynomial at: 6) equals: 0
]

{ #category : #'function evaluation' }
{ #category : #'testing - division' }
PMPolynomialTest >> testPolynomialDivisionBug [
"identify an error when trying to create a zero dividend"

Expand All @@ -63,7 +81,7 @@ PMPolynomialTest >> testPolynomialDivisionBug [
self shouldnt: [ pol1 / pol2 ] raise: Error
]

{ #category : #arithmetic }
{ #category : #'testing - arithmetic' }
PMPolynomialTest >> testPolynomialDoubleDispatch [
| n p |
n := 3.2.
Expand All @@ -80,7 +98,7 @@ PMPolynomialTest >> testPolynomialDoubleDispatch [
self assert: n - p equals: (p - n) negated
]

{ #category : #'function evaluation' }
{ #category : #'testing - algebra' }
PMPolynomialTest >> testPolynomialEvaluation [
"Code example 2.2"

Expand All @@ -89,7 +107,7 @@ PMPolynomialTest >> testPolynomialEvaluation [
self assert: 0 equals: (polynomial value: 1)
]

{ #category : #comparing }
{ #category : #'testing - comparing' }
PMPolynomialTest >> testPolynomialHash [
"polynomial hash is hash of coefficient array"

Expand All @@ -105,118 +123,148 @@ PMPolynomialTest >> testPolynomialHash [
self assert: p3 hash equals: p2 hash
]

{ #category : #'function evaluation' }
{ #category : #'testing - algebra' }
PMPolynomialTest >> testPolynomialIntegral [
"Code example 2.3"

| polynomial |
polynomial := (PMPolynomial coefficients: #(-3 7 2 1)) integral.
self assert: (polynomial at: 0) equals: 0.
self assert: (polynomial at: 1) equals: -3.
self assert: (polynomial at: 2) equals: 7 / 2.
self assert: (polynomial at: 3) equals: 2 / 3.
self assert: (polynomial at: 4) equals: 1 / 4.
"
Given p(x) = x^3 + 2x^2 + 7x - 3
then the integral is I(x) = 1/4 x^4 + 2/3 x^3 + 7/2 x^2 - 3x + C, where C is an arbitary
constant.
"

| polynomial expectedCoefficients expected |
polynomial := (PMPolynomial coefficients: #( -3 7 2 1 )) integral.
expectedCoefficients := Array
with: 0
with: -3
with: 7 / 2
with: 2 / 3
with: 1 / 4.
expected := PMPolynomial coefficients: expectedCoefficients.
self assert: polynomial equals: expected .
self assert: (polynomial at: 5) equals: 0
]

{ #category : #'function evaluation' }
{ #category : #'testing - algebra' }
PMPolynomialTest >> testPolynomialIntegralWithConstant [
"Code example 2.3"

| polynomial |
polynomial := (PMPolynomial coefficients: #(-3 7 2 1)) integral: 5.
self assert: (polynomial at: 0) equals: 5.
self assert: (polynomial at: 1) equals: -3.
self assert: (polynomial at: 2) equals: 7 / 2.
self assert: (polynomial at: 3) equals: 2 / 3.
self assert: (polynomial at: 4) equals: 1 / 4.
| polynomial arbitraryConstant integrand expectedCoefficients expected |
arbitraryConstant := 5.
integrand := PMPolynomial coefficients: #( -3 7 2 1 ).
polynomial := integrand integral: arbitraryConstant.
expectedCoefficients := Array
with: arbitraryConstant
with: -3
with: 7 / 2
with: 2 / 3
with: 1 / 4.
expected := PMPolynomial coefficients: expectedCoefficients.
self assert: polynomial equals: expected.
self assert: (polynomial at: 5) equals: 0
]

{ #category : #'function evaluation' }
{ #category : #'testing - multiplication' }
PMPolynomialTest >> testPolynomialMultiplication [
"Code example 2.3"

| pol1 pol2 polynomial |
pol1 := PMPolynomial coefficients: #(2 -3 1).
pol2 := PMPolynomial coefficients: #(-3 7 2 1).
polynomial := pol1 * pol2.
self assert: (polynomial at: 0) equals: -6.
self assert: (polynomial at: 1) equals: 23.
self assert: (polynomial at: 2) equals: -20.
self assert: (polynomial at: 3) equals: 3.
self assert: (polynomial at: 4) equals: -1.
self assert: (polynomial at: 5) equals: 1.
self assert: (polynomial at: 6) equals: 0
| p q product expected |
p := PMPolynomial coefficients: #( 2 -3 1 ).
q := PMPolynomial coefficients: #( -3 7 2 1 ).
product := p * q.
expected := PMPolynomial coefficients: #( -6 23 -20 3 -1 1 ).
self assert: product equals: expected.
]

{ #category : #'testing - multiplication' }
PMPolynomialTest >> testPolynomialMultiplicationIsCommutative [

| expected p q |
"p(x) = (x - 3) (x - 4), q(x) = x^3 + 1 therefore:

p(x) * q(x) = q(x) * p(x) = x^5 - 7 x^4 + 12 x^3 + x^2 - 7x + 12"
p := PMPolynomial coefficients: #( 12 -7 1 ).
q := PMPolynomial coefficients: #( 1 0 0 1 ).

expected := PMPolynomial coefficients: #( 12 -7 1 12 -7 1 ).
self assert: p * q equals: expected.
self assert: q * p equals: expected
]

{ #category : #'function evaluation' }
{ #category : #'testing - addition' }
PMPolynomialTest >> testPolynomialNumberAddition [
| polynomial |
polynomial := 2 + (PMPolynomial coefficients: #(2 -3 1)).
self assert: (polynomial at: 0) equals: 4.
self assert: (polynomial at: 1) equals: -3.
self assert: (polynomial at: 2) equals: 1.

| polynomial expected p |
p := PMPolynomial coefficients: #( 2 -3 1 ).
polynomial := 2 + p.
expected := PMPolynomial coefficients: #( 4 -3 1 ).
self assert: polynomial equals: expected.
self assert: (polynomial at: 3) equals: 0
]

{ #category : #'function evaluation' }
{ #category : #'testing - addition' }
PMPolynomialTest >> testPolynomialNumberAdditionInverse [
| polynomial |
polynomial := (PMPolynomial coefficients: #(2 -3 1)) + 2.
self assert: (polynomial at: 0) equals: 4.
self assert: (polynomial at: 1) equals: -3.
self assert: (polynomial at: 2) equals: 1.

| polynomial expected p |
p := PMPolynomial coefficients: #( 2 -3 1 ).
polynomial := p + 2.
expected := PMPolynomial coefficients: #( 4 -3 1 ).
self assert: polynomial equals: expected.
self assert: (polynomial at: 3) equals: 0
]

{ #category : #'function evaluation' }
{ #category : #'testing - division' }
PMPolynomialTest >> testPolynomialNumberDivision [
| polynomial |
polynomial := (PMPolynomial coefficients: #(2 -3 1)) / 2.
self assert: (polynomial at: 0) equals: 1.
self assert: (polynomial at: 1) equals: -3 / 2.
self assert: (polynomial at: 2) equals: 1 / 2.

| polynomial expected expectedCoefficients p |
p := PMPolynomial coefficients: #( 2 -3 1 ).
polynomial := p / 2.
expectedCoefficients := Array with: 1 with: -3 / 2 with: 1 / 2.
expected := PMPolynomial coefficients: expectedCoefficients.
self assert: polynomial equals: expected.
self assert: (polynomial at: 3) equals: 0
]

{ #category : #'function evaluation' }
{ #category : #'testing - multiplication' }
PMPolynomialTest >> testPolynomialNumberMultiplication [
| polynomial |
polynomial := 2 * (PMPolynomial coefficients: #(2 -3 1)).
self assert: (polynomial at: 0) equals: 4.
self assert: (polynomial at: 1) equals: -6.
self assert: (polynomial at: 2) equals: 2.
self assert: (polynomial at: 3) equals: 0

| product expected p |
p := PMPolynomial coefficients: #( 2 -3 1 ).
product := 2 * p.

expected := PMPolynomial coefficients: #( 4 -6 2 ).
self assert: product equals: expected
]

{ #category : #'function evaluation' }
{ #category : #'testing - multiplication' }
PMPolynomialTest >> testPolynomialNumberMultiplicationInverse [
| polynomial |
polynomial := (PMPolynomial coefficients: #(2 -3 1)) * 2.
self assert: (polynomial at: 0) equals: 4.
self assert: (polynomial at: 1) equals: -6.
self assert: (polynomial at: 2) equals: 2.
self assert: (polynomial at: 3) equals: 0

| product expected p |
p := PMPolynomial coefficients: #( 2 -3 1 ).
product := p * 2.

expected := PMPolynomial coefficients: #( 4 -6 2 ).
self assert: product equals: expected
]

{ #category : #'function evaluation' }
{ #category : #'testing - subtraction' }
PMPolynomialTest >> testPolynomialNumberSubtraction [
| polynomial |
polynomial := 2 - (PMPolynomial coefficients: #(2 -3 1)).
self assert: (polynomial at: 0) equals: 0.
self assert: (polynomial at: 1) equals: 3.
self assert: (polynomial at: 2) equals: -1.

| polynomial expected |
polynomial := 2 - (PMPolynomial coefficients: #( 2 -3 1 )).
expected := PMPolynomial coefficients: #( 0 3 -1 ).
self assert: polynomial equals: expected.
self assert: (polynomial at: 3) equals: 0
]

{ #category : #'function evaluation' }
{ #category : #'testing - subtraction' }
PMPolynomialTest >> testPolynomialNumberSubtractionInverse [
| polynomial |
polynomial := (PMPolynomial coefficients: #(2 -3 1)) - 2.
self assert: (polynomial at: 0) equals: 0.
self assert: (polynomial at: 1) equals: -3.
self assert: (polynomial at: 2) equals: 1.

| polynomial expected |
polynomial := (PMPolynomial coefficients: #( 2 -3 1 )) - 2.
expected := PMPolynomial coefficients: #( 0 -3 1 ).
self assert: polynomial equals: expected.
self assert: (polynomial at: 3) equals: 0
]

Expand Down Expand Up @@ -265,15 +313,15 @@ PMPolynomialTest >> testPolynomialRootsForLinear [
self assert: (roots at: 1) closeTo: -0.5
]

{ #category : #'function evaluation' }
{ #category : #'testing - subtraction' }
PMPolynomialTest >> testPolynomialSubtraction [
| polynomial |
polynomial := (PMPolynomial coefficients: #(2 -3 1))
- (PMPolynomial coefficients: #(-3 7 2 1)).
self assert: (polynomial at: 0) equals: 5.
self assert: (polynomial at: 1) equals: -10.
self assert: (polynomial at: 2) equals: -1.
self assert: (polynomial at: 3) equals: -1.

| polynomial p q expected |
p := PMPolynomial coefficients: #( 2 -3 1 ).
q := PMPolynomial coefficients: #( -3 7 2 1 ).
polynomial := p - q.
expected := PMPolynomial coefficients: #( 5 -10 -1 -1 ).
self assert: polynomial equals: expected.
self assert: (polynomial at: 4) equals: 0
]

Expand Down