-
Notifications
You must be signed in to change notification settings - Fork 526
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
## Explanation Fix part of #4044 Originally copied from #2173 when it was in proof-of-concept form This PR introduces the protos and test subject to represent polynomials. For the purposes of upcoming classifier work, a polynomial is defined as a sum of terms where each term has a coefficient and zero or more variables with positive integer powers. This representation provides support for all real polynomials, and keeps a nicely structured representation for coefficients that actually allows for retaining integers and rational values (this will become more evident when math expression -> polynomial conversion is added). Furthermore, various extensions files are added to help support some of the fundamental operations (mainly needed by test subjects). These operations are being thoroughly tested, and will be augmented with a lot more functionality in upcoming PRs. The new polynomial test subject doesn't have new tests to keep this PR focused on production code, and since it's relatively easy to verify as correct via review. #4100 is tracking adding tests. This structure will be utilized in a later PR in IsEquivalentTo classifier implementations for each numeric expression, algebraic expression, and math equation interaction. For specific details on this classifier, see [the PRD](https://docs.google.com/document/d/1x2vcSjocJUXkwwlce5Gjjq_Z83ykVIn2Fp0BcnrOrTg/edit#heading=h.1q3av9yssyi5). Polynomials are the ideal structure for verifying equivalence since they fully collapse expressions regardless of associativity, commutativity, and distributivity (to some extent--caveats will be noted in the future PR that converts expressions to this new polynomial structure). Slightly separate from polynomials, ``FloatExtensions`` was updated to include better epsilon values for comparing both floats and doubles (and a separate one is used for doubles). These are loosely based on the computed machine epsilon value listed here: https://en.wikipedia.org/wiki/Machine_epsilon, but it uses a higher order of magnitude and rounding for a bit more "wiggle room" for equality (so that it's not essentially replicating '==' for values close to 1). ## Essential Checklist - [x] The PR title and explanation each start with "Fix #bugnum: " (If this PR fixes part of an issue, prefix the title with "Fix part of #bugnum: ...".) - [x] Any changes to [scripts/assets](https://github.com/oppia/oppia-android/tree/develop/scripts/assets) files have their rationale included in the PR explanation. - [x] The PR follows the [style guide](https://github.com/oppia/oppia-android/wiki/Coding-style-guide). - [x] The PR does not contain any unnecessary code changes from Android Studio ([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#undo-unnecessary-changes)). - [x] The PR is made from a branch that's **not** called "develop" and is up-to-date with "develop". - [x] The PR is **assigned** to the appropriate reviewers ([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#clarification-regarding-assignees-and-reviewers-section)). ## For UI-specific PRs only N/A -- proto & testing library only change, and the proto changes are only additions. No UI functionality is yet affected by these changes. Commit history: * Copy proto-based changes from #2173. * Introduce math.proto & refactor math extensions. Much of this is copied from #2173. * Migrate tests & remove unneeded prefix. * Add needed newline. * Some needed Fraction changes. * Introduce math expression + equation protos. Also adds testing libraries for both + fractions & reals (new structure). Most of this is copied from #2173. * Add protos + testing lib for commutative exprs. * Add protos & test libs for polynomials. * Lint fix. * Lint fixes. * Fix broken test post-refactor. * Post-merge fix. * Add regex check, docs, and resolve TODOs. This also changes regex handling in the check to be more generic for better flexibility when matching files. * Lint fix. * Fix failing static checks. * Fix broken CI checks. Adds missing KDocs, test file exemptions, and fixes the Gradle build. * Lint fixes. * Add docs & exempted tests. * Remove blank line. * Add docs + tests. * Address reviewer comments + other stuff. This also fixes a typo and incorrectly ordered exemptions list I noticed during development of downstream PRs. * Move StringExtensions & fraction parsing. This splits fraction parsing between UI & utility components. * Address reviewer comments. * Alphabetize test exemptions. * Add missing KDocs. * Remove the ComparableOperationList wrapper. * Use more intentional epsilons for float comparing. * Remove failing test. * Fix broken build. * Fix broken build post-merge. * Post-merge fix. * More post-merge fixes.
- Loading branch information
1 parent
4805c65
commit 7e75830
Showing
18 changed files
with
2,027 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
156 changes: 156 additions & 0 deletions
156
testing/src/main/java/org/oppia/android/testing/math/PolynomialSubject.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
package org.oppia.android.testing.math | ||
|
||
import com.google.common.truth.FailureMetadata | ||
import com.google.common.truth.IntegerSubject | ||
import com.google.common.truth.StringSubject | ||
import com.google.common.truth.Truth.assertAbout | ||
import com.google.common.truth.Truth.assertThat | ||
import com.google.common.truth.Truth.assertWithMessage | ||
import com.google.common.truth.extensions.proto.LiteProtoSubject | ||
import org.oppia.android.app.model.Polynomial | ||
import org.oppia.android.testing.math.PolynomialSubject.Companion.assertThat | ||
import org.oppia.android.testing.math.RealSubject.Companion.assertThat | ||
import org.oppia.android.util.math.getConstant | ||
import org.oppia.android.util.math.isConstant | ||
import org.oppia.android.util.math.toPlainText | ||
|
||
// TODO(#4100): Add tests for this class. | ||
|
||
/** | ||
* Truth subject for verifying properties of [Polynomial]s. | ||
* | ||
* Note that this class is also a [LiteProtoSubject] so other aspects of the underlying [Polynomial] | ||
* proto can be verified through inherited methods. | ||
* | ||
* Call [assertThat] to create the subject. | ||
*/ | ||
class PolynomialSubject( | ||
metadata: FailureMetadata, | ||
private val actual: Polynomial? | ||
) : LiteProtoSubject(metadata, actual) { | ||
private val nonNullActual by lazy { | ||
checkNotNull(actual) { | ||
"Expected polynomial to be defined, not null (is the expression/equation not a valid" + | ||
" polynomial?)" | ||
} | ||
} | ||
|
||
/** Verifies that the represented [Polynomial] is null (i.e. not a valid polynomial). */ | ||
fun isNotValidPolynomial() { | ||
assertWithMessage( | ||
"Expected polynomial to be undefined, but was: ${actual?.toPlainText()}" | ||
).that(actual).isNull() | ||
} | ||
|
||
/** | ||
* Verifies that the represented [Polynomial] is a constant (i.e. [Polynomial.isConstant] and | ||
* returns a [RealSubject] to verify the value of the constant polynomial. | ||
*/ | ||
fun isConstantThat(): RealSubject { | ||
assertWithMessage("Expected polynomial to be constant, but was: ${nonNullActual.toPlainText()}") | ||
.that(nonNullActual.isConstant()) | ||
.isTrue() | ||
return assertThat(nonNullActual.getConstant()) | ||
} | ||
|
||
/** | ||
* Returns an [IntegerSubject] to test [Polynomial.getTermCount]. | ||
* | ||
* This method never fails since the underlying property defaults to 0 if there are no terms | ||
* defined in the polynomial (unless the polynomial is null). | ||
*/ | ||
fun hasTermCountThat(): IntegerSubject = assertThat(nonNullActual.termCount) | ||
|
||
/** | ||
* Returns a [PolynomialTermSubject] to test [Polynomial.getTerm] for the specified index. | ||
* | ||
* This method throws if the index doesn't correspond to a valid term. Callers should first verify | ||
* the term count using [hasTermCountThat]. | ||
*/ | ||
fun term(index: Int): PolynomialTermSubject = assertThat(nonNullActual.termList[index]) | ||
|
||
/** | ||
* Returns a [StringSubject] to test the plain-text representation of the [Polynomial] (i.e. via | ||
* [Polynomial.toPlainText]). | ||
*/ | ||
fun evaluatesToPlainTextThat(): StringSubject = assertThat(nonNullActual.toPlainText()) | ||
|
||
companion object { | ||
/** Returns a new [PolynomialSubject] to verify aspects of the specified [Polynomial] value. */ | ||
fun assertThat(actual: Polynomial?): PolynomialSubject = | ||
assertAbout(::PolynomialSubject).that(actual) | ||
|
||
private fun assertThat(actual: Polynomial.Term): PolynomialTermSubject = | ||
assertAbout(::PolynomialTermSubject).that(actual) | ||
|
||
private fun assertThat(actual: Polynomial.Term.Variable): PolynomialTermVariableSubject = | ||
assertAbout(::PolynomialTermVariableSubject).that(actual) | ||
} | ||
|
||
/** | ||
* Truth subject for verifying properties of [Polynomial.Term]s. | ||
* | ||
* Note that this class is also a [LiteProtoSubject] so other aspects of the underlying | ||
* [Polynomial.Term] proto can be verified through inherited methods. | ||
*/ | ||
class PolynomialTermSubject( | ||
metadata: FailureMetadata, | ||
private val actual: Polynomial.Term | ||
) : LiteProtoSubject(metadata, actual) { | ||
/** | ||
* Returns a [RealSubject] to test [Polynomial.Term.getCoefficient] for the represented term. | ||
* | ||
* This method never fails since the underlying property defaults to a default instance if it's | ||
* not defined in the term. | ||
*/ | ||
fun hasCoefficientThat(): RealSubject = assertThat(actual.coefficient) | ||
|
||
/** | ||
* Returns an [IntegerSubject] to test [Polynomial.Term.getVariableCount] for the represented | ||
* term. | ||
* | ||
* This method never fails since the underlying property defaults to 0 if there are no variables | ||
* in the represented term. | ||
*/ | ||
fun hasVariableCountThat(): IntegerSubject = assertThat(actual.variableCount) | ||
|
||
/** | ||
* Returns a [PolynomialTermVariableSubject] to test [Polynomial.Term.getVariable] for the | ||
* specified index. | ||
* | ||
* This method throws if the index doesn't correspond to a valid variable. Callers should first | ||
* verify the variable count using [hasVariableCountThat]. | ||
*/ | ||
fun variable(index: Int): PolynomialTermVariableSubject = | ||
assertThat(actual.variableList[index]) | ||
} | ||
|
||
/** | ||
* Truth subject for verifying properties of [Polynomial.Term.Variable]s. | ||
* | ||
* Note that this class is also a [LiteProtoSubject] so other aspects of the underlying | ||
* [Polynomial.Term.Variable] proto can be verified through inherited methods. | ||
*/ | ||
class PolynomialTermVariableSubject( | ||
metadata: FailureMetadata, | ||
private val actual: Polynomial.Term.Variable | ||
) : LiteProtoSubject(metadata, actual) { | ||
/** | ||
* Returns a [StringSubject] to test [Polynomial.Term.Variable.getName] for the represented | ||
* variable. | ||
* | ||
* This method never fails since the underlying property defaults to empty string if it's not | ||
* defined in the variable. | ||
*/ | ||
fun hasNameThat(): StringSubject = assertThat(actual.name) | ||
|
||
/** | ||
* Returns an [IntegerSubject] to test [Polynomial.Term.Variable.getPower] for the represented | ||
* variable. | ||
* | ||
* This method never fails since the underlying property defaults to 0 if it's not defined in | ||
* the variable. | ||
*/ | ||
fun hasPowerThat(): IntegerSubject = assertThat(actual.power) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.