Brunobkr/llama.cpp_AlgMor24_github
ΩFFFΣLLIa • llama.cpp • AlgMor24 ██████╗ ███████╗███████╗███████╗██╗ ██╗ ██╗ █████╗ ██╔═══██╗██╔════╝██╔════╝██╔════╝██║ ██║ ██║██╔══██╗ ██║ ██║█████╗ █████╗ █████╗ ██║ ██║ ██║███████║ ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║██╔══██║ ╚██████╔╝██║ ██║ ███████╗███████╗███████╗██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝╚═╝ ╚═╝ High-Performance LLM / VLM Inference & Autonomous Agentic Ecosystem… See the full description on the dataset page: https://huggingface.co/datasets/Brunobkr/llama.cpp_AlgMor24_github.
03.1k
1/**2 * This file converts a parse tree into a corresponding MathML tree. The main3 * entry point is the `buildMathML` function, which takes a parse tree from the4 * parser.5 */6 7import {fontMap, makeSpan} from "./buildCommon";8import {getCharacterMetrics} from "./fontMetrics";9import ParseError from "./ParseError";10import symbols, {ligatures} from "./symbols";11import {_mathmlGroupBuilders as groupBuilders} from "./defineFunction";12import {MathNode, TextNode} from "./mathMLTree";13 14import type Options from "./Options";15import type {AnyParseNode, SymbolParseNode} from "./parseNode";16import type {DomSpan, HtmlDomNode} from "./domTree";17import type {MathDomNode} from "./mathMLTree";18import type {Mode} from "./types";19import type {FontVariant, MathFont} from "./types/fonts";20 21const noVariantSymbols = new Set(["\\imath", "\\jmath"]);22const rowLikeTypes = new Set(["mrow", "mtable"]);23 24/**25 * Takes a symbol and converts it into a MathML text node after performing26 * optional replacement from symbols.js.27 */28export const makeText = function(29 text: string,30 mode: Mode,31 options?: Options,32): TextNode {33 if (symbols[mode][text] && symbols[mode][text].replace &&34 text.charCodeAt(0) !== 0xD835 &&35 !(ligatures.hasOwnProperty(text) && options &&36 ((options.fontFamily && options.fontFamily.slice(4, 6) === "tt") ||37 (options.font && options.font.slice(4, 6) === "tt")))) {38 text = symbols[mode][text].replace!;39 }40 41 return new TextNode(text);42};43 44/**45 * Wrap the given array of nodes in an <mrow> node if needed, i.e.,46 * unless the array has length 1. Always returns a single node.47 */48export const makeRow = function(body: MathDomNode[]): MathDomNode {49 if (body.length === 1) {50 return body[0];51 } else {52 return new MathNode("mrow", body);53 }54};55 56const mathFontVariants: Partial<57 Record<MathFont, FontVariant | ((group: SymbolParseNode) => FontVariant)>58> = {59 mathit: "italic",60 boldsymbol: (group) => (group.type === "textord" ? "bold" : "bold-italic"),61 mathbf: "bold",62 mathbb: "double-struck",63 mathsfit: "sans-serif-italic",64 mathfrak: "fraktur",65 mathscr: "script",66 mathcal: "script",67 mathsf: "sans-serif",68 mathtt: "monospace",69};70 71/**72 * Returns the math variant as a string or null if none is required.73 */74export const getVariant = (75 group: SymbolParseNode,76 options: Options,77): FontVariant | null | undefined => {78 // Handle \text... font specifiers as best we can.79 // MathML has a limited list of allowable mathvariant specifiers; see80 // https://www.w3.org/TR/MathML3/chapter3.html#presm.commatt81 if (group.mode === "text") {82 if (options.fontFamily === "texttt") {83 return "monospace";84 } else if (options.fontFamily === "textsf") {85 if (options.fontShape === "textit" &&86 options.fontWeight === "textbf") {87 return "sans-serif-bold-italic";88 } else if (options.fontShape === "textit") {89 return "sans-serif-italic";90 } else if (options.fontWeight === "textbf") {91 return "bold-sans-serif";92 } else {93 return "sans-serif";94 }95 } else if (options.fontShape === "textit" &&96 options.fontWeight === "textbf") {97 return "bold-italic";98 } else if (options.fontShape === "textit") {99 return "italic";100 } else if (options.fontWeight === "textbf") {101 return "bold";102 }103 }104 105 const font = options.font;106 if (!font || font === "mathnormal") {107 return null;108 }109 110 const mode = group.mode;111 const mathVariant = mathFontVariants[font];112 113 if (mathVariant) {114 return typeof mathVariant === "function"115 ? mathVariant(group)116 : mathVariant;117 }118 119 let text = group.text;120 if (noVariantSymbols.has(text)) {121 return null;122 }123 124 if (symbols[mode][text]) {125 const replacement = symbols[mode][text].replace;126 if (replacement) {127 text = replacement;128 }129 }130 131 const fontName = fontMap[font].fontName;132 if (getCharacterMetrics(text, fontName, mode)) {133 return fontMap[font].variant;134 }135 136 return null;137};138 139/**140 * Check for <mi>.</mi> which is how a dot renders in MathML,141 * or <mo separator="true" lspace="0em" rspace="0em">,</mo>142 * which is how a braced comma {,} renders in MathML143 */144function isNumberPunctuation(group: MathNode | null | undefined): boolean {145 if (!group) {146 return false;147 }148 if (group.type === 'mi' && group.children.length === 1) {149 const child = group.children[0];150 return child instanceof TextNode && child.text === '.';151 } else if (group.type === 'mo' && group.children.length === 1 &&152 group.getAttribute('separator') === 'true' &&153 group.getAttribute('lspace') === '0em' &&154 group.getAttribute('rspace') === '0em'155 ) {156 const child = group.children[0];157 return child instanceof TextNode && child.text === ',';158 } else {159 return false;160 }161}162 163/**164 * Takes a list of nodes, builds them, and returns a list of the generated165 * MathML nodes. Also combine consecutive <mtext> outputs into a single166 * <mtext> tag.167 */168export const buildExpression = function(169 expression: AnyParseNode[],170 options: Options,171 isOrdgroup?: boolean,172): MathNode[] {173 if (expression.length === 1) {174 const group = buildGroup(expression[0], options);175 if (isOrdgroup && group instanceof MathNode && group.type === "mo") {176 // When TeX writers want to suppress spacing on an operator,177 // they often put the operator by itself inside braces.178 group.setAttribute("lspace", "0em");179 group.setAttribute("rspace", "0em");180 }181 return [group];182 }183 184 const groups = [];185 let lastGroup;186 for (let i = 0; i < expression.length; i++) {187 const group = buildGroup(expression[i], options);188 if (group instanceof MathNode && lastGroup instanceof MathNode) {189 // Concatenate adjacent <mtext>s190 if (group.type === 'mtext' && lastGroup.type === 'mtext'191 && group.getAttribute('mathvariant') ===192 lastGroup.getAttribute('mathvariant')) {193 lastGroup.children.push(...group.children);194 continue;195 // Concatenate adjacent <mn>s196 } else if (group.type === 'mn' && lastGroup.type === 'mn') {197 lastGroup.children.push(...group.children);198 continue;199 // Concatenate <mn>...</mn> followed by <mi>.</mi>200 } else if (isNumberPunctuation(group) && lastGroup.type === 'mn') {201 lastGroup.children.push(...group.children);202 continue;203 // Concatenate <mi>.</mi> followed by <mn>...</mn>204 } else if (group.type === 'mn' && isNumberPunctuation(lastGroup)) {205 group.children = [...lastGroup.children, ...group.children];206 groups.pop();207 // Put preceding <mn>...</mn> or <mi>.</mi> inside base of208 // <msup><mn>...base...</mn>...exponent...</msup> (or <msub>)209 } else if ((group.type === 'msup' || group.type === 'msub') &&210 group.children.length >= 1 &&211 (lastGroup.type === 'mn' || isNumberPunctuation(lastGroup))212 ) {213 const base = group.children[0];214 if (base instanceof MathNode && base.type === 'mn') {215 base.children = [...lastGroup.children, ...base.children];216 groups.pop();217 }218 // \not219 } else if (lastGroup.type === 'mi' && lastGroup.children.length === 1) {220 const lastChild = lastGroup.children[0];221 if (lastChild instanceof TextNode && lastChild.text === '\u0338' &&222 (group.type === 'mo' || group.type === 'mi' ||223 group.type === 'mn')) {224 const child = group.children[0];225 if (child instanceof TextNode && child.text.length > 0) {226 // Overlay with combining character long solidus227 child.text = child.text.slice(0, 1) + "\u0338" +228 child.text.slice(1);229 groups.pop();230 }231 }232 }233 }234 groups.push(group);235 lastGroup = group;236 }237 return groups;238};239 240/**241 * Equivalent to buildExpression, but wraps the elements in an <mrow>242 * if there's more than one. Returns a single node instead of an array.243 */244export const buildExpressionRow = function(245 expression: AnyParseNode[],246 options: Options,247 isOrdgroup?: boolean,248): MathDomNode {249 return makeRow(buildExpression(expression, options, isOrdgroup));250};251 252/**253 * Takes a group from the parser and calls the appropriate groupBuilders function254 * on it to produce a MathML node.255 */256export const buildGroup = function(257 group: AnyParseNode | null | undefined,258 options: Options,259): MathNode {260 if (!group) {261 return new MathNode("mrow");262 }263 264 if (groupBuilders[group.type]) {265 // TODO(ts): MathMLBuilder returns MathDomNode but all concrete266 // builders return MathNode. Widening the return type here would267 // require updating all callers that assume MathNode.268 return groupBuilders[group.type](group, options) as MathNode;269 } else {270 throw new ParseError(271 "Got group of unknown type: '" + group.type + "'");272 }273};274 275/**276 * Takes a full parse tree and settings and builds a MathML representation of277 * it. In particular, we put the elements from building the parse tree into a278 * <semantics> tag so we can also include that TeX source as an annotation.279 *280 * Note that we actually return a domTree element with a `<math>` inside it so281 * we can do appropriate styling.282 */283export default function buildMathML(284 tree: AnyParseNode[],285 texExpression: string,286 options: Options,287 isDisplayMode: boolean,288 forMathmlOnly: boolean,289): DomSpan {290 const expression = buildExpression(tree, options);291 292 // TODO: Make a pass thru the MathML similar to buildHTML.traverseNonSpaceNodes293 // and add spacing nodes. This is necessary only adjacent to math operators294 // like \sin or \lim or to subsup elements that contain math operators.295 // MathML takes care of the other spacing issues.296 297 // Wrap up the expression in an mrow so it is presented in the semantics298 // tag correctly, unless it's a single <mrow> or <mtable>.299 let wrapper;300 if (expression.length === 1 && expression[0] instanceof MathNode &&301 rowLikeTypes.has(expression[0].type)) {302 wrapper = expression[0];303 } else {304 wrapper = new MathNode("mrow", expression);305 }306 307 // Build a TeX annotation of the source308 const annotation = new MathNode(309 "annotation", [new TextNode(texExpression)]);310 311 annotation.setAttribute("encoding", "application/x-tex");312 313 const semantics = new MathNode(314 "semantics", [wrapper, annotation]);315 316 const math = new MathNode("math", [semantics]);317 math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML");318 if (isDisplayMode) {319 math.setAttribute("display", "block");320 }321 322 // You can't style <math> nodes, so we wrap the node in a span.323 // NOTE: The span class is not typed to have <math> nodes as children, and324 // we don't want to make the children type more generic since the children325 // of span are expected to have more fields in `buildHtml` contexts.326 // The MathNode implements VirtualNode (toNode/toMarkup) which is all that327 // Span needs from its children for rendering.328 // TODO(ts): Span's child type is HtmlDomNode, but MathNode only implements329 // VirtualNode. The double-cast acknowledges this architectural limitation.330 const wrapperClass = forMathmlOnly ? "katex" : "katex-mathml";331 return makeSpan([wrapperClass], [math as unknown as HtmlDomNode]);332}333 