Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346############################################################################# ## ## CAP package ## ## Copyright 2014, Sebastian Gutsche, TU Kaiserslautern ## Sebastian Posur, RWTH Aachen ## ############################################################################# ################################# ## ## Tool methods ## ################################# ## Returns true if string represents an integer and ## converting is save, false otherwise. InstallGlobalFunction( STRING_REPRESENTS_INTEGER, i -> ForAll( i, j -> j in "0123456789" ) ); ## Converts to int if string is an int, ## returns fail otherwise InstallGlobalFunction( Int_SAVE, function( string ) if STRING_REPRESENTS_INTEGER( string ) then return Int( string ); else return fail; fi; end ); ##Splits string at occourences of substring BindGlobal( "SPLIT_STRING_MULTIPLE", function( string, substring ) local list, lenght_substring, current_pos; list := [ ]; lenght_substring := Length( substring ); current_pos := PositionSublist( string, substring ); while true do current_pos := PositionSublist( string, substring ); if current_pos = fail then Add( list, string ); break; fi; Add( list, string{[ 1 .. current_pos - 1 ]} ); string := string{[ current_pos + lenght_substring .. Length( string ) ]}; od; return list; end ); ## If string is true or false, method returns ## the corresponding bool. If string represents an int, ## method returns this int. Fail otherwise. BindGlobal( "CONVERT_STRING_TO_BOOL_OR_INT", function( string ) string := LowercaseString( NormalizedWhitespace( string ) ); if string = "true" then return true; elif string = "false" then return false; else return Int_SAVE( string ); fi; end ); ## Splits theorem at | and vdash, ## returns a list with three entries, ## and throws an error otherwise. BindGlobal( "SPLIT_THEOREM", function( theorem_string ) local return_rec; return_rec := rec( ); theorem_string := SplitString( theorem_string, "|" ); if Length( theorem_string ) <> 2 then return "no unique | found"; fi; return_rec!.context := NormalizedWhitespace( theorem_string[ 1 ] ); theorem_string := SPLIT_STRING_MULTIPLE( theorem_string[ 2 ], "vdash" ); if Length( theorem_string ) <> 2 then return "no unique vdash found"; fi; return_rec!.source := NormalizedWhitespace( theorem_string[ 1 ] ); return_rec!.range := NormalizedWhitespace( theorem_string[ 2 ] ); return return_rec; end ); ## Returns an empty list if string is empty. ## Splits string at ',' if not in ( ) or [ ]. BindGlobal( "SPLIT_KOMMAS_NOT_IN_BRACKETS", function( string ) local return_list, bracket_count, i, positions; if Length( string ) = 0 then return [ ]; fi; positions := [ 0 ]; ## Yes bracket_count := 0; for i in [ 1 .. Length( string ) ] do if string[ i ] in [ '(', '[' ] then bracket_count := bracket_count + 1; elif string[ i ] in [ ')', ']' ] then bracket_count := bracket_count - 1; elif bracket_count = 0 and string[ i ] = ',' then Add( positions, i ); fi; od; Add( positions, Length( string ) + 1 ); ## Yes return_list := [ ]; for i in [ 1 .. Length( positions ) - 1 ] do Add( return_list, string{[ positions[ i ] + 1 .. positions[ i + 1 ] - 1 ]} ); od; return return_list; end ); ## If string is of form command( some ) it returns ## a record with command entry is the command string ## and arguments is the list of arguments BindGlobal( "COMMAND_AND_ARGUMENTS", function( command_string ) local command, arguments, first_pos, i; i := PositionSublist( command_string, "(" ); if i = fail then return fail; fi; command := command_string{[ 1 .. i - 1 ]}; first_pos := i; while PositionSublist( command_string, ")", i ) <> fail do i := PositionSublist( command_string, ")", i ); od; arguments := command_string{[ first_pos + 1 .. i - 1 ]}; return rec( command := command, arguments := SPLIT_KOMMAS_NOT_IN_BRACKETS( arguments ) ); end ); ## If string is [ some ] then it returns the corresponding list. Fail otherwise BindGlobal( "FIND_LISTING", function( string ) NormalizeWhitespace( string ); if string[ 1 ] = '[' and string[ Length( string ) ] = ']' then return SPLIT_KOMMAS_NOT_IN_BRACKETS( string{[ 2 .. Length( string ) - 1 ]} ); fi; return fail; end ); InstallGlobalFunction( "SPLIT_SINGLE_PART_RECURSIVE", function( single_part ) local listing; NormalizeWhitespace( single_part ); listing := FIND_LISTING( single_part ); if listing <> fail then return List( listing, SPLIT_SINGLE_PART_RECURSIVE ); fi; listing := SPLIT_KOMMAS_NOT_IN_BRACKETS( single_part ); if listing = [ ] then return List( listing, SPLIT_SINGLE_PART_RECURSIVE ); fi; listing := COMMAND_AND_ARGUMENTS( single_part ); if listing = fail then return single_part; fi; Apply( listing!.arguments, SPLIT_SINGLE_PART_RECURSIVE ); return listing; end ); BindGlobal( "SPLIT_SINGLE_PART", function( part ) local return_rec, temp_rec; return_rec := rec( ); part := SplitString( part, ":" ); Perform( part, NormalizedWhitespace ); if Length( part ) = 2 then return_rec!.bound_variables := part[ 1 ]; part := part[ 2 ]; else return_rec!.bound_variables := fail; part := part[ 1 ]; fi; temp_rec := SPLIT_SINGLE_PART_RECURSIVE( part ); return_rec!.command := temp_rec!.command; return_rec!.arguments := temp_rec!.arguments; return return_rec; end ); BindGlobal( "SANITIZE_ARGUMENT_LIST", function( string ) local list, arg, tmp_list, new_list, position; NormalizeWhitespace( string ); list := SplitString( string, "," ); ## collect lists arg := 1; new_list := [ ]; while arg <= Length( list ) do position := PositionSublist( list[ arg ], "[" ); if position = fail then Add( new_list, NormalizedWhitespace( list[ arg ] ) ); else tmp_list := [ ]; Remove( list[ arg ], position ); position := fail; while position = fail do Add( tmp_list, NormalizedWhitespace( list[ arg ] ) ); arg := arg + 1; position := PositionSublist( list[ arg ], "]" ); od; Remove( list[ arg ], position ); Add( tmp_list, NormalizedWhitespace( list[ arg ] ) ); Add( new_list, tmp_list ); fi; arg := arg + 1; od; return new_list; end ); ## Returns the part of string before the first occourence of substring. ## If substring is not present, the whole string is returned BindGlobal( "REMOVE_PART_AFTER_FIRST_SUBSTRING", function( string, substring ) local position; position := PositionSublist( string, substring ); if position = fail then return string; else return string{[ 1 .. position - 1 ]}; fi; end ); ## Returns the number of occourences of substring in string BindGlobal( "COUNT_SUBSTRING_APPEARANCE", function( string, substring ) string := SPLIT_STRING_MULTIPLE( string, substring ); return Length( string ) - 1; end ); BindGlobal( "FIND_PART_WHICH_CONTAINS_FUNCTION", function( part ) local nr_substring_close_bracket, return_record, splitted_part, predicate, func, variables, position_equal, value, position_close_bracket; nr_substring_close_bracket := COUNT_SUBSTRING_APPEARANCE( part, "(" ); if nr_substring_close_bracket < 2 then return fail; fi; if nr_substring_close_bracket > 2 then part := Concatenation( "this is not a valid part: ", part ); Error( part ); fi; return_record := rec( ); splitted_part := SplitString( part, "(" ); predicate := NormalizedWhitespace( splitted_part[ 1 ] ); func := NormalizedWhitespace( splitted_part[ 2 ] ); variables := NormalizedWhitespace( splitted_part[ 3 ] ); position_equal := PositionSublist( variables, "=" ); if position_equal <> fail then variables := SplitString( variables, "=" ); value := variables[ 2 ]; variables := variables[ 1 ]; value := CONVERT_STRING_TO_BOOL_OR_INT( value ); else value := true; fi; position_close_bracket := PositionSublist( variables, ")" ); if position_close_bracket = fail then Error( "some ) should have been found" ); else variables := variables{[ 1 .. position_close_bracket - 1 ]}; fi; return_record!.TheoremPart := rec( Value := value, ValueFunction := ValueGlobal( NormalizedWhitespace( predicate ) ), Object := "result" ); return_record!.Variables := SANITIZE_ARGUMENT_LIST( variables ); return_record!.Function := func; return return_record; end ); BindGlobal( "FIND_PREDICATE_VARIABLES", function( source_part, range_variables ) local split_source_part, func, predicate, variables, source_rec, bound_variable, value, position_exists, position_forall, i; split_source_part := SplitString( source_part, "(" ); if Length( split_source_part ) <> 2 then Error( "this should not happen, too many (" ); fi; source_rec := rec( ); ## find bound variables predicate := split_source_part[ 1 ]; variables := SplitString( split_source_part[ 2 ], "=" ); if Length( variables ) = 2 then value := CONVERT_STRING_TO_BOOL_OR_INT( variables[ 2 ] ); variables := variables[ 1 ]; else value := true; variables := variables[ 1 ]; fi; position_forall := PositionSublist( predicate, "forall" ); position_exists := PositionSublist( predicate, "exists" ); if Minimum( [ position_forall, position_exists ] ) <> fail then predicate := predicate{[ Minimum( [ position_forall, position_exists ] ) + 7 .. Length( predicate ) ]}; predicate := SplitString( predicate, ":" ); bound_variable := predicate[ 1 ]; predicate := predicate[ 2 ]; bound_variable := SPLIT_STRING_MULTIPLE( bound_variable, "in" ); bound_variable := List( bound_variable, NormalizedWhitespace ); bound_variable := Position( range_variables, bound_variable[ 2 ] ); if position_forall <> fail then bound_variable := [ bound_variable, "all" ]; else bound_variable := [ bound_variable, "any" ]; fi; else predicate := split_source_part[ 1 ]; variables := NormalizedWhitespace( variables{[ 1 .. PositionSublist( variables, ")" ) - 1 ]} ); for i in [ 1 .. Length( range_variables ) ] do if IsString( range_variables[ i ] ) then if variables = range_variables[ i ] then bound_variable := i; break; fi; else bound_variable := Position( range_variables[ i ], variables ); if bound_variable <> fail then bound_variable := [ i, bound_variable ]; break; else Unbind( bound_variable ); fi; fi; od; if not IsBound( bound_variable ) then variables := Concatenation( "variable ", variables, " was not recognized" ); fi; fi; return rec( Object := bound_variable, ValueFunction := ValueGlobal( NormalizedWhitespace( predicate ) ), Value := value ); end ); InstallGlobalFunction( PARSE_THEOREM_FROM_LATEX, function( theorem_string ) local variable_part, source_part, range_part, range_value, range_command, range_predicate, range_variables, position, i, current_source_rec, source_part_split, sources_list, int_conversion, theorem_record, result_function_variables, to_be_removed, source_part_copy; source_part := PositionSublist( theorem_string, "|" ); if source_part = fail then Error( "no | found" ); fi; range_part := PositionSublist( theorem_string, "vdash" ); if range_part = fail then Error( "no \vdash found" ); fi; theorem_string := SplitString( theorem_string, "|" ); theorem_string[ 2 ] := SPLIT_STRING_MULTIPLE( theorem_string[ 2 ], "\vdash" ); variable_part := NormalizedWhitespace( theorem_string[ 1 ] ); source_part := NormalizedWhitespace( theorem_string[ 2 ][ 1 ] ); range_part := NormalizedWhitespace( theorem_string[ 2 ][ 2 ] ); ##Sanitize variables variable_part := SplitString( variable_part, "," ); variable_part := List( variable_part, i -> SplitString( i, ":" ) ); variable_part := List( variable_part, i -> List( i, j -> NormalizedWhitespace( j ) ) ); ## split source part source_part_copy := ShallowCopy( source_part ); RemoveCharacters( source_part_copy, " \n\t\r" ); if source_part_copy = "()" then source_part := [ ]; else source_part := SplitString( source_part, "," ); fi; ## Rebuild Sourcepart, remove brackets source_part := List( source_part, NormalizedWhitespace ); i := 1; while i < Length( source_part ) do if COUNT_SUBSTRING_APPEARANCE( source_part[ i ], "(" ) > COUNT_SUBSTRING_APPEARANCE( source_part[ i ], ")" ) then source_part[ i ] := Concatenation( source_part[ i ], source_part[ i + 1 ] ); Remove( source_part, [ i + 1 ] ); else i := i + 1; fi; od; for i in [ 1 .. Length( source_part ) ] do if source_part[ i ][ 1 ] = '(' then source_part[ i ] := source_part[ i ]{[ 2 .. Length( source_part[ i ] ) - 1 ]}; fi; od; ## find function, and therefore return variables ## check range first theorem_record := FIND_PART_WHICH_CONTAINS_FUNCTION( range_part ); sources_list := [ ]; if theorem_record <> fail then ## Range contains the function theorem_record!.Range := theorem_record!.TheoremPart; Unbind( theorem_record!.TheoremPart ); result_function_variables := theorem_record!.Variables; Unbind( theorem_record!.Variables ); else theorem_record := rec( ); fi; to_be_removed := [ ]; for i in source_part do current_source_rec := FIND_PART_WHICH_CONTAINS_FUNCTION( i ); if current_source_rec <> fail then result_function_variables := current_source_rec!.Variables; theorem_record!.Function := current_source_rec!.Function; Add( sources_list, current_source_rec!.TheoremPart ); Add( to_be_removed, i ); fi; od; for i in to_be_removed do Remove( source_part, Position( source_part, i ) ); od; if not IsBound( theorem_record!.Function ) then Error( "no function found. This is the wrong parser" ); fi; if not IsBound( theorem_record!.Range ) then theorem_record!.Range := FIND_PREDICATE_VARIABLES( range_part, result_function_variables ); fi; for i in source_part do Add( sources_list, FIND_PREDICATE_VARIABLES( i, result_function_variables ) ); od; for i in [ 1 .. Length( result_function_variables ) ] do if not IsString( result_function_variables[ i ] ) then continue; fi; int_conversion := STRING_REPRESENTS_INTEGER( result_function_variables[ i ] ); if int_conversion = false then continue; fi; Add( sources_list, rec( Type := "testdirect", Object := i, Value := Int( result_function_variables[ i ] ) ) ); od; theorem_record!.Source := sources_list; for i in [ 1 .. Length( result_function_variables ) ] do if IsList( result_function_variables[ i ] ) and not IsString( result_function_variables[ i ] ) then result_function_variables[ i ] := Length( result_function_variables[ i ] ); else result_function_variables[ i ] := 0; fi; od; theorem_record!.Variable_list := result_function_variables; return theorem_record; end ); BindGlobal( "RETURN_STRING_BETWEEN_SUBSTRINGS", function( string, substring_begin, substring_end ) local substring, rest_of_string, position_begin, position_end; position_begin := PositionSublist( string, substring_begin ); position_end := PositionSublist( string, substring_end ); if position_begin = fail or position_end = fail then return fail; fi; substring := string{[ position_begin + Length( substring_begin ) .. position_end - 1 ]}; rest_of_string := string{[ position_end + Length( substring_end ) .. Length( string ) ]}; return [ substring, rest_of_string ]; end ); BindGlobal( "REMOVE_CHARACTERS_FROM_LATEX", function( string ) local i; for i in [ "&", "\\", "big", "\big", "$", "mathrm", "~" ] do string := Concatenation( SPLIT_STRING_MULTIPLE( string, i ) ); od; return string; end ); InstallGlobalFunction( "READ_LOGIC_FILE", function( filename, type ) local stream, file, line, substring, theorem_list, without_align, parser; if not IsExistingFile( filename ) then Error( "no file found" ); fi; if LowercaseString( type ) = "implication" then parser := PARSE_PREDICATE_IMPLICATION_FROM_LATEX; elif LowercaseString( type ) = "theorem" then parser := PARSE_THEOREM_FROM_LATEX; elif LowercaseString( type ) = "eval_rule" then parser := PARSE_EVAL_RULE_FROM_LATEX; else Error( "wrong parsing type" ); fi; stream := IO_File( filename, "r" ); line := IO_ReadLine( stream ); file := ""; while line <> "" do line := REMOVE_PART_AFTER_FIRST_SUBSTRING( line, "%" ); file := Concatenation( file, line ); line := IO_ReadLine( stream ); od; IO_Close( stream ); NormalizeWhitespace( file ); file := REMOVE_CHARACTERS_FROM_LATEX( file ); theorem_list := [ ]; while true do substring := RETURN_STRING_BETWEEN_SUBSTRINGS( file, "begin{sequent}", "end{sequent}" ); if substring = fail then break; fi; file := substring[ 2 ]; without_align := RETURN_STRING_BETWEEN_SUBSTRINGS( substring[ 1 ], "begin{align*}", "end{align*}" ); if without_align = fail then without_align := substring[ 1 ]; else without_align := without_align[ 1 ]; fi; Add( theorem_list, parser( without_align ) ); od; return theorem_list; end ); InstallGlobalFunction( READ_THEOREM_FILE, function( theorem_file ) return READ_LOGIC_FILE( theorem_file, "theorem" ); end ); ############################## ## ## True methods ## ############################## InstallGlobalFunction( "PARSE_PREDICATE_IMPLICATION_FROM_LATEX", function( theorem_string ) local variable_part, source_part, range_part, source_filter, range_filter, i; variable_part := SplitString( theorem_string, "|" ); source_part := SPLIT_STRING_MULTIPLE( variable_part[ 2 ], "vdash" ); range_part := source_part[ 2 ]; source_part := source_part[ 1 ]; variable_part := variable_part[ 1 ]; variable_part := NormalizedWhitespace( SplitString( variable_part, ":" )[ 2 ] ); source_part := SplitString( source_part, "," ); source_part := List( source_part, i -> NormalizedWhitespace( REMOVE_PART_AFTER_FIRST_SUBSTRING( i, "(" ) ) ); if Length( source_part ) = 0 then Error( "no source part found" ); fi; source_filter := ValueGlobal( source_part[ 1 ] ); Remove( source_part, 1 ); for i in source_part do source_filter := source_filter and ValueGlobal( i ); od; range_part := NormalizedWhitespace( REMOVE_PART_AFTER_FIRST_SUBSTRING( range_part, "(" ) ); range_part := ValueGlobal( range_part ); return rec( CellType := variable_part, Source := source_filter, Range := range_part ); end ); InstallGlobalFunction( READ_PREDICATE_IMPLICATION_FILE, function( predicate_file ) return READ_LOGIC_FILE( predicate_file, "implication" ); end ); ## PARSE_THEOREM_FROM_LATEX( "A:\Obj ~|~ \IsZero( A ) \vdash \IsProjective( A )" ); InstallGlobalFunction( SEARCH_FOR_VARIABLE_NAME_APPEARANCE, function( tree, names ) local appearance_list, current_result, i, j, name_position, return_list; ## command_case if IsRecord( tree ) then return SEARCH_FOR_VARIABLE_NAME_APPEARANCE( tree!.arguments, names ); fi; if IsString( tree ) then name_position := Position( names, tree ); return_list := List( names, i -> [ ] ); if name_position <> fail then return_list[ name_position ] := [ [ ] ]; fi; return return_list; fi; if IsList( tree ) and not IsString( tree ) then return_list := List( names, i -> [ ] ); for i in [ 1 .. Length( tree ) ] do current_result := SEARCH_FOR_VARIABLE_NAME_APPEARANCE( tree[ i ], names ); for j in [ 1 .. Length( current_result ) ] do current_result[ j ] := List( current_result[ j ], k -> Concatenation( [ i ], k ) ); return_list[ j ] := Concatenation( current_result[ j ], return_list[ j ] ); od; od; return return_list; fi; end ); ## InstallGlobalFunction( REPLACE_VARIABLE, function( tree, names, replacements ) local return_rec, entry; if IsString( tree ) and Position( names, tree ) <> fail then return replacements[ Position( names, tree ) ]; fi; if IsList( tree ) then return List( tree, i -> REPLACE_VARIABLE( i, names, replacements ) ); fi; if IsRecord( tree ) then return_rec := ShallowCopy( tree ); return_rec.arguments := REPLACE_VARIABLE( tree!.arguments, names, replacements ); return return_rec; fi; return tree; end ); InstallGlobalFunction( REPLACE_INTEGER_VARIABLE, function( tree ) local int; if IsString( tree ) then int := STRING_REPRESENTS_INTEGER( tree ); if int = false then return tree; else return Int( tree ); fi; fi; if IsList( tree ) then return List( tree, REPLACE_INTEGER_VARIABLE ); fi; if IsRecord( tree ) then int := ShallowCopy( tree ); int!.arguments := REPLACE_INTEGER_VARIABLE( tree!.arguments ); return int; fi; return tree; end ); InstallGlobalFunction( SEARCH_FOR_INT_VARIABLE_APPEARANCE, function( tree ) local appearance_list, current_result, i, j, int; if IsList( tree ) and Length( tree ) = 2 and IsString( tree[ 1 ] ) and IsList( tree[ 2 ] ) and not IsString( tree[ 2 ] ) then return SEARCH_FOR_INT_VARIABLE_APPEARANCE( tree[ 2 ] ); fi; if IsList( tree ) then appearance_list := [ ]; for i in [ 1 .. Length( tree ) ] do if IsString( tree[ i ] ) then int := STRING_REPRESENTS_INTEGER( tree[ i ] ); if int <> false then Add( appearance_list, [ [ i ], Int( tree[ i ] ) ] ); fi; elif IsList( tree[ i ] ) then current_result := SEARCH_FOR_INT_VARIABLE_APPEARANCE( tree[ i ] ); for j in current_result do Add( appearance_list, [ Concatenation( [ i ], j[ 1 ] ), j[ 2 ] ] ); od; fi; od; return appearance_list; fi; end ); ## InstallGlobalFunction( FIND_COMMAND_POSITIONS, function( tree, variable_names ) local current_command, command_list, i, current_return, j, return_list; command_list := [ ]; if IsList( tree ) and Length( tree ) = 2 and IsString( tree[ 1 ] ) and IsList( tree[ 2 ] ) and Position( variable_names, tree[ 1 ] ) = fail then command_list := [ [ [ ], tree[ 1 ] ] ]; tree := tree[ 2 ]; fi; if IsList( tree ) then for i in [ 1 .. Length( tree ) ] do current_return := FIND_COMMAND_POSITIONS( tree[ i ], variable_names ); for j in current_return do Add( command_list, [ Concatenation( [ i ], j[ 1 ] ), j[ 2 ] ] ); od; od; fi; return command_list; end ); BindGlobal( "FIND_VARIABLE_TYPES", function( var_list ) local i, j, next_type; var_list := List( var_list, i -> SplitString( i, ":" ) ); Perform( var_list, i -> List( i, NormalizedWhitespace ) ); for i in [ 1 .. Length( var_list ) ] do if Length( var_list[ i ] ) = 1 then for j in [ i + 1 .. Length( var_list ) ] do if IsBound( var_list[ j ][ 2 ] ) then var_list[ i ][ 2 ] := var_list[ j ][ 2 ]; break; fi; od; fi; if not IsBound( var_list[ i ][ 2 ] ) then Error( "no type for variable found" ); fi; var_list[ i ][ 2 ] := LowercaseString( NormalizedWhitespace( var_list[ i ][ 2 ] ) ); NormalizeWhitespace( var_list[ i ][ 1 ] ); od; return var_list; end ); InstallGlobalFunction( GIVE_VARIABLE_NAMES_WITH_POSITIONS_RECURSIVE, function( tree ) local i, var_list, current_var; if IsString( tree ) then return [ [ [ ], tree ] ]; elif IsList( tree ) then var_list := [ ]; for i in [ 1 .. Length( tree ) ] do current_var := GIVE_VARIABLE_NAMES_WITH_POSITIONS_RECURSIVE( tree[ i ] ); current_var := List( current_var, j -> [ Concatenation( [ i ], j[ 1 ] ), j[ 2 ] ] ); Append( var_list, current_var ); od; return var_list; elif IsRecord( tree ) then return GIVE_VARIABLE_NAMES_WITH_POSITIONS_RECURSIVE( tree!.arguments ); fi; return [ ]; end ); InstallGlobalFunction( "IS_LIST_WITH_INDEX", function( variable_name ) if PositionSublist( variable_name, "[" ) = fail then return false; fi; return true; end ); InstallGlobalFunction( "SPLIT_INTO_LIST_NAME_AND_INDEX", function( variable_name ) if not IS_LIST_WITH_INDEX( variable_name ) then return [ variable_name ]; fi; NormalizeWhitespace( variable_name ); variable_name := SplitString( variable_name, "[" ); variable_name[ 2 ] := variable_name[ 2 ]{[ 1 .. Length( variable_name[ 2 ] ) - 1 ]}; return List( variable_name, NormalizedWhitespace ); end ); InstallGlobalFunction( REPLACE_INTEGER_STRINGS_BY_INTS_AND_VARIABLES_BY_FAIL_RECURSIVE, function( record ) if IsRecord( record ) then return rec( command := record.command, arguments := REPLACE_INTEGER_STRINGS_BY_INTS_AND_VARIABLES_BY_FAIL_RECURSIVE( record!.arguments ) ); elif IsList( record ) and not IsString( record ) then return List( record, REPLACE_INTEGER_STRINGS_BY_INTS_AND_VARIABLES_BY_FAIL_RECURSIVE ); elif IsString( record ) and STRING_REPRESENTS_INTEGER( record ) then return Int_SAVE( record ); fi; return fail; end ); ## InstallGlobalFunction( PARSE_EVAL_RULE_FROM_LATEX, function( rule ) local split_record, variables, source, range, object_variables, list_variables, int_variables, range_source, range_replace, range_source_tree, variables_with_positions, variable_record, variable, possible_positions, equal_variable_pairs, current_variable_and_index, additional_position, range_replace_list_and_index, new_source_list, bound_variable_string, bound_variable_name, bound_variable_list_content, bound_variable_list_boundaries, i, return_rec, source_list, j; RemoveCharacters( rule, " \n\t\r" ); split_record := SPLIT_THEOREM( rule ); if IsString( split_record ) then Error( Concatenation( split_record ), " in ", rule ); fi; variables := split_record!.context; source := split_record!.source; range := split_record!.range; ## Sanitize variables and find type variables := SPLIT_KOMMAS_NOT_IN_BRACKETS( variables ); variables := FIND_VARIABLE_TYPES( variables ); object_variables := Filtered( variables, i -> i[ 2 ] in [ "obj", "mor" ] ); list_variables := Filtered( variables, i -> i[ 2 ] in [ "listobj", "listmor" ] ); int_variables := Filtered( variables, i -> i[ 2 ] in [ "int" ] ); list_variables := List( list_variables, i -> i[ 1 ] ); int_variables := List( int_variables, i -> i[ 1 ] ); ## Sanitize range, find positions of variables range := SplitString( range, "=" ); if Length( range ) <> 2 then Error( "range must contain exactly one =" ); fi; range_source := range[ 1 ]; range_replace := range[ 2 ]; range_replace := ReplacedString( range_replace, "_{Mor}", "" ); range_replace := ReplacedString( range_replace, "_{Obj}", "" ); range_source_tree := SPLIT_SINGLE_PART( range_source ); ## Find variable positions variables_with_positions := GIVE_VARIABLE_NAMES_WITH_POSITIONS_RECURSIVE( range_source_tree ); ## Build complete variable record: variable_record := rec( ); for variable in variables do possible_positions := Filtered( variables_with_positions, i -> i[ 2 ] = variable[ 1 ] ); if possible_positions = [ ] then continue; fi; variable_record.( variable[ 1 ] ) := possible_positions[ 1 ][ 1 ]; od; return_rec := rec( ); return_rec!.command_tree := REPLACE_INTEGER_STRINGS_BY_INTS_AND_VARIABLES_BY_FAIL_RECURSIVE( range_source_tree ); return_rec!.variable_record := variable_record; ## find matching variables equal_variable_pairs := List( variables_with_positions, i -> [ i[ 1 ] ] ); for i in [ 1 .. Length( variables_with_positions ) ] do for j in [ i + 1 .. Length( variables_with_positions ) ] do if variables_with_positions[ i ][ 2 ] = variables_with_positions[ j ][ 2 ] then Add( equal_variable_pairs[ i ], variables_with_positions[ j ][ 1 ] ); fi; od; od; equal_variable_pairs := Filtered( equal_variable_pairs, i -> Length( i ) > 1 ); for variable in variables_with_positions do if IS_LIST_WITH_INDEX( variable[ 2 ] ) then current_variable_and_index := SPLIT_INTO_LIST_NAME_AND_INDEX( variable[ 2 ] ); if STRING_REPRESENTS_INTEGER( current_variable_and_index[ 2 ] ) then additional_position := Int_SAVE( current_variable_and_index[ 2 ] ); else additional_position := current_variable_and_index[ 2 ]; fi; Add( equal_variable_pairs, [ variable[ 1 ], Concatenation( variable_record.( current_variable_and_index[ 1 ] ), additional_position ) ] ); fi; od; return_rec!.equal_variable_positions := equal_variable_pairs; if IS_LIST_WITH_INDEX( range_replace ) then range_replace_list_and_index := SPLIT_INTO_LIST_NAME_AND_INDEX( range_replace ); return_rec!.replace := Concatenation( variable_record.( range_replace_list_and_index[ 1 ] ), [ range_replace_list_and_index[ 2 ] ] ); else return_rec!.replace := variable_record.( range_replace ); fi; return_rec!.starting_command := range_source_tree!.command; ## Starting with sources if source = "()" then source_list := [ ]; else source_list := SPLIT_KOMMAS_NOT_IN_BRACKETS( source ); fi; source_list := List( source_list, SPLIT_SINGLE_PART ); ## create test function for source new_source_list := [ ]; for source in source_list do if source.bound_variables <> fail then bound_variable_string := source!.bound_variables; bound_variable_string := RETURN_STRING_BETWEEN_SUBSTRINGS( bound_variable_string, "forall", "in" ); bound_variable_name := bound_variable_string[ 1 ]; if COUNT_SUBSTRING_APPEARANCE( bound_variable_string[ 2 ], "[" ) = 0 then source!.bound_variable_list_name := bound_variable_string[ 2 ]; else bound_variable_list_content := RETURN_STRING_BETWEEN_SUBSTRINGS( bound_variable_string[ 2 ], "[", "]" )[ 1 ]; for i in [ "..", ",dots,", "dots" ] do bound_variable_list_content := SPLIT_STRING_MULTIPLE( bound_variable_list_content, i ); if Length( bound_variable_list_content ) > 1 then break; else bound_variable_list_content := bound_variable_list_content[ 1 ]; fi; od; if Length( bound_variable_list_content ) < 2 then Error( "could not split bound variable list correctly" ); fi; bound_variable_list_boundaries := [ ]; for i in [ 1, 2 ] do if STRING_REPRESENTS_INTEGER( bound_variable_list_content[ i ] ) then bound_variable_list_boundaries[ i ] := Int_SAVE( bound_variable_list_content[ i ] ); else bound_variable_list_boundaries[ i ] := bound_variable_list_content[ i ]; fi; od; source!.bound_variable_list_boundaries := bound_variable_list_boundaries; fi; source!.bound_variable_name := bound_variable_name; fi; Add( new_source_list, source ); od; return_rec!.source_list := new_source_list; return return_rec; end ); InstallGlobalFunction( READ_EVAL_RULE_FILE, function( eval_rule_file ) return READ_LOGIC_FILE( eval_rule_file, "eval_rule" ); end );