So i was inspired by SourceCoders' Basic Optimizer function, and i thought about making one on the calculator, so you could optimize your Basic Programs without having to transfer them to the computer for any utility. I quickly wrote up some code in Axe, and the optimizations have started! Currently it has support for:

Ending Parenthasis
Ending Brackets
Ending Braces
Ending Quotes
Devlar
Powers of 10
Squared or cubed
Negative cancelations

And there is plans and psedocode for

Implied multiplication
=0 into Not(
Expression rearranging to maximize parenthesis deletion

any other ideas of simple find and replace optimizations that i could put into the optimizer? Obviously i cant do some of the complicated stuff, but there are some good simple replacements that can make a big difference. And note that it ignores Strings completely Strings Should not be changed ^^. And there also might be an option on whether to erase empty lines or not. Some people like to keep them for readability during development, and then maybe want to take them out later.
This certainly sounds like a cool idea; how does it work? Does it use a state machine of sorts in order to omit optimizing the contents of strings? Let me show you how the SourceCoder optimizations work via Regex, and I'd also appreciate your (and others') help in coming up with a better optimizer for SourceCoder:


Code:
//Optimizations
$opti = array(
array('/(\)|\})(\<br \/\>:|:|\&\#8594\;|$)/',               '\2',1,0,-2),
array('/([^\:\<])\"(\<br \/\>:|\&\#8594\;|$)/',               '\1\2',1,0,-2),
array('/\"(\d+)(\<br \/\>:|:|\&\#8594\;|$)/',                  '\1\2',1,0,-2),
array('/(If [^\<\:]*)(:|\<br \/\>:)Then(:|\<br \/\>:)([^\<\:]*)(:|\<br \/\>:)End/',   '\1\3\4',1,0,-2),
array('/(Output\(1,1,)"$/',                              '"',1,0,-2),
array('/Disp \"([^\<\:\"]*)(:|\<br \/\>:)(Pause )(:|\<br \/\>:|$)/',      '\3\1\4',1,0,-2),
array('/Stop/',                                       'Return',1,0,-2),
array('/(:|\<br \/\>)Return$/',                           '',1,0,-2),
array('/([^\d])0\&\#8594\;(\w)(:|\<br \/\>:)/',               '\1DelVar \2',1,0,-2),
array('/(DelVar \w)(:|\<br \/\>:)/',                        '\1',1,0,-2),
array('/(\w|\{L\}\w\w*\((\d\d*|\w)\)|Ans)\≠0/',         'not(\1)',1,0,-2),
array('/(For\(\w\,[^\,]*\,[^\,]*),1/',                     '\1',1,0,-2),
array('/\^2/',                                       '<sup>2</sup>',1,0,-2),
array('/\^3/',                                       '<sup>3</sup>',1,0,-2),
array('/(\d+|\w+)\*/',                                 '\1',1,0,-2),
array('/[^\d ]1([A-Z]+|\(+)/',                           '\1\2',1,0,-2),
array('/(Disp|Prompt) (\w(,\w)*)(:|\<br \/\>:)\1 (\w)/',         '\1 \2,\5',1,0,-2),
array('/not\((\a)\) and not\((\a)\)/',                     'not(\1 or \2)',1,0,-2),
array('/not\((\a)\) or not\((\a)\)/',                     'not(\1 and \2)',1,0,-2),
array('/If (\w+)(\=|\&gt\;|\&lt\;|\&\#8800;|\&\#8804;|\&\#8805;)(\w+)(:|\<br \/\>:)(\w+)(\+|\-|\/|\*)(\w+)→(\7|\5)/','\5\6(\1\2\3)\7→\8',1,0,-2),
array('/(\<br \/\>:)\<br \/\>:/',                              '\1',1,0,-2),
array('/(If [^\<\:]*)(:|\<br \/\>:)Then(:|\<br \/\>:)(\"[^\<\:]*)(:|\<br \/\>:)Else(:|\<br \/\>:)(\"[^\<\:]*)(:|\<br \/\>:)End/',   '\7\8\1\2\4',1,0,-2),
array('/→Ans/','',1,0,-2),
array('/(\w+)\/\((\w+)/','\1/\2',1,0,-2),
array('/\((\w+)\)\/(\w+)/','\1/\2',1,0,-2),
array('/\((\w+)\)(\+|\-)(\w+)/','\1\2\3',1,0,-2),
array('/Disp ([^\<]+)(:|\<br \/\>:)(Input|Prompt) (\w+)/',         '\3\1",\4',1,0,-2),
);


