Try to match a pattern operand against the identity value (0 for Add, 1 * for Multiply). If direct matching fails and the pattern is a product with * a free wildcard, set that wildcard to 0 (since 0 * anything = 0).
(
patOp: Expression,
identity: Expression,
sub: BoxedSubstitution,
options: PatternMatchOptions & { acceptVariants?: boolean },
ce: Expression['engine']
)
| 1286 | function matchWithMissingTerms( |
| 1287 | expr: Expression, |
| 1288 | pattern: Expression, |
| 1289 | substitution: BoxedSubstitution, |
| 1290 | options: PatternMatchOptions & { acceptVariants?: boolean }, |
| 1291 | ce: Expression['engine'] |
| 1292 | ): BoxedSubstitution | null { |
| 1293 | if (!isFunction(expr) || !isFunction(pattern)) return null; |
| 1294 | |
| 1295 | const operator = expr.operator; |
| 1296 | const identity = |
| 1297 | operator === 'Add' ? ce.Zero : operator === 'Multiply' ? ce.One : null; |
| 1298 | if (!identity) return null; |
| 1299 | |
| 1300 | const patOps = pattern.ops; |
| 1301 | const missing = patOps.length - expr.nops; |
| 1302 | if (missing <= 0) return null; |
| 1303 | |
| 1304 | // Try all combinations of which pattern ops are identity terms. |
| 1305 | // Sort so combinations with simpler identity terms are tried first |
| 1306 | // (a bare wildcard `_c` is a better identity candidate than a complex |
| 1307 | // pattern like `Multiply(_a, Power(_x, 2))`). |
| 1308 | const combos = combinations(patOps.length, missing); |
| 1309 | combos.sort((a, b) => { |
| 1310 | const scoreA = a.reduce((s, i) => s + patternComplexity(patOps[i]), 0); |
| 1311 | const scoreB = b.reduce((s, i) => s + patternComplexity(patOps[i]), 0); |
| 1312 | return scoreA - scoreB; |
| 1313 | }); |
| 1314 | |
| 1315 | for (const identityIndices of combos) { |
| 1316 | const activePatOps = patOps.filter((_, i) => !identityIndices.includes(i)); |
| 1317 | const identityPatOps = identityIndices.map((i) => patOps[i]); |
| 1318 | |
| 1319 | // Create a sub-pattern with only the active ops and try matching |
| 1320 | const subPattern = ce.function(operator, activePatOps, { form: 'raw' }); |
| 1321 | let sub = matchPermutation(expr, subPattern, substitution, options); |
| 1322 | if (sub === null) continue; |
| 1323 | |
| 1324 | // For each identity pattern op, try to match it against the identity value |
| 1325 | let failed = false; |
| 1326 | for (const patOp of identityPatOps) { |
no test coverage detected