@@ -25,6 +25,8 @@ import { shouldNeverHappen } from "@syntest/search";
2525export class BranchDistanceVisitor extends AbstractSyntaxTreeVisitor {
2626 protected static override LOGGER : Logger ;
2727
28+ protected _stringAlphabet : string ;
29+
2830 private _K = 1 ; // punishment factor
2931
3032 private _variables : Record < string , unknown > ;
@@ -34,8 +36,13 @@ export class BranchDistanceVisitor extends AbstractSyntaxTreeVisitor {
3436 private _isDistanceMap : Map < string , boolean > ;
3537 private _distance : number ;
3638
37- constructor ( variables : Record < string , unknown > , inverted : boolean ) {
39+ constructor (
40+ stringAlphabet : string ,
41+ variables : Record < string , unknown > ,
42+ inverted : boolean
43+ ) {
3844 super ( "" ) ;
45+ this . _stringAlphabet = stringAlphabet ;
3946 this . _variables = variables ;
4047 this . _inverted = inverted ;
4148
@@ -282,22 +289,30 @@ export class BranchDistanceVisitor extends AbstractSyntaxTreeVisitor {
282289 }
283290 case "!" : {
284291 if ( argumentIsDistance ) {
285- value = this . _inverted ? 1 - argumentValue : argumentValue ;
292+ value = this . _inverted
293+ ? this . _normalize ( 1 - argumentValue )
294+ : this . _normalize ( argumentValue ) ;
286295 } else {
287296 if ( this . _inverted ) {
288- value =
289- typeof argumentValue === "number"
290- ? this . _normalize ( Math . abs ( 0 - argumentValue ) )
291- : argumentValue
292- ? 0
293- : this . _normalize ( 1 ) ;
297+ if ( typeof argumentValue === "boolean" ) {
298+ value = argumentValue ? 0 : this . _normalize ( 1 ) ;
299+ } else if ( typeof argumentValue === "number" ) {
300+ value = argumentValue ? 0 : this . _normalize ( 1 ) ;
301+ } else {
302+ // could be other type
303+ value = argumentValue ? 0 : this . _normalize ( Number . MAX_VALUE ) ;
304+ }
294305 } else {
295- value =
296- typeof argumentValue === "number"
306+ if ( typeof argumentValue === "boolean" ) {
307+ value = argumentValue ? this . _normalize ( 1 ) : 0 ;
308+ } else if ( typeof argumentValue === "number" ) {
309+ value = argumentValue
297310 ? this . _normalize ( Math . abs ( 0 - argumentValue ) )
298- : argumentValue
299- ? this . _normalize ( 1 )
300311 : 0 ;
312+ } else {
313+ // could be other type
314+ value = argumentValue ? this . _normalize ( Number . MAX_VALUE ) : 0 ;
315+ }
301316 }
302317 }
303318 break ;
@@ -457,7 +472,7 @@ export class BranchDistanceVisitor extends AbstractSyntaxTreeVisitor {
457472 typeof leftValue === "string" &&
458473 typeof rightValue === "string"
459474 ) {
460- value = this . _editDistDP ( leftValue , rightValue ) ;
475+ value = this . _realCodedEditDistance ( leftValue , rightValue ) ;
461476 } else if (
462477 typeof leftValue === "boolean" &&
463478 typeof rightValue === "boolean"
@@ -466,9 +481,9 @@ export class BranchDistanceVisitor extends AbstractSyntaxTreeVisitor {
466481 } else {
467482 // TODO type difference?!
468483 if ( operator === "===" ) {
469- value = leftValue === rightValue ? 0 : 1 ;
484+ value = leftValue === rightValue ? 0 : Number . MAX_VALUE ;
470485 } else {
471- value = leftValue == rightValue ? 0 : 1 ;
486+ value = leftValue == rightValue ? 0 : Number . MAX_VALUE ;
472487 }
473488 }
474489 break ;
@@ -488,18 +503,18 @@ export class BranchDistanceVisitor extends AbstractSyntaxTreeVisitor {
488503 value = 1 ; // TODO should this one be inverted?
489504 } else {
490505 if ( this . _inverted ) {
491- value = leftValue in rightValue ? 1 : 0 ;
506+ value = leftValue in rightValue ? Number . MAX_VALUE : 0 ;
492507 } else {
493- value = leftValue in rightValue ? 0 : 1 ;
508+ value = leftValue in rightValue ? 0 : Number . MAX_VALUE ;
494509 }
495510 }
496511 break ;
497512 }
498513 case "instanceof" : {
499514 if ( this . _inverted ) {
500- value = leftValue instanceof rightValue ? 1 : 0 ;
515+ value = leftValue instanceof rightValue ? Number . MAX_VALUE : 0 ;
501516 } else {
502- value = leftValue instanceof rightValue ? 0 : 1 ;
517+ value = leftValue instanceof rightValue ? 0 : Number . MAX_VALUE ;
503518 }
504519 break ;
505520 }
@@ -582,36 +597,82 @@ export class BranchDistanceVisitor extends AbstractSyntaxTreeVisitor {
582597 public LogicalExpression : ( path : NodePath < t . LogicalExpression > ) => void = (
583598 path
584599 ) => {
600+ let operator = path . node . operator ;
601+
585602 const left = path . get ( "left" ) ;
586603 const right = path . get ( "right" ) ;
587604
605+ if ( this . _inverted ) {
606+ if ( operator === "||" ) {
607+ operator = "&&" ;
608+ } else if ( operator === "&&" ) {
609+ operator = "||" ;
610+ }
611+ }
612+
588613 left . visit ( ) ;
589614 right . visit ( ) ;
590615
591616 let leftValue = < any > this . _valueMap . get ( left . toString ( ) ) ;
592617 let rightValue = < any > this . _valueMap . get ( right . toString ( ) ) ;
593618
594619 if ( ! this . _isDistanceMap . get ( left . toString ( ) ) ) {
595- leftValue = leftValue ? 0 : 1 ;
620+ // should we check for number /booleans here?
621+ if ( this . _inverted ) {
622+ if ( typeof leftValue === "boolean" ) {
623+ leftValue = leftValue ? this . _normalize ( 1 ) : 0 ;
624+ } else if ( typeof leftValue === "number" ) {
625+ leftValue = leftValue ? this . _normalize ( Math . abs ( 0 - leftValue ) ) : 0 ;
626+ } else {
627+ leftValue = leftValue ? this . _normalize ( Number . MAX_VALUE ) : 0 ;
628+ }
629+ } else {
630+ if ( typeof leftValue === "boolean" ) {
631+ leftValue = leftValue ? 0 : this . _normalize ( 1 ) ;
632+ } else if ( typeof leftValue === "number" ) {
633+ leftValue = leftValue ? 0 : this . _normalize ( 1 ) ;
634+ } else {
635+ leftValue = leftValue ? 0 : this . _normalize ( Number . MAX_VALUE ) ;
636+ }
637+ }
596638 }
597639
598640 if ( ! this . _isDistanceMap . get ( right . toString ( ) ) ) {
599- rightValue = rightValue ? 0 : 1 ;
641+ // should we check for number /booleans here?
642+ if ( this . _inverted ) {
643+ if ( typeof rightValue === "boolean" ) {
644+ rightValue = rightValue ? this . _normalize ( 1 ) : 0 ;
645+ } else if ( typeof rightValue === "number" ) {
646+ rightValue = rightValue
647+ ? this . _normalize ( Math . abs ( 0 - rightValue ) )
648+ : 0 ;
649+ } else {
650+ rightValue = rightValue ? this . _normalize ( Number . MAX_VALUE ) : 0 ;
651+ }
652+ } else {
653+ if ( typeof rightValue === "boolean" ) {
654+ rightValue = rightValue ? 0 : this . _normalize ( 1 ) ;
655+ } else if ( typeof rightValue === "number" ) {
656+ rightValue = rightValue ? 0 : this . _normalize ( 1 ) ;
657+ } else {
658+ rightValue = rightValue ? 0 : this . _normalize ( Number . MAX_VALUE ) ;
659+ }
660+ }
600661 }
601662
602663 let value : unknown ;
603- switch ( path . node . operator ) {
664+ switch ( operator ) {
604665 case "||" : {
605- value = this . _normalize ( Math . min ( leftValue , rightValue ) ) ;
666+ value = Math . min ( leftValue , rightValue ) ; // should this be normalized?
606667 break ;
607668 }
608669 case "&&" : {
609- value = this . _normalize ( leftValue + rightValue ) ;
670+ value = this . _normalize ( leftValue + rightValue ) ; // should this be normalized?
610671 break ;
611672 }
612673 case "??" : {
613674 // TODO no clue
614- value = 0 ;
675+ value = this . _normalize ( Number . MAX_VALUE ) ;
615676 break ;
616677 }
617678 default : {
@@ -626,7 +687,115 @@ export class BranchDistanceVisitor extends AbstractSyntaxTreeVisitor {
626687 path . skip ( ) ;
627688 } ;
628689
629- private _editDistDP ( string1 : string , string2 : string ) {
690+ private minimum ( a : number , b : number , c : number ) {
691+ let mi ;
692+
693+ mi = a ;
694+ if ( b < mi ) {
695+ mi = b ;
696+ }
697+
698+ if ( c < mi ) {
699+ mi = c ;
700+ }
701+ return mi ;
702+ }
703+
704+ protected _realCodedEditDistance ( s : string , t : string ) {
705+ const d : number [ ] [ ] = [ ] ; // matrix
706+ let index ; // iterates through s
707+ let index_ ; // iterates through t
708+ let s_index ; // ith character of s
709+ let t_index ; // jth character of t
710+ let cost ; // cost
711+
712+ if ( s == undefined && t != undefined ) {
713+ return t . length ;
714+ }
715+ if ( t == undefined && s != undefined ) {
716+ return s . length ;
717+ }
718+ if ( s == undefined && t == undefined ) {
719+ return Number . MAX_VALUE ;
720+ }
721+ // Step 1
722+
723+ const n = s . length ; // length of s
724+ const m = t . length ; // length of t
725+ if ( n == 0 ) {
726+ return m ;
727+ }
728+ if ( m == 0 ) {
729+ return n ;
730+ }
731+
732+ for ( let indexA = 0 ; indexA < n + 1 ; indexA ++ ) {
733+ const row = [ ] ;
734+ for ( let indexB = 0 ; indexB < m + 1 ; indexB ++ ) {
735+ row . push ( 0 ) ;
736+ }
737+ d . push ( row ) ;
738+ }
739+
740+ // Step 2
741+
742+ for ( index = 0 ; index <= n ; index ++ ) {
743+ d [ index ] [ 0 ] = index ;
744+ }
745+
746+ for ( index_ = 0 ; index_ <= m ; index_ ++ ) {
747+ d [ 0 ] [ index_ ] = index_ ;
748+ }
749+
750+ // Step 3
751+
752+ for ( index = 1 ; index <= n ; index ++ ) {
753+ s_index = s . charAt ( index - 1 ) ;
754+
755+ // Step 4
756+
757+ for ( index_ = 1 ; index_ <= m ; index_ ++ ) {
758+ t_index = t . charAt ( index_ - 1 ) ;
759+
760+ // Step 5
761+
762+ if ( s_index == t_index ) {
763+ cost = 0 ;
764+ } else {
765+ //
766+ if (
767+ ! this . _stringAlphabet . includes ( t_index ) ||
768+ ! this . _stringAlphabet . includes ( s_index )
769+ ) {
770+ BranchDistanceVisitor . LOGGER . warn (
771+ `cannot search for character missing from the sampling alphabet one of these is missing: ${ t_index } , ${ s_index } `
772+ ) ;
773+ cost = Number . MAX_VALUE ;
774+ } else {
775+ cost = Math . abs (
776+ this . _stringAlphabet . indexOf ( s_index ) -
777+ this . _stringAlphabet . indexOf ( t_index )
778+ ) ;
779+ }
780+ cost = this . _normalize ( cost ) ;
781+ }
782+
783+ // Step 6
784+
785+ d [ index ] [ index_ ] = this . minimum (
786+ d [ index - 1 ] [ index_ ] + 1 ,
787+ d [ index ] [ index_ - 1 ] + 1 ,
788+ d [ index - 1 ] [ index_ - 1 ] + cost
789+ ) ;
790+ }
791+ }
792+
793+ // Step 7
794+
795+ return d [ n ] [ m ] ;
796+ }
797+
798+ protected _editDistDP ( string1 : string , string2 : string ) {
630799 const m = string1 . length ;
631800 const n = string2 . length ;
632801 const table = [ ] ;
0 commit comments