Mathematica->FrameMaker
- To: mathgroup at christensen.cybernetics.net
- Subject: [mg866] Mathematica->FrameMaker
- From: Dave Wagner <wagner at bullwinkle.cs.Colorado.EDU>
- Date: Thu, 27 Apr 1995 01:38:33 -0400
By popular demand, here is a notebook that shows the general idea of how to convert Mathematica expressions into FrameMaker equations. As you'll see, the format of the two is remarkably similar. Note the following: 1. It's only a beginning. 2. There are lots of mumblings and musings to myself scattered throughout. 3. I chose a recursive approach. Given the structural similarity between the two formats, a rule-based approach might be easier. 3. You have to wrap the output inside a MIF file and then import that file into FrameMaker. Although you could conceivably reverse-engineer the format of a MIF file, I highly recommend that instead you ftp the MIF reference manual from ftp.frame.com. It's incredibly detailed (over 200 pages) and the price is right: free! Regarding the C program that translates Mathematica notebooks into MIF files: it only runs on the Macintosh, certain font information is hard-coded into it, it has warts, etc.. In other words, it's not fit for human consumption in its present state. Dave Wagner Principia Consulting (303) 786-8371 princon at csn.net http://www.csn.net/princon ============= Clip here =========================== (*^ ::[ Information = "This is a Mathematica Notebook file. It contains ASCII text, and can be transferred by email, ftp, or other text-file transfer utility. It should be read or edited using a copy of Mathematica or MathReader. If you received this as email, use your mail application or copy/paste to save everything from the line containing (*^ down to the line containing ^*) into a plain text file. On some systems you may have to give the file a name ending with ".ma" to allow Mathematica to recognize it as a Notebook. The line below identifies what version of Mathematica created this file, but it can be opened using any other version as well."; FrontEndVersion = "Macintosh Mathematica Notebook Front End Version 2.2"; MacintoshStandardFontEncoding; fontset = title, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeTitle, center, M7, bold, e8, 24, "Times"; fontset = subtitle, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeTitle, center, M7, bold, e6, 18, "Times"; fontset = subsubtitle, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeTitle, center, M7, italic, e6, 14, "Times"; fontset = section, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeSection, grayBox, M22, bold, a20, 18, "Times"; fontset = subsection, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeSection, blackBox, M19, bold, a15, 14, "Times"; fontset = subsubsection, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeSection, whiteBox, M18, bold, a12, 12, "Times"; fontset = text, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = smalltext, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Courier"; fontset = input, noPageBreakInGroup, nowordwrap, preserveAspect, groupLikeInput, M42, N23, bold, L-5, 12, "Courier"; fontset = output, output, inactive, noPageBreakInGroup, nowordwrap, preserveAspect, groupLikeOutput, M42, N23, L-5, 12, "Courier"; fontset = message, inactive, noPageBreakInGroup, nowordwrap, preserveAspect, groupLikeOutput, M42, N23, R65535, L-5, 12, "Courier"; fontset = print, inactive, noPageBreakInGroup, nowordwrap, preserveAspect, groupLikeOutput, M42, N23, L-5, 12, "Courier"; fontset = info, inactive, noPageBreakInGroup, nowordwrap, preserveAspect, groupLikeOutput, M42, N23, B65535, L-5, 12, "Courier"; fontset = postscript, PostScript, formatAsPostScript, output, inactive, noPageBreakInGroup, nowordwrap, preserveAspect, groupLikeGraphics, M7, l34, w282, h287, 12, "Courier"; fontset = name, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, italic, R65535, B65535, 10, "Geneva"; fontset = header, inactive, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = leftheader, inactive, L2, 12, "Times"; fontset = footer, inactive, noKeepOnOnePage, preserveAspect, center, M7, 12, "Times"; fontset = leftfooter, inactive, L2, 12, "Times"; fontset = help, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 10, "Times"; fontset = clipboard, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = completions, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = special1, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, bold, 18, "Times"; fontset = special2, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, bold, 14, "Times"; fontset = special3, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, bold, 12, "Times"; fontset = special4, inactive, nohscroll, noKeepOnOnePage, preserveAspect, blackDot, M27, 12, "Times"; fontset = special5, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M27, 12, "Times"; paletteColors = 256; showRuler; automaticGrouping; currentKernel; ] :[font = title; inactive; preserveAspect; startGroup] Mathematica->FrameMaker Equation Translation ;[s] 2:0,1;11,0;45,-1; 2:1,25,18,Times,1,24,0,0,0;1,25,18,Times,3,24,0,0,0; :[font = text; inactive; preserveAspect] Here's a sample expression. :[font = input; preserveAspect; startGroup] foo=(-b + Sqrt[b^2-4 a c])/(2 a) :[font = output; output; inactive; preserveAspect; endGroup] (-b + (b^2 - 4*a*c)^(1/2))/(2*a) ;[o] 2 -b + Sqrt[b - 4 a c] --------------------- 2 a :[font = input; preserveAspect; startGroup] FullForm[foo] :[font = output; output; inactive; preserveAspect; endGroup] FullForm[(-b + (b^2 - 4*a*c)^(1/2))/(2*a)] ;[o] Times[Rational[1, 2], Power[a, -1], Plus[Times[-1, b], Power[Plus[Power[b, 2], Times[-4, a, c]], Rational[1, 2]]]] :[font = text; inactive; preserveAspect] The MIF equivalent is: :[font = smalltext; inactive; preserveAspect] <MathFullForm ` equal[char[x],over[plus[minus[char[b]], pm[sqrt[plus[power[char[b],num[2,"2"]],minus[times[num[4,"4"], char[a],char[c]]]]]]],times[num[2,"2"],char[a]]]]' > :[font = text; inactive; preserveAspect] Note that the negative power must be converted to an "over". This can be recognized as follows: :[font = input; preserveAspect; startGroup] Numerator[foo] :[font = output; output; inactive; preserveAspect; endGroup] -b + (b^2 - 4*a*c)^(1/2) ;[o] 2 -b + Sqrt[b - 4 a c] :[font = input; preserveAspect; startGroup] Denominator[foo] :[font = output; output; inactive; preserveAspect; endGroup] 2*a ;[o] 2 a :[font = text; inactive; preserveAspect] If the denominator is 1, it is not a fraction! :[font = input; preserveAspect; startGroup] Numerator[x^2+2x+1] :[font = output; output; inactive; preserveAspect; endGroup] 1 + 2*x + x^2 ;[o] 2 1 + 2 x + x :[font = input; preserveAspect; startGroup] Denominator[x^2+2x+1] :[font = output; output; inactive; preserveAspect; endGroup] 1 ;[o] 1 :[font = text; inactive; preserveAspect] This is easy! :[font = text; inactive; preserveAspect] What about other places where fractions can occur? :[font = input; preserveAspect; startGroup] Exp[a/b] :[font = output; output; inactive; preserveAspect; endGroup] E^(a/b) ;[o] a/b E :[font = input; preserveAspect; startGroup] FullForm[%] :[font = output; output; inactive; preserveAspect; endGroup] FullForm[E^(a/b)] ;[o] Power[E, Times[a, Power[b, -1]]] :[font = input; preserveAspect; startGroup] Denominator[%[[2]]] :[font = output; output; inactive; preserveAspect; endGroup] b ;[o] b :[font = text; inactive; preserveAspect] So, the application of this test must be recursive. Be careful not to get into an infinite recursion! It will probably be necessary to use a helper function. :[font = input; preserveAspect; startGroup] cfrac = Nest[1/(1+#)&, a, 4] :[font = output; output; inactive; preserveAspect; endGroup] (1 + (1 + (1 + (1 + a)^(-1))^(-1))^(-1))^(-1) ;[o] 1 ----------------- 1 1 + ------------- 1 1 + --------- 1 1 + ----- 1 + a :[font = input; preserveAspect; startGroup] FullForm[cfrac] :[font = output; output; inactive; preserveAspect; endGroup] FullForm[(1 + (1 + (1 + (1 + a)^(-1))^(-1))^(-1))^(-1)] ;[o] Power[Plus[1, Power[Plus[1, Power[Plus[1, Power[Plus[1, a], -1]], -1]], -1]], -1] :[font = input; preserveAspect; startGroup] Denominator[cfrac] :[font = output; output; inactive; preserveAspect; endGroup] 1 + (1 + (1 + (1 + a)^(-1))^(-1))^(-1) ;[o] 1 1 + ------------- 1 1 + --------- 1 1 + ----- 1 + a :[font = input; preserveAspect; startGroup] Denominator[%] :[font = output; output; inactive; preserveAspect; endGroup] 1 ;[o] 1 :[font = text; inactive; preserveAspect] So it looks like it's never the case that Denominator can return a non-1 value twice in a row. :[font = text; inactive; preserveAspect] Here's a sketch of how to proceed: :[font = input; preserveAspect] Clear[parse] parse[x_] /; Denominator[x]=!=1 := over[parse[Numerator[x]], parse[Denominator[x]]] :[font = input; preserveAspect; startGroup] parse[1/2] :[font = output; output; inactive; preserveAspect; endGroup] over[parse[1], parse[2]] ;[o] over[parse[1], parse[2]] :[font = input; preserveAspect; startGroup] parse[cfrac] :[font = output; output; inactive; preserveAspect; endGroup] over[parse[1], parse[1 + (1 + (1 + (1 + a)^(-1))^(-1))^(-1)]] ;[o] 1 over[parse[1], parse[1 + -------------]] 1 1 + --------- 1 1 + ----- 1 + a :[font = input; preserveAspect; startGroup] Clear[parse] parse[x_] /; Denominator[x]=!=1 := over[parse[Numerator[x]], parse[Denominator[x]]] parse[x_+y_] := plus[parse[x],parse[y]] :[font = message; inactive; preserveAspect; endGroup] General::spell1: Possible spelling error: new symbol name "plus" is similar to existing symbol "Plus". :[font = input; preserveAspect; startGroup] ??parse :[font = print; inactive; preserveAspect; endGroup] Global`parse parse[x_] /; Denominator[x] =!= 1 := over[parse[Numerator[x]], parse[Denominator[x]]] parse[(x_) + (y_)] := plus[parse[x], parse[y]] :[font = input; preserveAspect; startGroup] parse[(a+b)/(c+d)] :[font = output; output; inactive; preserveAspect; endGroup] over[plus[parse[a], parse[b]], plus[parse[c], parse[d]]] ;[o] over[plus[parse[a], parse[b]], plus[parse[c], parse[d]]] :[font = input; preserveAspect; startGroup] parse[cfrac] :[font = output; output; inactive; preserveAspect; endGroup] over[parse[1], add[parse[1], over[parse[1], add[parse[1], over[parse[1], add[parse[1], over[parse[1], add[parse[1], parse[a]]]]]]]]] ;[o] over[parse[1], add[parse[1], over[parse[1], add[parse[1], over[parse[1], add[parse[1], over[parse[1], add[parse[1], parse[a]]]]]]]]] :[font = text; inactive; preserveAspect] Note that this only works if the denominator-checking rule is the very first rule! It appears that recursion won't be a problem, but have to think about this. :[font = input; preserveAspect; startGroup] FullForm[a-b] :[font = output; output; inactive; preserveAspect; endGroup] FullForm[a - b] ;[o] Plus[a, Times[-1, b]] :[font = input; preserveAspect; startGroup] % /. Times[-1,x_] -> minus[x] :[font = output; output; inactive; preserveAspect; endGroup] a + minus[b] ;[o] a + minus[b] :[font = input; preserveAspect] parse[Times[-1,x_]] := minus[parse[x]] :[font = input; preserveAspect; startGroup] parse[(a-b)/c] :[font = output; output; inactive; preserveAspect; endGroup] over[plus[parse[a], minus[parse[b]]], parse[c]] ;[o] over[plus[parse[a], minus[parse[b]]], parse[c]] :[font = text; inactive; preserveAspect] Parsing symbols is tricky, because in general they are more than one character long. It would be safest to parse them into "string"s rather than "char"s. :[font = input; preserveAspect; startGroup] StringByteCount["bar"] :[font = output; output; inactive; preserveAspect; endGroup] 3 ;[o] 3 :[font = input; preserveAspect; startGroup] StringByteCount[ToString[bar]] :[font = output; output; inactive; preserveAspect; endGroup] 3 ;[o] 3 :[font = text; inactive; preserveAspect] This fails miserably is the thing passed to it is not a symbol! :[font = input; preserveAspect; startGroup] StringByteCount[ToString[foo]] :[font = output; output; inactive; preserveAspect; endGroup] 69 ;[o] 69 :[font = text; inactive; preserveAspect] Here's how to embed a double-quote inside a FrameMath string: :[font = input; preserveAspect; startGroup] "he\"\"llo" :[font = output; output; inactive; preserveAspect; endGroup] "he\"\"llo" ;[o] he""llo :[font = input; preserveAspect; startGroup] parse[foo] :[font = output; output; inactive; preserveAspect; endGroup] over[plus[minus[parse[b]], parse[(b^2 - 4*a*c)^(1/2)]], parse[2*a]] ;[o] 2 over[plus[minus[parse[b]], parse[Sqrt[b - 4 a c]]], parse[2 a]] :[font = input; preserveAspect; startGroup] parse[Power[a_,b_]] := power[parse[a],parse[b]] :[font = message; inactive; preserveAspect; endGroup] General::spell1: Possible spelling error: new symbol name "power" is similar to existing symbol "Power". :[font = input; preserveAspect; startGroup] parse[foo] :[font = output; output; inactive; preserveAspect; endGroup] over[plus[minus[parse[b]], power[plus[power[parse[b], parse[2]], parse[-4*a*c]], over[parse[1], parse[2]]]], parse[2*a]] ;[o] over[plus[minus[parse[b]], power[plus[power[parse[b], parse[2]], parse[-4 a c]], over[parse[1], parse[2]]]], parse[2 a]] :[font = input; preserveAspect] Clear[parse] parse[Plus[x_, y__]] := Map[parse, plus[x,y]] :[font = input; preserveAspect; startGroup] parse[a+b+c] :[font = output; output; inactive; preserveAspect; endGroup] plus[parse[a], parse[b], parse[c]] ;[o] plus[parse[a], parse[b], parse[c]] :[font = input; preserveAspect] Clear[parse] parse[x_] /; Denominator[x]=!=1 := over[parse[Numerator[x]], parse[Denominator[x]]] parse[Plus[x_, y__]] := Map[parse, plus[x,y]] parse[Times[-1, x_]] := minus[parse[x]] parse[Times[n_?Negative, x__]] := minus[parse[Times[-n,x]]] parse[Times[x_, y__]] := Map[parse, times[x,y]] parse[Sqrt[x_]] := sqrt[parse[x]] parse[Power[a_, b_]] := power[parse[a], parse[b]] parse[x_Symbol] /; StringByteCount[ToString[x]]===1 := char[x] parse[x_Symbol] := string[InputForm[ToString[x]]] parse[n_?NumberQ] := num[FullForm[n],InputForm[ToString[n]]] :[font = input; preserveAspect; startGroup] parse[foo] :[font = output; output; inactive; preserveAspect; endGroup] over[plus[minus[char[b]], sqrt[plus[power[char[b], num[2, InputForm["2"]]], minus[times[num[4, InputForm["4"]], char[a], char[c]]]] ]], times[num[2, InputForm["2"]], char[a]]] ;[o] over[plus[minus[char[b]], sqrt[plus[power[char[b], num[2, "2"]], minus[times[num[4, "4"], char[a], char[c]]]]]], times[num[2, "2"], char[a]]] :[font = text; inactive; preserveAspect] Compare to the real thing: :[font = smalltext; inactive; preserveAspect] over[plus[minus[char[b]], pm[sqrt[plus[power[char[b],num[2,"2"]],minus[times[num[4,"4"], char[a],char[c]]]]]]],times[num[2,"2"],char[a]]] :[font = input; preserveAspect; startGroup] parse[-b + Sqrt[glarble^2- 4 scoomb c]/(2 scoomb)] :[font = output; output; inactive; preserveAspect; endGroup] plus[minus[char[b]], over[sqrt[plus[power[string[InputForm["glarbl\ e"]], num[FullForm[2], InputForm["2"]]], minus[times[num[FullForm[4], InputForm["4"]], char[c], string[InputForm["scoomb"]]]]]], times[num[FullForm[2], InputForm["2"]], string[InputForm["scoomb"]]]]] ;[o] plus[minus[char[b]], over[sqrt[plus[power[string["glarble"], num[2, "2"]], minus[times[num[4, "4"], char[c], string["scoomb"]]]]], times[num[2, "2"], string["scoomb"]]]] :[font = input; preserveAspect; startGroup] parse[Pi] :[font = output; output; inactive; preserveAspect; endGroup] string[InputForm["Pi"]] ;[o] string["Pi"] :[font = input; preserveAspect; startGroup] parse[N[Pi]] :[font = output; output; inactive; preserveAspect; endGroup] num[FullForm[3.141592653589793238], InputForm["3.14159"]] ;[o] num[3.141592653589793238, "3.14159"] :[font = input; preserveAspect; startGroup] FullForm[%] :[font = output; output; inactive; preserveAspect; endGroup; endGroup] FullForm[num[3.141592653589793238, InputForm["3.14159"]]] ;[o] num[3.141592653589793238, InputForm["3.14159"]] ^*)