66
77namespace CSharpMath {
88 using System . Collections ;
9+ using System . Data . SqlTypes ;
10+ using System . Numerics ;
911 using Atom ;
1012 using Atoms = Atom . Atoms ;
11- using System . Numerics ;
1213
1314 public static partial class Evaluation {
1415 enum Precedence {
1516 DefaultContext ,
17+ LimitSubscriptContext ,
1618 BraceContext ,
1719 BracketContext ,
1820 ParenthesisContext ,
@@ -135,7 +137,7 @@ static Result<MathItem> TryMakeSet(MathItem.Comma c, bool leftClosed, bool right
135137 { "[" , ( "]" , Precedence . BracketContext ) } ,
136138 { "{" , ( "}" , Precedence . BraceContext ) } ,
137139 } ;
138- static readonly Dictionary < ( string ? left , string ? right ) , Func < MathItem ? , Result < MathItem > > > BracketHandlers =
140+ static readonly Dictionary < ( string ? left , string ? right ) , Func < MathItem ? , Result < MathItem > > > InnerHandlers =
139141 new Dictionary < ( string ? left , string ? right ) , Func < MathItem ? , Result < MathItem > > > {
140142 { ( "(" , ")" ) , item => item switch {
141143 null => "Missing math inside ( )" ,
@@ -155,7 +157,8 @@ static Result<MathItem> TryMakeSet(MathItem.Comma c, bool leftClosed, bool right
155157 MathItem . Comma c => TryMakeSet ( c , true , true ) ,
156158 _ => item
157159 } } ,
158- { ( "{" , "}" ) , item => item . AsEntities ( "set element" ) . Bind ( entities => ( MathItem ) MathS . Sets . Finite ( entities ) ) }
160+ { ( "{" , "}" ) , item => item . AsEntities ( "set element" ) . Bind ( entities => ( MathItem ) MathS . Sets . Finite ( entities ) ) } ,
161+ { ( "|" , "|" ) , item => item . AsEntity ( "abs argument" ) . Bind ( x => ( MathItem ) MathS . Abs ( x ) ) }
159162 } ;
160163 static Result < MathItem ? > Transform ( MathList mathList , ref int i , Precedence prec ) {
161164 MathItem ? prev = null ;
@@ -169,13 +172,19 @@ static Result<MathItem> TryMakeSet(MathItem.Comma c, bool leftClosed, bool right
169172 var atom = mathList [ i ] ;
170173 MathItem ? @this ;
171174 bool subscriptAllowed = false , binaryIsComparison = false , binaryIsRightAssociative = false ;
172- Result HandleSuperscript ( ref MathItem ? @this , MathList superscript ) {
175+ Result HandleSuperscript ( ref MathItem ? @this , ref int i , MathList superscript ) {
173176 switch ( superscript ) {
174- case { Count : 1 } when superscript [ 0 ] is Atoms . Ordinary { Nucleus : "∁" } :
177+ case [ Atoms . Ordinary { Nucleus : "∁" } ] :
175178 ( @this , error ) =
176179 @this . AsEntity ( "target of set inversion" ) . Bind ( target => ( MathItem ? ) MathS . SetSubtraction ( MathS . Sets . C , target ) ) ; // we don't support domains yet
177180 if ( error != null ) return error ;
178181 break ;
182+ case [ Atoms . UnaryOperator { Nucleus : ( "+" or "\u2212 " ) and var direction } ] :
183+ if ( prec != Precedence . LimitSubscriptContext ) return $ "{ direction } alone in superscript but not in limit subscript context";
184+ if ( i != mathList . Count - 1 ) return $ "Limit direction indicator { direction } not placed at the end";
185+ if ( direction == "+" ) i = mathList . Count + 1 ; // signal approach from right
186+ else i = mathList . Count ; // signal approach from left
187+ break ;
179188 default :
180189 Entity ? exponent ;
181190 ( exponent , error ) = Transform ( superscript ) . ExpectEntityOrNull ( nameof ( exponent ) ) ;
@@ -241,6 +250,7 @@ Result HandleSuperscript(ref MathItem? @this, MathList superscript) {
241250 ( "e" , 0 , FontStyle . Roman or FontStyle . Default or FontStyle . Italic ) => MathS . e ,
242251 ( "π" , 0 , FontStyle . Roman or FontStyle . Default or FontStyle . Italic ) => MathS . pi ,
243252 ( "i" , 0 , FontStyle . Roman or FontStyle . Default or FontStyle . Italic ) => MathS . i ,
253+ ( "undefined" , 0 , FontStyle . Roman ) => MathS . NaN ,
244254 // Convert θ to theta
245255 ( _, _, FontStyle . Default or FontStyle . Italic ) when LaTeXSettings . CommandForAtom ( atom ) is string s => MathS . Var ( string . Concat ( s . TrimStart ( '\\ ' ) , underscore , subscript ) ) ,
246256 _ => MathS . Var ( name + underscore + subscript . ToString ( ) )
@@ -326,6 +336,54 @@ Result HandleSuperscript(ref MathItem? @this, MathList superscript) {
326336 handleFunction = MathS . Arccosec ;
327337 handleFunctionInverse = MathS . Cosec ;
328338 goto handleFunction ;
339+ case Atoms . LargeOperator { Nucleus : "sinh" } :
340+ handleFunction = MathS . Hyperbolic . Sinh ;
341+ handleFunctionInverse = MathS . Hyperbolic . Arsinh ;
342+ goto handleFunction ;
343+ case Atoms . LargeOperator { Nucleus : "cosh" } :
344+ handleFunction = MathS . Hyperbolic . Cosh ;
345+ handleFunctionInverse = MathS . Hyperbolic . Arcosh ;
346+ goto handleFunction ;
347+ case Atoms . LargeOperator { Nucleus : "tanh" } :
348+ handleFunction = MathS . Hyperbolic . Tanh ;
349+ handleFunctionInverse = MathS . Hyperbolic . Artanh ;
350+ goto handleFunction ;
351+ case Atoms . LargeOperator { Nucleus : "coth" } :
352+ handleFunction = MathS . Hyperbolic . Cotanh ;
353+ handleFunctionInverse = MathS . Hyperbolic . Arcotanh ;
354+ goto handleFunction ;
355+ case Atoms . LargeOperator { Nucleus : "sech" } :
356+ handleFunction = MathS . Hyperbolic . Sech ;
357+ handleFunctionInverse = MathS . Hyperbolic . Arsech ;
358+ goto handleFunction ;
359+ case Atoms . LargeOperator { Nucleus : "csch" } :
360+ handleFunction = MathS . Hyperbolic . Cosech ;
361+ handleFunctionInverse = MathS . Hyperbolic . Arcosech ;
362+ goto handleFunction ;
363+ case Atoms . LargeOperator { Nucleus : "arsinh" } :
364+ handleFunction = MathS . Hyperbolic . Arsinh ;
365+ handleFunctionInverse = MathS . Hyperbolic . Sinh ;
366+ goto handleFunction ;
367+ case Atoms . LargeOperator { Nucleus : "arcosh" } :
368+ handleFunction = MathS . Hyperbolic . Arcosh ;
369+ handleFunctionInverse = MathS . Hyperbolic . Cosh ;
370+ goto handleFunction ;
371+ case Atoms . LargeOperator { Nucleus : "artanh" } :
372+ handleFunction = MathS . Hyperbolic . Artanh ;
373+ handleFunctionInverse = MathS . Hyperbolic . Tanh ;
374+ goto handleFunction ;
375+ case Atoms . LargeOperator { Nucleus : "arcoth" } :
376+ handleFunction = MathS . Hyperbolic . Arcotanh ;
377+ handleFunctionInverse = MathS . Hyperbolic . Cotanh ;
378+ goto handleFunction ;
379+ case Atoms . LargeOperator { Nucleus : "arsech" } :
380+ handleFunction = MathS . Hyperbolic . Arsech ;
381+ handleFunctionInverse = MathS . Hyperbolic . Sech ;
382+ goto handleFunction ;
383+ case Atoms . LargeOperator { Nucleus : "arcsch" } :
384+ handleFunction = MathS . Hyperbolic . Arcosech ;
385+ handleFunctionInverse = MathS . Hyperbolic . Cosech ;
386+ goto handleFunction ;
329387 case Atoms . LargeOperator { Nucleus : "log" , Subscript : var logBaseList } :
330388 Entity ? logBase ;
331389 ( logBase , error ) = Transform ( logBaseList ) . ExpectEntityOrNull ( nameof ( logBase ) ) ;
@@ -339,10 +397,33 @@ Result HandleSuperscript(ref MathItem? @this, MathList superscript) {
339397 handleFunction = MathS . Ln ;
340398 handleFunctionInverse = arg => MathS . Pow ( MathS . e , arg ) ;
341399 goto handleFunction ;
400+ case Atoms . LargeOperator { Nucleus : "abs" } :
401+ handleFunction = MathS . Abs ;
402+ handleFunctionInverse = arg => MathS . NaN ;
403+ goto handleFunction ;
342404 case Atoms . LargeOperator { Nucleus : "sgn" } :
343405 handleFunction = MathS . Signum ;
344406 handleFunctionInverse = arg => MathS . NaN ;
345407 goto handleFunction ;
408+ case Atoms . LargeOperator { Nucleus : "lim" , Subscript : var limitSubscript } :
409+ Entity limitVariable , limitTarget ;
410+ int limitSubscriptIndex = 0 ;
411+ ( limitVariable , error ) = Transform ( limitSubscript , ref limitSubscriptIndex , Precedence . LimitSubscriptContext ) . ExpectEntity ( "limit variable in subscript" ) ;
412+ if ( error != null ) return error ;
413+ if ( limitSubscriptIndex == limitSubscript . Count ) return "Missing → in limit subscript" ;
414+ limitSubscriptIndex ++ ;
415+ ( limitTarget , error ) = Transform ( limitSubscript , ref limitSubscriptIndex , Precedence . LimitSubscriptContext ) . ExpectEntity ( "limit target in subscript" ) ;
416+ if ( error != null ) return error ;
417+ var limitDirection =
418+ limitSubscriptIndex == limitSubscript . Count + 1
419+ ? ApproachFrom . Left
420+ : limitSubscriptIndex == limitSubscript . Count + 2
421+ ? ApproachFrom . Right
422+ : ApproachFrom . BothSides ;
423+ handleFunction = limitBody => MathS . Limit ( limitBody , limitVariable , limitTarget , limitDirection ) ;
424+ handleFunctionInverse = arg => MathS . NaN ;
425+ subscriptAllowed = true ;
426+ goto handleFunction ;
346427 case Atoms . BinaryOperator { Nucleus : "+" } :
347428 handlePrecedence = Precedence . AddSubtract ;
348429 handleBinary = ( a , b ) => a + b ;
@@ -436,10 +517,12 @@ Result HandleSuperscript(ref MathItem? @this, MathList superscript) {
436517 handleBinary = ( x , y ) => MathS . Negation ( MathS . ExclusiveDisjunction ( x , y ) ) ; // XNOR = equivalence
437518 goto handleBinary ;
438519 case Atoms . Relation { Nucleus : "→" } :
439- handlePrecedence = Precedence . Implication ;
440- handleBinary = MathS . Implication ;
441- binaryIsRightAssociative = true ;
442- goto handleBinary ;
520+ if ( prec != Precedence . LimitSubscriptContext ) {
521+ handlePrecedence = Precedence . Implication ;
522+ handleBinary = MathS . Implication ;
523+ binaryIsRightAssociative = true ;
524+ goto handleBinary ;
525+ } else return prev ;
443526 case Atoms . Relation { Nucleus : "↛" } :
444527 handlePrecedence = Precedence . Implication ;
445528 handleBinary = ( x , y ) => MathS . Negation ( MathS . Implication ( x , y ) ) ;
@@ -542,20 +625,18 @@ Result HandleSuperscript(ref MathItem? @this, MathList superscript) {
542625 i -- ;
543626 return prev ;
544627 }
545- return
546- BracketHandlers . TryGetValue ( ( contextInfo . KnownOpening , rightBracket ) , out var handler )
547- ? handler ( prev ) . Bind ( handled => {
548- MathItem ? nullable = handled ;
549- if ( HandleSuperscript ( ref nullable , super ) . Error is { } error )
550- return Result . Err ( error ) ;
551- return Result . Ok ( nullable ) ;
552- } )
553- : $ "Unrecognized bracket pair { contextInfo . KnownOpening } { rightBracket } ";
554- case Atoms . Inner { LeftBoundary : { Nucleus : var left } , InnerList : var inner , RightBoundary : { Nucleus : var right } } :
628+ if ( InnerHandlers . TryGetValue ( ( contextInfo . KnownOpening , rightBracket ) , out var handler ) ) {
629+ ( MathItem ? handled , error ) = handler ( prev ) ;
630+ if ( error != null ) return error ;
631+ else if ( HandleSuperscript ( ref handled , ref i , super ) . Error is { } superscriptError )
632+ return Result . Err ( superscriptError ) ;
633+ return Result . Ok ( handled ) ;
634+ } else return $ "Unrecognized bracket pair { contextInfo . KnownOpening } { rightBracket } ";
635+ case Atoms . Inner { LeftBoundary . Nucleus : var left , InnerList : var inner , RightBoundary . Nucleus : var right } :
555636 ( @this , error ) = Transform ( inner ) ;
556637 if ( error != null ) return error ;
557638 ( @this , error ) =
558- BracketHandlers . TryGetValue ( ( left , right ) , out handler )
639+ InnerHandlers . TryGetValue ( ( left , right ) , out handler )
559640 ? handler ( @this )
560641 : $ "Unrecognized bracket pair { left ?? "(empty)" } { right ?? "(empty)" } ";
561642 if ( error != null ) return error ;
@@ -589,7 +670,7 @@ Result HandleSuperscript(ref MathItem? @this, MathList superscript) {
589670 case Atoms . Space _:
590671 case Atoms . Ordinary { Nucleus : var nucleus } when string . IsNullOrWhiteSpace ( nucleus ) :
591672 break ;
592- case Atoms . Inner inner :
673+ case Atoms . Inner { LeftBoundary . Nucleus : "(" or "[" , RightBoundary . Nucleus : ")" or "]" } inner :
593674 var superscript = inner . Superscript ;
594675 bracketArgument = inner . InnerList ;
595676 goto stealExponent ;
@@ -685,17 +766,17 @@ chainedComparisonTarget is { } target
685766 return prev ;
686767 }
687768
688- handlePostfix :
769+ handlePostfix :
689770 ( @this , error ) =
690771 prev . AsEntity ( "left operand for " + atom . Nucleus ) . Bind ( e => ( MathItem ) handlePostfix ( e ) ) ;
691772 if ( error != null ) return error ;
692773 prev = null ; // We used up prev, don't keep it
693774 goto handleThis ;
694775
695- handleThis :
776+ handleThis :
696777 if ( ! subscriptAllowed && atom . Subscript . Count > 0 )
697778 return $ "Subscripts are unsupported for { atom . TypeName } { atom . Nucleus } ";
698- error = HandleSuperscript ( ref @this , atom . Superscript ) . Error ;
779+ error = HandleSuperscript ( ref @this , ref i , atom . Superscript ) . Error ;
699780 if ( error != null ) return error ;
700781 Entity ? prevEntity , thisEntity ;
701782 ( prevEntity , error ) =
@@ -707,7 +788,7 @@ chainedComparisonTarget is { } target
707788 if ( error != null ) return error ;
708789 prev = prevEntity * thisEntity ;
709790 break ;
710- }
791+ }
711792 }
712793 if ( ContextInfo . TryGetValue ( prec , out var info ) )
713794 return "Missing " + info . InferredClosing ;
0 commit comments