1- import React , { useEffect } from 'react' ;
2- import * as Contexts from './HerbieContext' ;
1+ import React , { useEffect } from 'react' ;
2+ import * as HerbieContext from './HerbieContext' ;
33import * as fpcorejs from './lib/fpcore' ;
44import { Sample } from './HerbieTypes' ;
5- import { analyzeErrorExpression , ErrorExpressionResponse } from './lib/herbiejs' ;
5+ import * as types from './HerbieTypes' ;
6+ import { analyzeErrorExpression } from './lib/herbiejs' ;
7+ import { ErrorExpressionResponse , } from './HerbieTypes'
8+ import Mermaid from './LocalError/Mermaid' ;
9+
10+ function localErrorTreeAsMermaidGraph (
11+ tree : types . LocalErrorTree ,
12+ bits : number ,
13+ currentLocation : Array < number > ,
14+ targetLocation : Array < number >
15+ ) {
16+ let edges = [ ] as string [ ] ;
17+ let colors = { } as Record < string , string > ;
18+ let counter = 0 ;
19+
20+ const isLeaf = ( n : types . LocalErrorTree ) => n [ 'children' ] . length === 0 ;
21+ const formatName = ( id : string , name : string , err : string ) =>
22+ id + '[<span class=nodeLocalError title=' + err + '>' + name + '</span>]' ;
23+
24+ const locationsMatch = ( loc1 : Array < number > , loc2 : Array < number > ) =>
25+ JSON . stringify ( loc1 ) === JSON . stringify ( loc2 ) ;
26+
27+ function loop ( n : types . LocalErrorTree , currentLoc : Array < number > ) {
28+ const name = n [ 'e' ] ;
29+ const children = n [ 'children' ] ;
30+ const avg_error = n [ 'avg-error' ] ;
31+
32+ const id = 'N' + counter ++ ;
33+ const nodeName = formatName ( id , name , avg_error ) ;
34+
35+ for ( const [ index , child ] of children . entries ( ) ) {
36+ const childLocation = [ ...currentLoc , index + 1 ] ;
37+
38+ if ( locationsMatch ( childLocation , targetLocation ) ) {
39+ console . log ( `Setting color to red for node at location: ${ childLocation } ` ) ;
40+ colors [ id ] = 'ff0000' ;
41+ }
42+
43+ const cName = loop ( child , childLocation ) ;
44+ edges . push ( cName + ' --> ' + nodeName ) ;
45+ }
46+
47+ return nodeName ;
48+ }
49+
50+ loop ( tree , currentLocation ) ;
51+
52+ if ( isLeaf ( tree ) ) {
53+ const name = tree [ 'e' ] ;
54+ const avg_error = tree [ 'avg-error' ] ;
55+ edges . push ( formatName ( 'N0' , name , avg_error ) ) ;
56+ }
57+
58+ for ( const id in colors ) {
59+ edges . push ( 'style ' + id + ' fill:#' + colors [ id ] ) ;
60+ }
61+
62+ return 'flowchart RL\n\n' + edges . join ( '\n' ) ;
63+ }
664
765interface ErrorExplanationProps {
8- expressionId : number ;
66+ expressionId : number ;
967}
1068
11- const ErrorExplanation : React . FC < ErrorExplanationProps > = ( props ) => {
12- // Export the expression to a language of the user's choice
13- const [ expressions ] = Contexts . useGlobal ( Contexts . ExpressionsContext ) ;
14- const [ selectedPoint ] = Contexts . useGlobal ( Contexts . SelectedPointContext ) ;
15- const [ serverUrl ] = Contexts . useGlobal ( Contexts . ServerContext ) ;
16- const [ spec ] = Contexts . useGlobal ( Contexts . SpecContext ) ;
17-
18- // Get the expression text
19- const expressionText = expressions [ props . expressionId ] . text ;
20-
21- const [ errorResponse , setErrorResponse ] = React . useState < ErrorExpressionResponse | null > ( null ) ;
22-
23- const translateExpression = async ( ) => {
24-
25- if ( selectedPoint ) {
26-
27- const vars = fpcorejs . getVarnamesMathJS ( expressionText ) ;
28- const specVars = fpcorejs . getVarnamesMathJS ( spec . expression ) ;
29- const modSelectedPoint = selectedPoint . filter ( ( xi , i ) => vars . includes ( specVars [ i ] ) ) ;
30-
31- // Make server call to get translation when user submits
32- try {
33- const host = serverUrl ;
34- const response = await analyzeErrorExpression (
35- fpcorejs . mathjsToFPCore ( expressionText ) ,
36- { points : [ [ modSelectedPoint , 1e308 ] ] } as Sample ,
37- host
38- ) ;
39- setErrorResponse ( response ) ;
40-
41- } catch ( error ) {
42- console . error ( 'Error:' , error ) ;
43- }
44- }
45- } ;
46-
47- useEffect ( ( ) => {
48- translateExpression ( ) ;
49- } , [ expressionText , selectedPoint ] ) ;
50-
51- return ( < div >
52- { /* Display the export code */ }
53- { errorResponse && errorResponse . explanation . length > 0 ? (
54- < div >
55- < p > Operator: { errorResponse . explanation [ 0 ] [ 0 ] } </ p >
56- < p > Expression: { errorResponse . explanation [ 0 ] [ 1 ] } </ p >
57- < p > Type: { errorResponse . explanation [ 0 ] [ 2 ] } </ p >
58- < p > Occurrences: { errorResponse . explanation [ 0 ] [ 3 ] } </ p >
59- < p > Errors: { errorResponse . explanation [ 0 ] [ 4 ] } </ p >
60- < pre > Details: { JSON . stringify ( errorResponse . explanation [ 0 ] [ 5 ] , null , 2 ) } </ pre >
61- </ div >
62- ) : (
63- < p > No explanation available.</ p >
64- ) }
69+ function ErrorExplanation ( { expressionId } : { expressionId : number } ) {
70+ const [ expressions ] = HerbieContext . useGlobal ( HerbieContext . ExpressionsContext ) ;
71+ const [ selectedPoint ] = HerbieContext . useGlobal ( HerbieContext . SelectedPointContext ) ;
72+ const [ errorResponse , setErrorResponse ] = React . useState < ErrorExpressionResponse | null > ( null ) ;
73+ const [ selectedPointsLocalError ] = HerbieContext . useGlobal ( HerbieContext . SelectedPointsLocalErrorContext ) ;
74+ const [ selectedPointsErrorExp , ] = HerbieContext . useGlobal ( HerbieContext . SelectedPointsErrorExpContext ) ;
75+ const [ averageLocalErrors ] = HerbieContext . useGlobal ( HerbieContext . AverageLocalErrorsContext ) ;
76+ const [ selectedSampleId ] = HerbieContext . useGlobal ( HerbieContext . SelectedSampleIdContext ) ;
6577
66- </ div >
78+ const pointLocalError = selectedPointsLocalError . find ( a => a . expressionId === expressionId ) ?. error ;
79+
80+ console . log ( selectedPointsErrorExp )
81+ const localError = selectedPoint && pointLocalError
82+ ? pointLocalError
83+ : averageLocalErrors . find ( ( localError ) => localError . sampleId === selectedSampleId && localError . expressionId === expressionId ) ?. errorTree ;
84+
85+
86+ // Use useEffect to update the errorResponse state
87+ useEffect ( ( ) => {
88+ console . log ( expressionId )
89+ console . log ( expressions [ expressionId ] . text )
90+ const pointErrorExp = selectedPointsErrorExp . find ( a => a . expressionId === expressionId ) ?. error ;
91+ setErrorResponse ( pointErrorExp || null ) ; // If pointErrorExp is undefined, set null
92+ } , [ selectedPointsErrorExp ] ) ; // Run this effect whenever pointErrorExp changes
93+
94+
95+
96+ if ( ! localError ) {
97+ return (
98+ < div className = "local-error not-computed" >
99+ < div > Please select a point on the error plot to compute local error.</ div >
100+ </ div >
67101 ) ;
102+ }
103+
104+ return (
105+ < div >
106+ { errorResponse && errorResponse . explanation . length > 0 ? (
107+ < div >
108+ < p > Operator: { errorResponse . explanation [ 0 ] [ 0 ] } </ p >
109+ < p > Expression: { errorResponse . explanation [ 0 ] [ 1 ] } </ p >
110+ < p > Type: { errorResponse . explanation [ 0 ] [ 2 ] } </ p >
111+ < p > Occurrences: { errorResponse . explanation [ 0 ] [ 3 ] } </ p >
112+ < p > Errors: { errorResponse . explanation [ 0 ] [ 4 ] } </ p >
113+ < pre > Details: { JSON . stringify ( errorResponse . explanation [ 0 ] [ 5 ] , null , 2 ) } </ pre >
114+ </ div >
115+ ) : (
116+ < p > No explanation available.</ p >
117+ ) }
118+ < div className = "local-error-graph" >
119+ < Mermaid chart = { localErrorTreeAsMermaidGraph ( localError , 64 , [ ] , [ 1 ] ) } />
120+ </ div >
121+ </ div >
122+ ) ;
68123} ;
69124
70- export default ErrorExplanation ;
125+ export default ErrorExplanation ;
0 commit comments