Edit: I should also mention that the optimization tools aren't actually my original code, but instead created by Brazucs of UnitedTI and integrated into SourceCoder about 5 years ago.
Well it loops through the entire program token by token, if it encounters a quote, it flips a flag that says its inside a string. If it encounters another quote, a newline, or a store token, it flips the flag back. And for every token *not* found when not in a string has its address passed into the optimization sub.

That sub has hand written code (not a table replace) to search for and around tokens and do optimizations directly. For instance when it encounters a closing parentheses it does this:


Code:
Check to see if the next token is either a colon, a newline, or a store
If so, remove the token and shift the program down


And for more complicated optimizations, such as the powers of 10, it does things like this:


Code:
Check to see if the token is a 1
Check to see if the previous token is NOT a number
Find the number of zeros after the 1
If the number is greater than 1 and less than 10, add the scientific E  and the single digit power
If the number is greater than 9, add the scientific E and the two digit power
Shift the program data down as neccesary


And each optimization has a statement coded for it specifically. There are cases where optimization leads to more possible optimization though, so the optimizer loops through the program multiple times until no more are found.
OK, that's known as a state machine, so I thought so. Smile That's how I'd like SourceCoder's to work as well, which obviously is a bit easier and hence can be made more powerful in PHP on my server than on Axe on a calculator. Let me explain each of my optimizations.


Code:
array('/(\)|\})(\<br \/\>:|:|\&\#8594\;|$)/',               '\2',1,0,-2),
Remove a closing ) or }, but only if it's followed by a :, a newline, the end of the program, or some character I don't recognize with Unicode ID 8594.

Code:
array('/([^\:\<])\"(\<br \/\>:|\&\#8594\;|$)/',               '\1\2',1,0,-2),
Remove a single-quote followed by a newline, provided that it's not delimiting a blank line

Code:
array('/\"(\d+)(\<br \/\>:|:|\&\#8594\;|$)/',                  '\1\2',1,0,-2),
Replace a number by itself in a string with just the number, to save the quote byte.

Code:
array('/(If [^\<\:]*)(:|\<br \/\>:)Then(:|\<br \/\>:)([^\<\:]*)(:|\<br \/\>:)End/',   '\1\3\4',1,0,-2),
Remove the Then and End around a single statement after an If, including constructions like If \ Then \ Goto \ End.

