Skip to content

[Interactive Graph] Update tangent notes for AI shared context#3333

Open
ivyolamit wants to merge 3 commits intomainfrom
LEMS-3937/update-tangent-notes
Open

[Interactive Graph] Update tangent notes for AI shared context#3333
ivyolamit wants to merge 3 commits intomainfrom
LEMS-3937/update-tangent-notes

Conversation

@ivyolamit
Copy link
Contributor

Summary:

This PR updates the existing tangent notes, to reflect recent fixes in the POC PR.

Issue: LEMS-3937

Test plan:

@ivyolamit ivyolamit self-assigned this Mar 12, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 12, 2026

🗄️ Schema Change: No Changes ✅

@github-actions
Copy link
Contributor

github-actions bot commented Mar 12, 2026

🛠️ Item Splitting: No Changes ✅

@github-actions
Copy link
Contributor

github-actions bot commented Mar 12, 2026

Size Change: 0 B

Total Size: 486 kB

ℹ️ View Unchanged
Filename Size
packages/kas/dist/es/index.js 20.8 kB
packages/keypad-context/dist/es/index.js 1 kB
packages/kmath/dist/es/index.js 5.96 kB
packages/math-input/dist/es/index.js 98.5 kB
packages/math-input/dist/es/strings.js 1.61 kB
packages/perseus-core/dist/es/index.item-splitting.js 11.8 kB
packages/perseus-core/dist/es/index.js 24.9 kB
packages/perseus-editor/dist/es/index.js 100 kB
packages/perseus-linter/dist/es/index.js 8.82 kB
packages/perseus-score/dist/es/index.js 9.26 kB
packages/perseus-utils/dist/es/index.js 403 B
packages/perseus/dist/es/index.js 187 kB
packages/perseus/dist/es/strings.js 7.47 kB
packages/pure-markdown/dist/es/index.js 1.39 kB
packages/simple-markdown/dist/es/index.js 6.71 kB

compressed-size-action

@github-actions
Copy link
Contributor

github-actions bot commented Mar 12, 2026

npm Snapshot: Published

Good news!! We've packaged up the latest commit from this PR (7f54f17) and published it to npm. You
can install it using the tag PR3333.

Example:

pnpm add @khanacademy/perseus@PR3333

If you are working in Khan Academy's frontend, you can run the below command.

./dev/tools/bump_perseus_version.ts -t PR3333

If you are working in Khan Academy's webapp, you can run the below command.

./dev/tools/bump_perseus_version.js -t PR3333

@ivyolamit ivyolamit marked this pull request as ready for review March 12, 2026 15:41
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — documentation-only update with no code changes.

Extended reasoning...

Overview

This PR modifies only two files: an empty changeset (khaki-terms-brush.md) and the tangent notes markdown file (tangent.md). All changes are documentation corrections that improve accuracy around the canonical form normalization for tangent coefficients — specifically clarifying that only b > 0 can be guaranteed (not both a > 0 and b > 0), adding descriptions of what p1 and p2 represent, and noting that coefficient computation delegates to kmath.

Security risks

None. This PR contains zero code changes — only markdown documentation updates in an AI shared context notes file.

Level of scrutiny

Low scrutiny appropriate. This is a documentation-only change with no runtime impact. The content corrections are mathematically accurate and internally consistent throughout the document (the canonical form discussion at lines 113-116, the scoring section, and the decisions section all agree).

Other factors

The one bug reported is a valid nit: line 50 says the grapher-util.ts copy is "kept in sync with the kmath version", which is slightly misleading since the two implementations use different normalization strategies. This is a minor documentation wording issue that does not block approval — the rest of the PR actually documents this difference correctly in multiple other places. No outstanding reviewer comments exist, and no human reviews have been submitted yet.

The Grapher widget already has a tangent graph type that served as the mathematical reference:

- `packages/perseus-core/src/utils/grapher-util.ts` — Tangent coefficient computation (`getTangentCoefficients`) and equation string generation. Uses the same `f(x) = a * tan(b*x - c) + d` model. Also contains the `"sin("` → `"tan("` label bug (see [Related: Grapher Widget Bug](#related-grapher-widget-bug)).
- `packages/perseus-core/src/utils/grapher-util.ts` — Tangent coefficient computation (`getTangentCoefficients`), equation string generation, and its own copy of `canonicalTangentCoefficients()` (kept in sync with the kmath version). Uses the same `f(x) = a * tan(b*x - c) + d` model. Also contains the `"sin("` → `"tan("` label bug (see [Related: Grapher Widget Bug](#related-grapher-widget-bug)).
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The claim that grapher-util.ts's canonicalTangentCoefficients() is "kept in sync with the kmath version" (line 50) is inaccurate. The grapher-util.ts version (lines 58-91) guarantees both a > 0 and b > 0 using a phase += period/2 step, while this same PR's documentation elsewhere correctly states the kmath version can only guarantee b > 0 using the odd function identity. Consider rewording to note that the grapher-util.ts copy uses a different (and mathematically questionable) normalization strategy.

Extended reasoning...

What the bug is

Line 50 of the updated tangent.md introduces the phrase: grapher-util.ts has "its own copy of canonicalTangentCoefficients() (kept in sync with the kmath version)". This claim is internally inconsistent with the rest of the documentation added by this same PR.

The inconsistency in detail

The grapher-util.ts canonicalTangentCoefficients() (lines 58-91) implements a two-step normalization:

  1. Guarantee a > 0: flips signs of amplitude, angularFrequency, and phase
  2. Guarantee b > 0: flips angularFrequency and phase, then does phase += period/2

Meanwhile, the PR's own documentation at lines 113-116 describes the kmath version as using a fundamentally different approach:

  • Guarantee b > 0 using the odd function identity: a * tan(-|b|x - c) = (-a) * tan(|b|x - (-c)), which flips signs of a and c
  • Explicitly notes: "unlike sine... tangent has no such half-period identity, so only b > 0 can be guaranteed"

These are different algorithms with different guarantees (a > 0 AND b > 0 vs only b > 0).

Why the grapher-util.ts approach is mathematically questionable

The grapher-util.ts version uses phase += period/2 (i.e., phase += π/2) to guarantee b > 0. This step implicitly relies on tan(x + π/2) = -tan(x), but that identity is incorrect: tan(x + π/2) = -cot(x), not -tan(x). The sine version works because sin(x + π) = -sin(x) is a valid identity. The tangent version appears to be a copy-paste from the sine normalization with only the period changed from to π, without accounting for the different trigonometric identities.

Step-by-step proof of the discrepancy

Consider f(x) = -1 * tan(-2x - 1) + 0 (a = -1, b = -2, c = 1, d = 0).

grapher-util.ts algorithm:

  1. a < 0, so flip: a = 1, b = 2, c = -1
  2. b > 0 already, skip step 2
  3. Normalize c: c = -1, add π → c ≈ 2.14
  4. Result: tan(2x - 2.14) with a = 1, b = 2

kmath algorithm (as documented):

  1. b < 0, so apply odd identity: a = -(-1) = 1, b = 2, c = -(-1) = -1 (wait, let me redo: flips signs of a and c)
    Actually: a * tan(-|b|x - c) = (-a) * tan(|b|x + c), so a becomes 1, c becomes -1, b becomes 2
  2. Normalize c: c = -1, add π → c ≈ 2.14
  3. Result: 1 * tan(2x - 2.14) with a = 1, b = 2

In this case they agree, but the key difference is that the grapher-util.ts version always guarantees a > 0 as an independent first step, while the kmath version does not have this guarantee. For cases where a < 0 and b > 0, the grapher-util.ts version will flip a positive while also flipping b negative, then use the questionable phase shift to fix b. The kmath version would leave a negative since b is already positive.

Impact

This is a documentation-only issue in an AI shared context notes file. The "kept in sync" claim could mislead developers or AI assistants into thinking the two implementations are interchangeable or identical, when they are not. Since this PR is specifically updating these notes for accuracy, the claim should be corrected.

Suggested fix

Replace "kept in sync with the kmath version" with something like "uses a different normalization algorithm that guarantees both a > 0 and b > 0, unlike the kmath version which only guarantees b > 0".

The Grapher widget already has a tangent graph type that served as the mathematical reference:

- `packages/perseus-core/src/utils/grapher-util.ts` — Tangent coefficient computation (`getTangentCoefficients`) and equation string generation. Uses the same `f(x) = a * tan(b*x - c) + d` model. Also contains the `"sin("` → `"tan("` label bug (see [Related: Grapher Widget Bug](#related-grapher-widget-bug)).
- `packages/perseus-core/src/utils/grapher-util.ts` — Tangent coefficient computation (`getTangentCoefficients`), equation string generation, and its own copy of `canonicalTangentCoefficients()` that uses a different normalization strategy than the kmath version: it guarantees both `a > 0` and `b > 0` by using a `phase += period/2` step, whereas the kmath version only guarantees `b > 0` via the odd function identity (see [Canonical Normalization](#canonical-normalization) for details). Uses the same `f(x) = a * tan(b*x - c) + d` model. Also contains the `"sin("` → `"tan("` label bug (see [Related: Grapher Widget Bug](#related-grapher-widget-bug)).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely shouldn't have two different versions of a function called canonicalTangentCoefficients because that would be an oxymoron 😆 Do we need to update the kmath function? I don't understand why the math would be different.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this section, References > Grapher Widget (Legacy Tangent)
this part here is just mentioning what logic we currently have in the Grapher widget.

But since we will be deprecating the Grapher widget in the near future, the proper place to have the logic will be in packages/kmath/src/geometry.ts This is following the pattern we have for sin:

Copy link
Contributor Author

@ivyolamit ivyolamit Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other option I can think is to move all the logic in kmath, and update the Grapher logic to use it. What do you think?

Update: Thinking more about this during current implementation, IMO it will be best to not touch the grapher-util.ts since this is currently a private function used within the file and additionally will be deprecated anyways. Moving forward anything related to tangent will use the function in geometry.ts this also follows the pattern for sin.

@ivyolamit ivyolamit requested a review from handeyeco March 13, 2026 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants