@@ -100,6 +100,20 @@ function hslToRgb(h: number, s: number, l: number) {
100100 return rgbToHex ( round ( r * 255 ) , round ( g * 255 ) , round ( b * 255 ) ) ;
101101}
102102
103+ // Helper function to permute sample points to match expression variable order
104+ function permuteSampleToExpressionOrder ( sample : HerbieTypes . Sample , expressionText : string , specExpression : string ) : HerbieTypes . Sample {
105+ const specVars = fpcorejs . getVarnamesMathJS ( specExpression ) ;
106+ const permutedVars = fpcorejs . getVarnamesMathJS ( expressionText ) ;
107+ const permutedIndices = permutedVars . map ( v => specVars . indexOf ( v ) ) ;
108+
109+ const permutedSamplePoints = sample . points . map ( ( [ point , error ] ) : [ HerbieTypes . ordinalPoint , number ] => {
110+ const newPoint : HerbieTypes . ordinalPoint = point . map ( ( _ , idx ) => point [ permutedIndices [ idx ] ] ) ;
111+ return [ newPoint , error ] ;
112+ } ) ;
113+
114+ return new HerbieTypes . Sample ( permutedSamplePoints , sample . specId , sample . inputRangesId , sample . id ) ;
115+ }
116+
103117export function addJobRecorder ( _ : typeof herbiejs ) {
104118 const [ , setJobCount ] = HerbieContext . useReducerGlobal ( HerbieContext . JobCountContext )
105119 function jobRecorder < P extends any [ ] , Q > ( f : ( ...args : P ) => Q ) {
@@ -450,15 +464,7 @@ function HerbieUIInner() {
450464 // HACK to make sampling work on Herbie side
451465 const specVars = fpcorejs . getVarnamesMathJS ( spec . expression )
452466 // re-order the sample points to match the expression
453- // TODO Write a function here to abstract the re-ordering of sample points
454-
455- const permutedVars = fpcorejs . getVarnamesMathJS ( expression . text )
456- const permutedIndices = permutedVars . map ( v => specVars . indexOf ( v ) ) ;
457- const permutedSamplePoints = sample . points . map ( ( [ point , error ] ) : [ HerbieTypes . ordinalPoint , number ] => {
458- const newPoint : HerbieTypes . ordinalPoint = point . map ( ( _ , idx ) => point [ permutedIndices [ idx ] ] ) ;
459- return [ newPoint , error ] ;
460- } )
461- const permutedSample = new HerbieTypes . Sample ( permutedSamplePoints , sample . specId , sample . inputRangesId , sample . id ) ;
467+ const permutedSample = permuteSampleToExpressionOrder ( sample , expression . text , spec . expression ) ;
462468 const analysis = await herbiejsJobs . analyzeExpression ( fpcorejs . mathjsToFPCore ( expression . text , spec . expression , specVars ) , permutedSample , serverUrl )
463469 // analysis now looks like [[[x1, y1], e1], ...]. We want to average the e's
464470
@@ -498,8 +504,8 @@ function HerbieUIInner() {
498504
499505 try {
500506 const formula = fpcorejs . mathjsToFPCore ( expression . text ) ;
501- // TODO permute the sample points to match the expression
502- const costData = await herbiejsJobs . getCost ( formula , sample , serverUrl ) ;
507+ const permutedSample = permuteSampleToExpressionOrder ( sample , expression . text , spec . expression ) ;
508+ const costData = await herbiejsJobs . getCost ( formula , permutedSample , serverUrl ) ;
503509
504510 return new HerbieTypes . CostAnalysis ( expression . id , costData ) ;
505511 } catch ( e ) {
@@ -689,14 +695,16 @@ function HerbieUIInner() {
689695 const vars = fpcorejs . getVarnamesMathJS ( expression . text )
690696 const specVars = fpcorejs . getVarnamesMathJS ( spec . expression )
691697 const modSelectedPoint = selectedPoint . filter ( ( xi , i ) => vars . includes ( specVars [ i ] ) )
692- // TODO permute the sample points to match the expression
698+ // Create temporary sample and permute it
699+ const tempSample = new HerbieTypes . Sample ( [ [ modSelectedPoint , 1e308 ] ] , spec . id , - 1 , - 1 ) ;
700+ const permutedSample = permuteSampleToExpressionOrder ( tempSample , expression . text , spec . expression ) ;
693701 localErrors . push (
694702 new HerbieTypes . PointLocalErrorAnalysis (
695703 expression . id ,
696704 selectedPoint ,
697705 await herbiejsJobs . analyzeLocalError (
698706 fpcorejs . mathjsToFPCore ( expression . text ) ,
699- { points : [ [ modSelectedPoint , 1e308 ] ] } as HerbieTypes . Sample ,
707+ permutedSample ,
700708 serverUrl
701709 )
702710 )
@@ -722,14 +730,16 @@ function HerbieUIInner() {
722730 const vars = fpcorejs . getVarnamesMathJS ( expression . text )
723731 const specVars = fpcorejs . getVarnamesMathJS ( spec . expression )
724732 const modSelectedPoint = selectedPoint . filter ( ( xi , i ) => vars . includes ( specVars [ i ] ) )
725- // TODO permute the sample points to match the expression
733+ // Create temporary sample and permute it
734+ const tempSample = new HerbieTypes . Sample ( [ [ modSelectedPoint , 1e308 ] ] , spec . id , - 1 , - 1 ) ;
735+ const permutedSample = permuteSampleToExpressionOrder ( tempSample , expression . text , spec . expression ) ;
726736 errorExp . push (
727737 new HerbieTypes . PointErrorExpAnalysis (
728738 expression . id ,
729739 selectedPoint ,
730740 await herbiejsJobs . analyzeErrorExpression (
731741 fpcorejs . mathjsToFPCore ( expression . text ) ,
732- { points : [ [ modSelectedPoint , 1e308 ] ] } as HerbieTypes . Sample ,
742+ permutedSample ,
733743 serverUrl
734744 )
735745 )
0 commit comments