Proposals
Lynn H. Maxson
lmaxson@pacbell.net
Mon, 17 Jul 2000 10:28:43 -0700 (PDT)
"One difficult part of talking with you is that you
never answer yes or no to a question, nor do you
directly address a statement. You instead discuss
something related to the statement which happened
to be on your mind at the time."
Billy, part of the time it is guessing game. You
realise that you have not communicated well which
leaves you guessing on what it takes to get on
track. Once you done this incorrectly several
times the task gets even more difficult. I've
often considered answering with a simple "yes" or
"no". Maybe you have offered me an easy way out.
"I don't understand how your comment about
"specialties" has any relation to the rest of your
paragraph. How does it?
Optimization is not a specialty -- it's
everything."
The paragraph contained a reference to how IBM has
relegated its "optimized" code generation for its
compilers regardless of source language to a group
devoted to that purpose. This to my way of
thinking makes it a specialty.
As to the reference that it is "everything" I must
somehow protest. In order of priority of emphasis
I must place the mapping of the solution set to the
problem set as first. If that means using fixed
decimal integer arithmetic instead of binary, then
so be it.
After doing that I am interested in its most
efficient execution. To do that I need to know "a
priori" the mix of the input data. All programs
are data driven. The greater the knowledge I have
of the input data the better I can organize the
decision logic to as to minimize the average number
of decisions made in the aggregate. This is one
form of optimization available to me with an HLL.
As I cannot optimize an iteration, considering that
its decision logic is necessary and sufficient,
that leaves only sequences. For me to optimize
these in terms of generated code I am dependent
upon feedback from each implementation. For the
same compiler whose implementation varies by the
version that implies that either I go back to all
the source I have written in all programs using
that compiler or I simply accept what it produces
unless its runtime turns out not to be "good
enough".
" Everyone who's ever written a program is an
optimiser. Anyone who's ever walked a new route to
an old place is an optimiser."
An optimist, maybe.<g>
"There are many specialties within optimization, of
course. Some of the most rigorous involve the
attempt to translate some aspects of optimization
to a machine-expressible algorithm."
How does it differ as a specialty here from my
illustration?
"Those responsible for code generators must be,
yes. I see you're bringing in a confusion between
code generation and optimization again; the
ultimate optimiser is also a code generator, but
merely making a fancy code generator doesn't give
you an optimiser. Optimising is FAR more
difficult."
Well, if everyone who writes a program is an
optimiser, how difficult can it be? One of us
certainly is confused.<g> Optimizing compilers
which internally reorganize the translated source
statement and then seek to minimize the execution
time of the generated code are not merely fancy
code generators, but optimizing code generators.
That it is difficult for people to do consistently
is why you incorporate the rules into software.
If you write in a HLL, you have no control over the
code generated, whether or not you select an
optimizing option. The only control you have,
where you know what code get generated for a
particular expression, is to write in the form of
that expression. Even there the sequence may
change from one version to the next. So you dare
not recompile without reverification.
"The computer won't find the optimum for anything
but the most trivial imaginable program in a week.
I disproved this in my last post."
Maybe we can assert this as Billy's Theorem where
Billy operationally defines the difference between
an "optimiser" (the person), "optimizing" (the
process), "optimum" (the result), and "efficient"
(today's optimum).<g>
"...and in the process, he'll have changed the
low-level design of the code just a bit to better
fit the architecture, something your computer can't
do in a million years."
You must be running scared here to believe that any
better fit he discovers is not specifiable in
software. We can debate whether or not it is
possible to specify in software a discovery process
that could "discover" this more efficient form in
some reasonable time period. We cannot debate that
once discovered we can specify our discovery in
software.
The point is that the "computer" (for some reason
you still regard this as an independent entity)
does what the software tells it to do. If we tell
the software "with this input produce that output",
it will do it without having to "discover" what to
do.<g>
"Yes, I do. I insist that the programmer will code
NOT the best possible code for the low-level
design, but rather code which is BETTER than
possible for that low-level design."
Now I am not sure which of us is more confused.<g>
"Do you still believe any of that? Then let me
disprove it in ONE WORD:
Go.
ONE PERSON can defeat a computer at Go, even
allowing the computer a huge amount of time."
Well, technically no. The human player would have
to pass on the next move to his successor as the
amount of time that the software would need might
exceed his lifetime. To say that we have granted
it a "huge" amount of time is also saying that we
have also set a limit.<g>
However picking an optimal strategy is different
from optimizing a code sequence. That is dependent
upon finding that code sequence which uses the
least number of machine cycles each execution
regardless of the number of executions. While the
number of executions may be large all the machine
logic associated with each iterative execution may
be optimum.
Moreover the fact that a program may never
terminate does not mean that it is not executing as
fast as it possibly can.<g> Stick with the subject
of code optimization.
"You're also mistaken when you associate heuristics
with optimum solutions. Heuristics don't even try
to find optimum solutions; they merely find
solutions which are 'good enough'."
I don't care how humans arrive at a decision, come
to a conclusion. Whether optimum or "good enough",
as long as it can be specified in software it will
suffice. If a better, more optimum way is found,
we can replace the existing choice with the newer
one. We may never discover an optimum, but that
does not prevent us from coming closer and closer
nor preventing our specifying our discovery in
software.
I do not argue that software does anything on its
own, even a discovery process, that is not dictated
by human-determined rules. That which we discover
we specify in software such that we can get maximum
benefit. The software functions as a tool
extending human abilities. I do not go to war with
software or regard it as a competitor when in fact
it is a loyal and blindly obedient servant.
Now it is true that as a human I can master many
machine architectures and discover hundreds and
thousands of rules which apply to expression
evaluation in terms of code generation. However I
have determined that I prefer to write in a HLL
ignorant (independent) of any machine architecture.
Thus I incorporate my rules into software governing
the translation of my language into the machine's
language in the same manner "as if" I had written
it in its language.
Now whether my discoveries are optimum or not is
unimportant. What is important is that among my
discoveries and those of others is at least one in
any given input instance that is equal to or better
than any other in terms of machine cycles required.
It may not be optimum in any absolute sense, but it
represents my best choice at the moment. Until a
new discovery comes along, gets added to the
collection, and a new evaluation changes things it
will have to be "good enough" as it is the best I
have (currently).
"You're also badly mistaken (shockingly so) when
you claim that selecting from an infinitely large
set requires an infinite number of programmers.
The very act of programming IS by definition
selecting a single program from an infinitely large
set (the set of all programs); so is optimization
(the set of all programs which fit the specs).
This is done all the time by a SINGLE programmer."
It's no wonder that I tend to meander a bit in
these responses as I ponder a stratagem to pursue
to get communication back on track.<g> To quote
you in a word "go". The first player makes a move.
The second player concedes defeat. There's no
sense in playing out a game you know you are going
to lose.<g>
You have great faith in the gestalt abilities of
every programmer. It amazes me then how different
ones come up with different results. Must be
something willy-nilly in the individual selection
process from the same infinite pool of programs.
The fact of the matter is that you can make a
non-optimum selection. To make an optimum
selection you would have to examine an infinite
number. No matter how quickly you eliminated one
from consideration the time would exceed your
lifetime.
I won't even bother that the storage capacity of
the brain would not hold an infinite number even it
were possible to examine each (which by definition
of infinite is impossible). So obviously it does
not occur in this manner by any single or multiples
of programmers.<g>
">Moreover there is no way anyone can develop a
>"secret" heuristic and keep it that way in
>practice. Once it exists in machine code the
>secret is out: it becomes another among a host of
>heuristics.
What? That's impossible."
Wrong again.<g> The longer answer would be that
for a given input a new output mapping exists.
That new output is specifiable in software.
"No, it's because heuristics vary. The same
heuristic can be coded in different ways; or the
code to recognise when the heuristic fits might be
better or worse. The compiler's optimiser might be
better or worse (and that's one area where there's
DEFINITELY no one best way).
It's not a technical problem; it's a mathematical
impossibility."
It does not make a difference how you code a
heuristic, by definition it must produce the same
result. The only possible difference is the time
required.
It is true that how people code logic can impact
the application of an heuristic. That's a people
difference which we seek to overcome. That is true
when it comes to the compiler's optimiser.
From a given set of choices, finite or infinite,
there may be no "one" best choice (although there
may be), but there is at least one whose runtime
performance (regardless of its space requirements)
is at least equal or better than any other. For
what it is worth it is logically true.<g>
"Sure, if you want. Of course, that's not true;
optimization is a single process, and performing it
piecemeal will always result in something inferior.
However, it's generally good enough."
Optimization is a process. A process is a set of
stages (sub-processes). Each is a piece. Anytime
a piece makes a change we transfer control back to
the intial sub-process to repeat the process. Once
we get through this iteration, when no piece makes
a change, we terminate the process.
If you believe that because every process must be
executed in a piecemeal manner and therefor must
produce inferior results, then I will exit any
further discussion on the subject.<g>
"Ah, but this isn't true! Ever heard of "loop
unrolling"? It can VASTLY speed up code! Of
course, it increases the bulk of code..."
Loop unrolling can only occur where the number of
iterations is fixed and known at "compile time",
i.e. expressed in the source. As such it is
subject to the embedded optimizing rules which can
account for it as well. If your statement is that
it makes a different directed graph, one of
repetition and not iteration, it still does not
affect the optimization of the repeated code.
"Do you hear what you're saying? Read it again!
Look at what you're saying to me!!!!!!! Please!
You're claiming that you're not trying to find when
a program terminates; what you're actually trying
to find is WHETHER A PROGRAM TERMINATES IN LESS
TIME. Same thing!"
Well, one of us is confused. I don't have any
problem with whether a program terminates or not or
even when it terminates. The only assumption that
I make is that in two executions (which could be
occurring concurrently) that it is possible that
one is executing faster than the other, that
somehow their internal coding differences accounts
for their performance difference.
Strangely enough I can tell you that a program will
terminate if that program contains a sequence only.
I can on a given machine with a given set of code
tell you when it will terminate. I can because I
have done so. I didn't allow somebody's theorem to
get in the way. The fact is that there seems to be
a variation in the runtime between the different
runs, so you have to iterate it in as near isolated
conditions as much as possible a thousand or more
times to have some confidence in the "average" run
time.
This method comes directly from Abrash's "The Zen
of Assembly" which is on my bookshelf along with
the "Tao of Objects" and the "The Art of the
Metaobject Protocol". Fortunately Abrash hadn't
heard of Rice's Theorem either so he could offer a
terminating code wrapper for my code so that we
could determine from a set of given expressions
which one ran faster. Without proving it other
than empirically, which is the only real world
test, I had no other proof in mind.<g>
"... and you profile the program while it's
running. Parts
of the program which run frequently can get
optimised with more
time-consuming optimization processes.
Suprisingly, it seems to work well."
Yes.<g>
"Have you ever attempted to count the number of
paths in a trivial program? You're correct that
it's finite (by your definition of the word
'path'); however, it's a HUGE number. Using your
algorithm, we'd have to optimise each path
seperately; you miss the fact that any two paths
can overlap, and usually do."
The most trivial program is a sequence of a single
statement. Counting the number of paths is quite
simple: one. I have in fact accounted for the
number of paths in a non-trivial program. When
called upon I depend upon my PL/I compiler to
enumerate the number of paths in a program.
As I write structured code I don't seem to have the
overlap problem you referred to. I do have
reusable paths, but they are logically
non-overlapping. Using my algorithm we would have
to optimize each path separately. If that meant
that reusable portions would differ, then we would
generate multiple versions of each portion. That
may bother your optimizer, but not mine.<g>
"You speak of "finite" additional time -- but are
you sure that the time is finite?"
This gets back to the "infinite possibilities"
thing you laid on me. In any give language we have
only a certain (finite) number of operators. In
order for there to be infinite possibilities at
least one of these operators must fall into this
category. I would be more than happy at some other
time to take each operator in turn for any given
machine architecture to show for each there were
only a finite number of choices.
I understand your definition of logical
equivalence. I also understand the concept of
machine cycles. I also understand how I can use an
heuristic regarding one to restrict what I have to
consider out of the universe of the other, a
restriction which reduces what I produce to a
finite number. It is no more than saying that
while the set of integers is infinite, the set of
those equal to or greater than zero and equal to or
less than 37 is not.
That means all I have to have for each operator is
a "starter set" of machine code. I never have to
consider anything which exceeds its number of
machine cycles. Machine cycles is what determines
from a set of choices which is best, whether
optimum or not. The optimum choice is either equal
to or less than this. If less than this, then it
must be in the "computable" finite set.
"You've said this before, and I don't understand
it. How does your system cause this to happen? I
don't understand at all."
You understand public domain. Here's a
specification language whose definition is
specified in the language, i.e. exists as a set of
specifications. Here's a tool written in that
language. Here's the source for both in the public
domain.
What is it that you don't understand? Here is a
language and a tool whose only input is source. It
has rules of syntax and semantics. As long as the
source follows the rules you cannot introduce
incompatibilities. You can introduce
contradictions, but that simply means selecting one
or the other or a process which includes both.
The user owns the tool and the source. When he
wants an application written he finds someone to
write the additional specifications expressed in
the source language. These get added to the user's
source: they remain his property.
This is no more than what occurs in large accounts
with their own IT departments today. All this does
is bring it down to the level of the individual
user. If the minimal claim of "50 times time
reduction, 200 times cost reduction" is valid, it
means that a single user can afford to have a
"build to order" (custom) solution now instead of a
"build to stock" (package) currently.
If users keep adding source into the public domain,
then more and more applications become less and
less expensive. In that manner the current
advantage that vendors have over users disappears.
In such a system the user dictates and the vendor
obeys.
The beauty of a specification and a formal
specification language lies in its non-proprietary
nature. You cannot own "what" something does, only
"how" it does it. If I personally have a "what" in
mind, and a means of producing an executable on my
own, i.e. not for resale, then nothing or no one
can physically, legally, or otherwise stop me. If
I submit my "what" to the public domain, all of
whose members have the same capability, then
nothing can stop them either.
You cannot introduce incompatibilities. You have
no need for standards other than rules of syntax.
There's no way for anyone to establish a monopoly
and quash competition. You (and maybe a few
friends together) can afford to have custom
specifications written (if you cannot or do not
want to write them yourself). What you have is a
viable market segment down to a single user.
Now what is it that you don't understand?<g>