Skip to content

Commit

Permalink
Merge pull request #142 from openstax/k12-588/remove-compute-engine
Browse files Browse the repository at this point in the history
Remove compute engine
  • Loading branch information
P-Gill97 authored Jan 26, 2024
2 parents 785ce8c + a47bace commit cc84457
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 35 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"build:authoring": "tsc && vite build -m authoring"
},
"dependencies": {
"@khanacademy/kas": "github:openstax/raise-kas#1ab668e5032bcf4ede04f5f28f9beafc4f9d218f",
"@khanacademy/kas": "github:openstax/raise-kas#6481127dacbd9fda7d34a6e79f27d0e4cb4798d5",
"bootstrap": "^5.3.2",
"formik": "^2.4.5",
"mathlive": "^0.95.5",
Expand Down
2 changes: 1 addition & 1 deletion specs/blocks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ test('attempts-exhausted response overrides answer-specific response', async ({
test('Math field component rendered', async ({ page }) => {
const htmlContent = `
<div class="os-raise-ib-pset" data-schema-version="1.0" data-retry-limit="3">
<div class="os-raise-ib-pset-problem" data-problem-type="input" data-solution='3\\sqrt2+\\frac42' data-problem-comparator='math'>
<div class="os-raise-ib-pset-problem" data-problem-type="input" data-solution='3\\sqrt2+2' data-problem-comparator='math'>
<div class="os-raise-ib-pset-problem-content">
<p id="problem">MultipleChoice problem content: \\( x^2 \\)</p>
</div>
Expand Down
46 changes: 25 additions & 21 deletions src/components/InputProblem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { CorrectAnswerIcon, WrongAnswerIcon } from './Icons'
import { Mathfield } from './Mathfield'
import { type MathfieldElement } from 'mathlive'
import { parse, compare } from '@khanacademy/kas'
import { ComputeEngine } from '@cortex-js/compute-engine'
export const MAX_CHARACTER_INPUT_PROBLEM_LENGTH = 500

interface InputProblemProps extends BaseProblemProps {
Expand Down Expand Up @@ -38,6 +37,30 @@ export function buildClassName(correct: boolean, formDisabled: boolean, errorRes
return className
}

export const detectAndTransform = (input: string): string => {
// Handle fractions with single digit numerators and denominators
const fractionRegex: RegExp = /\\frac(\d)(\d)/g
input = input.replace(fractionRegex, '\\frac{$1}{$2}')

// Handle square roots with single digits
const sqrtRegex: RegExp = /\\sqrt(\d)/g
input = input.replace(sqrtRegex, '\\sqrt{$1}')

return input
}

export const evaluateMathComparator = (input: string, answer: string): boolean => {
const parsedInput = parse(detectAndTransform(input))
const parsedAnswer = parse(detectAndTransform(answer))

if (!parsedInput.parsed || !parsedAnswer.parsed) {
console.error('KAS failed to parse solution or input')
return false
}

return compare(parsedInput.expr, parsedAnswer.expr, { simplify: false, form: true }).equal
}

export const InputProblem = ({
solvedCallback, exhaustedCallback, allowedRetryCallback, attemptsExhaustedResponse,
solution, retryLimit, content, contentId, comparator, encourageResponse, buttonText, correctResponse, answerResponses, onProblemAttempt
Expand Down Expand Up @@ -82,26 +105,7 @@ export const InputProblem = ({
return parseFloat(trimmedInput) === parseFloat(trimmedAnswer)
}
if (comparator.toLowerCase() === 'math') {
const ce = new ComputeEngine()

let parsedInput = parse(ce.serialize(ce.parse(trimmedInput)))
let parsedAnswer = parse(ce.serialize(ce.parse(trimmedAnswer)))

// Sometimes compute engine produces an output that the KAS parse method does not understand
// If that is the case we can try to parse again with the raw trimmed input and answer
// An example of an expression that requires this is x>5
if (!parsedInput.parsed) {
parsedInput = parse(trimmedInput)
}
if (!parsedAnswer.parsed) {
parsedAnswer = parse(trimmedAnswer)
}

if (!parsedInput.parsed || !parsedAnswer.parsed) {
return false
}

return compare(parsedInput.expr, parsedAnswer.expr, { simplify: false, form: true }).equal
return evaluateMathComparator(trimmedInput, trimmedAnswer)
}
return trimmedInput.toLowerCase() === trimmedAnswer.toLowerCase()
}
Expand Down
31 changes: 30 additions & 1 deletion src/tests/InputProblem.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render, screen, fireEvent, act } from '@testing-library/react'
import { InputProblem, MAX_CHARACTER_INPUT_PROBLEM_LENGTH, buildClassName } from '../components/InputProblem'
import { InputProblem, MAX_CHARACTER_INPUT_PROBLEM_LENGTH, buildClassName, detectAndTransform, evaluateMathComparator } from '../components/InputProblem'
import '@testing-library/jest-dom'

test('InputProblem renders with content, input and button', async () => {
Expand Down Expand Up @@ -409,3 +409,32 @@ test('Test buildClassName', async () => {
const validationError = buildClassName(false, false, 'error')
expect(validationError).toBe('os-form-control os-wrong-answer-choice')
})

test('Test detectAndTransform', async () => {
// If a fraction and sqrt transformation is needed
const input = 'x=\\frac12 + \\sqrt3'
const expectedOutput = 'x=\\frac{1}{2} + \\sqrt{3}'
let result = detectAndTransform(input)
expect(result).toEqual(expectedOutput)

// No transformation is needed
const correctInput = 'x = \\frac{12}{2} + \\sqrt{9} + 4x'
result = detectAndTransform(input)
expect(correctInput).toEqual(correctInput)
})

test('Test evaluteMathComparator', async () => {
// Fraction test
expect(evaluateMathComparator('\\frac12', '\\frac{1}{2}')).toBe(true)

// sqrt and nth root test
expect(evaluateMathComparator('x=\\sqrt4', 'x=\\sqrt[2]{4}')).toBe(true)
expect(evaluateMathComparator('x=\\sqrt4', 'x=\\sqrt[3]{4}')).toBe(false)

// form test
expect(evaluateMathComparator('y=\\frac12x-3', 'y+3=\\frac12x')).toBe(false)

// test \lt \gt
expect(evaluateMathComparator('x<\\frac{1}{3}', 'x\\lt\\frac{1}{3}')).toBe(true)
expect(evaluateMathComparator('x>\\frac13', 'x\\gt\\frac{1}{3}')).toBe(true)
})
10 changes: 4 additions & 6 deletions src/tests/kas.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { parse, compare } from '@khanacademy/kas'
import { ComputeEngine } from '@cortex-js/compute-engine'

test('Test kas with compute engine and edge cases', async () => {
test('Test kas', async () => {
const options = {
simplify: false,
form: true
}
const ce = new ComputeEngine()

const consideredEqual = [
{ expr1: ce.serialize(ce.parse('\\frac42')), expr2: ce.serialize(ce.parse('\\frac{4}{2}')) },
{ expr1: 'x>4', expr2: '4<x' },
{ expr1: 'x\\le4', expr2: '4\\gex' },
{ expr1: 'x\\lt4', expr2: '4\\gtx' },
{ expr1: 'x\\gt4', expr2: '4\\ltx' },
{ expr1: '|-4|', expr2: '|4|' },
{ expr1: '\\sqrt[3]{27}', expr2: '\\sqrt[3]{27}' },
{ expr1: ce.serialize(ce.parse('y=\\frac{1}{2}x+2')), expr2: ce.serialize(ce.parse('y=\\frac{x}{2}+2')) }
{ expr1: '\\sqrt[3]{27}', expr2: '\\sqrt[3]{27}' }
]
// If the options simplify is true the nth root tests fail.
consideredEqual.forEach((val) => {
Expand Down
2 changes: 0 additions & 2 deletions vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ export default defineConfig(({ mode }) => {

config.build['rollupOptions'].output.manualChunks = {
mathlive: ['mathlive'],
cortexjs: ['@cortex-js/compute-engine']

}

return config
Expand Down

0 comments on commit cc84457

Please sign in to comment.