Code:
array('/(Output\(1,1,)"$/',                              '"',1,0,-2),
Remove the construction Output(1,1,". I'm unsure what this is for.

Code:
array('/Disp \"([^\<\:\"]*)(:|\<br \/\>:)(Pause )(:|\<br \/\>:|$)/',      '\3\1\4',1,0,-2),
Convert Disp "string" \ Pause to Pause "string"

Code:
array('/Stop/',                                       'Return',1,0,-2),
Turn Stops into Returns. Because, come on.

Code:
array('/(:|\<br \/\>)Return$/',                           '',1,0,-2),
Remove any Return that's the last command in a program

Code:
array('/([^\d])0\&\#8594\;(\w)(:|\<br \/\>:)/',               '\1DelVar \2',1,0,-2),
Replace 0->var with Delvar var

Code:
array('/(DelVar \w)(:|\<br \/\>:)/',                        '\1',1,0,-2),
Remove the newline or colon after a Delvar.

Code:
array('/(\w|\{L\}\w\w*\((\d\d*|\w)\)|Ans)\≠0/',         'not(\1)',1,0,-2),
I'd have to look closer at this to understand fully the logic it applies, but the high-level interpretation is that it changes If BLAH!=0 to If BLAH. and If BLAH=0 to If not(BLAH.

Code:
array('/(For\(\w\,[^\,]*\,[^\,]*),1/',                     '\1',1,0,-2),
Remove the final ,1 increment in For( loops with it.

Code:
array('/\^2/',                                       '<sup>2</sup>',1,0,-2),
Replace ^2 with the exponent 2.

Code:
array('/\^3/',                                       '<sup>3</sup>',1,0,-2),
Same with ^3 -> exponent 3.

Code:
array('/(\d+|\w+)\*/',                                 '\1',1,0,-2),
Implicit multiplication creation.

Code:
array('/[^\d ]1([A-Z]+|\(+)/',                           '\1\2',1,0,-2),
No point having 1 as a coefficient.

Code:
array('/(Disp|Prompt) (\w(,\w)*)(:|\<br \/\>:)\1 (\w)/',         '\1 \2,\5',1,0,-2),
Replace series of Disp A \ Disp B or Prompt A \ Prompt B with Disp A,B or Prompt A,B

Code:
array('/not\((\a)\) and not\((\a)\)/',                     'not(\1 or \2)',1,0,-2),
combine boolean expressions

Code:
array('/not\((\a)\) or not\((\a)\)/',                     'not(\1 and \2)',1,0,-2),
more of same.

Code:
array('/If (\w+)(\=|\&gt\;|\&lt\;|\&\#8800;|\&\#8804;|\&\#8805;)(\w+)(:|\<br \/\>:)(\w+)(\+|\-|\/|\*)(\w+)→(\7|\5)/','\5\6(\1\2\3)\7→\8',1,0,-2),
This massively complex thing does some kind of If \ Store statement compression to value(conditional)->variable expression

Code:
array('/(\<br \/\>:)\<br \/\>:/',                              '\1',1,0,-2),
Remove blank lines

Code:
array('/(If [^\<\:]*)(:|\<br \/\>:)Then(:|\<br \/\>:)(\"[^\<\:]*)(:|\<br \/\>:)Else(:|\<br \/\>:)(\"[^\<\:]*)(:|\<br \/\>:)End/',   '\7\8\1\2\4',1,0,-2),
I have no idea. I'd have to work this one out more carefully.

Code:
array('/→Ans/','',1,0,-2),
No point storing to Ans.

Code:
array('/(\w+)\/\((\w+)/','\1/\2',1,0,-2),
remove extraneous parenthesis around division

Code:
array('/\((\w+)\)\/(\w+)/','\1/\2',1,0,-2),
same thing, but for the first half of the division

Code:
array('/\((\w+)\)(\+|\-)(\w+)/','\1\2\3',1,0,-2),
Remove extraneous addition and subtraction parentheses, but I think this one might be functionally incorrect (same with the division)

Code:
array('/Disp ([^\<]+)(:|\<br \/\>:)(Input|Prompt) (\w+)/',         '\3\1",\4',1,0,-2),
Combine Disp / Input or Disp / Prompt into a single Input or Prompt.
Those are some really great optimizations! I hadn't thought of some of those, and the logical ones involving If and logical things are quite complex o.O I will definetaly see if i can try to implement those!

Also i need to do some research on regex's to see if i can get my expression recognition working and so i can move them around to maximize parentheses loss ^^
builderboy2005 wrote:
Those are some really great optimizations! I hadn't thought of some of those, and the logical ones involving If and logical things are quite complex o.O I will definetaly see if i can try to implement those!

Also i need to do some research on regex's to see if i can get my expression recognition working and so i can move them around to maximize parentheses loss ^^
Oooh, can you tell me about this expression recognition? I'm sure you're not trying to write a full regex parser, but you're trying to make a rudimentary regex-like parser? Fire away with any regex questions; I've been using them for years. Razz
Haha its not been fully conceptualized even, but i think that i have an idea of how to get it working. I just need to figure out which groups of parenthesis are movable relative to each other. Like if i have a bunch of expressions added together, they are free to move around. Same if they are all multiplied together
builderboy2005 wrote:
Haha its not been fully conceptualized even, but i think that i have an idea of how to get it working. I just need to figure out which groups of parenthesis are movable relative to each other. Like if i have a bunch of expressions added together, they are free to move around. Same if they are all multiplied together
Ah, that's very ambitious; I didn't even consider something that intense for SourceCoder! Laughing It seems to me that you'd first need to go to the most innermost sets of parenthesis, rearrange those as possible, then work your way out. Although, what if someone did something like (A+B+(C+D+(E)))? You'd need to remove between multiple levels.
Yeah i know its pretty crazy Very Happy but i have an idea that it may possibly be able to work. I remember i had a parenthesis expression parser written when i wrote my PEMDAS math parser, so i might build off that, but yeah, it would have to work from outside in.
builderboy2005 wrote:
Yeah i know its pretty crazy Very Happy but i have an idea that it may possibly be able to work. I remember i had a parenthesis expression parser written when i wrote my PEMDAS math parser, so i might build off that, but yeah, it would have to work from outside in.
Was that Axe or BASIC? If BASIC, do you have some source code to throw out here, or is it unwieldily large?
basic, and actually its fairly smallish, only a tad bit over 1K
builderboy2005 wrote:
basic, and actually its fairly smallish, only a tad bit over 1K
SourceCoder it and post it up, then, if you don't mind! I'm curious to see it and help you explore how it could be adapted.
Main program
http://sc.cemetech.net/?xpi=0b66e2b79e9cbb85d4822eaf409c7873
This is the expressions parser if i remember correctly Very Happy
http://sc.cemetech.net/?xpi=5ca6f07cdd3345746dc2d0dbda0f76ca
String to number converter
http://sc.cemetech.net/?xpi=1fc6e6b4ab578ded49e8ba7daec81557

The last program is a number to string converter i believe, i was trying to make one that was faster than the LinReg(Ax+b) way. And it uses Expr() at one point, but its only to go from number to string, not to do any math evaluation.
AMATH
KermMartian has just edited this program. The source code now reads:
BASIC Code wrote:
:ClrHome
:Input ":",Str1
:Str1→Str0
:" "+Str1+" →Str1
:"0123456789→Str9
:
:While 1
:
:If not(inString(Str1,")":Then
:" →Str5
:" →Str6
:sub(Str1,2,length(Str1)-2→Str4
:prgmA
:Str4→Str1
:ClrHome
:Output(1,2,Str1
:Output(2,2,expr(Str0
:Return
:End
:
:1→L
:Repeat ")"=sub(Str1,L,1
:If "("=sub(Str1,L,1
:L→K
:L+1→L
:End
:sub(Str1,K+1,L-K-1→Str4
:sub(Str1,1,K-1→Str5
:sub(Str1,L+1,length(Str1)-L→Str6
:prgmA
:Str5+Str4+Str6→Str1
:ClrHome
:Output(1,1,Str1
:End
Generated by SourceCoder, © 2005-2010 Cemetech
This is an automatic post from SourceCoder 2. Report abuse to admin@cemetech.net . You can disable these posts by unchecking the "Post on Update" box in the file's permissions.
A
KermMartian has just edited this program. The source code now reads:
BASIC Code wrote:
:0
:For(F,1,5
:Ans or inString(Str4,sub("+-*/^",F,1
:End
:If not(Ans
:Return
:
:" "+Str4+" →Str4
:‾1→H
:
:Repeat H=5
:
:Repeat H=5 or inString(Str4,sub(Str7,1,1)) or inString(Str4,sub(Str7,2,1
:H+2→H
:sub("^^/*-+",H,2→Str7
:End
:
:1→F
:While F≤length(Str4
:If inString(Str7,sub(Str4,F,1
:Then
:F-1
:While Ans≠1 and not(inString("+-*/()",sub(Str4,Ans,1
:Ans-1
:End
:Ans→I
:sub(Str4,Ans+1,F-Ans-1→Str2
:F+1
:While Ans≠length(Str4) and not(inString("^+-*/()",sub(Str4,Ans,1
:Ans+1
:End
:Ans→J
:sub(Str4,F+1,Ans-F-1→Str3
:expr(Str2→A
:expr(Str3→B
:If "*"=sub(Str4,F,1
:AB→C
:If "/"=sub(Str4,F,1
:A/B→C
:If "+"=sub(Str4,F,1
:A+B→C
:If "-"=sub(Str4,F,1
:A-B→C
:If "^"=sub(Str4,F,1
:A^B→C
:prgmAN2S
:sub(Str4,1,I)+Str8+sub(Str4,J,1+length(Str4)-J→Str4
:I→F
:ClrHome
:If length(Str5)≠1 or length(Str6)≠1:Then
:Output(1,1,Str5+"("+sub(Str4,2,length(Str4)-2)+")"+Str6
:Else
:Output(1,1,Str4
:End
:End
:F+1→F
:End
:
:End
:sub(Str4,2,length(Str4)-2→Str4
Generated by SourceCoder, © 2005-2010 Cemetech
This is an automatic post from SourceCoder 2. Report abuse to admin@cemetech.net . You can disable these posts by unchecking the "Post on Update" box in the file's permissions.
AN2S
KermMartian has just edited this program. The source code now reads:
BASIC Code wrote:
:If E‾6>abs(0.5-abs(.5-fPart(C)
:round(C,0→C
:
:If not(C:Then
:"0→Str8
:Return
:End
:
:DelVar PC<0→N
:abs(C→C
:2-not(not(fPart(C→E
:While fPart(C
:P+1→P
:10C→C
:End
:
:":→Str8
:While C
:C/10→C
:fPart(Ans→D
:C-Ans→C
:If not(P
:"."+Str8→Str8
:P-1→P
:sub(Str9,10D+1,1)+Str8→Str8
:End
:If P≥0:Then
:For(D,1,P
:"0"+Str8→Str8
:End
:"."+Str8→Str8
:End
:sub(Str8,1,length(Str8)-E→Str8
:If N:"‾"+Str8→Str8
:Str8
Generated by SourceCoder, © 2005-2010 Cemetech
This is an automatic post from SourceCoder 2. Report abuse to admin@cemetech.net . You can disable these posts by unchecking the "Post on Update" box in the file's permissions.
BuilderBoy, very impressive! That looks like it could definitely be a good place to start, and looking at that and understanding how it works, it does indeed seem that a recursive parser would be necessary to properly optimize TI-BASIC programs effectively and correctly, both for the sake of your program and for SourceCoder. Do you agree? Do you have any particular thoughts or lessons that you learned or re-learned from your code?
I think a recursive parser would definetaly needed for things like the advanced expression parsing for sure, although not necessarily for the ending quotes Wink

As for the code, it gave me ideas of how to handle and detect individual expressions. We really only care about the expressions inside of parentheses (because that is what we are optimizing) and so that makes detection of the expressions very easy. then its just a matter of rules for optimizing. Expressions that are added together can be freely moved about each other, providing that they are kept with any expressions that they are multiplied to. And likewise, expressions that are multiplied together can be moved around freely within the multiplication.
BuilderBoy, exactly, which will be challenging but not impossible to implement, I think. I'm wondering how we'd be able to figure out how to optimize some of the more complex things, like moving addition of a number that's not a list element with a list element around to save a parenthesis, or -A+B -> A-B to save a byte. Perhaps some of those are outside the scope of the projects? We could always try all the possible permutations, but even that would require some more complexity. Hmm.
Yeah this sounds like a whole project just on its own rather than a section of a larger program. For now i think i am going to focus more on the simpler optimizations, and gradually work my way up towards the more complicated ones. Like optimizing =0 into Not() is a medium challenging one, since you still need to count for order of operations, but it is a ton simpler. Also things like If+Store optimizations and If:then optimizations exc...
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 2
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement