Wednesday, February 16, 2011

Explain( Explain )...Or How I came to be God

Recently I've been engaged in a discussion at the Talking Philosophy blog about the Principle of Sufficient Reason. The discussion resulted from a blog post by Jeremy Stangroom about Fredrick Copleston's and Bertrand Russel's differing interpretations of the work of Leucippus (who is credited as an early developer of the theory of atomism). The principle states that for every fact F there must be an explanation for why F is the case. I can understand how appealing this is for many philosophers and scientists. After all, philosophy and science primary mission is to find out how and why things are the way they are. But, as Russell so well puts it in a 1949 radio discussion with Copelston:

[The] physicist looks for causes; that does not necessarily imply that there are causes everywhere. A man may look for gold without assuming that there is gold everywhere; if he finds gold, well and good, if he doesn’t he’s had bad luck. The same is true when the physicists look for causes.

Inevitable, the discussion expanded to involve determinism, they idea that every event has a cause. Hard determinism denies the idea of potentials and possibilities. And, ultimately, Free Will. And if you have read my blog, you can imagine how such a view contradicts my core convictions.

Well, at some point I though "Why not apply my software engineering abilities to investigate the Principle of Sufficient Reason". Let me just refer to the principle as PSR from here on (it's just such a dreadfully long name). PSR is a more generalized version of hard determinism. It speaks not of causes but of reasons. All PSR demands is that we explain every fact. But, ultimately, I don't see a difference between the two. Determinism simply restricts the explanations to some group of reasons denoted as "causes". If PSR does not hold up, hard determinism will stand on very shaky ground.

So let's get to work. Every software needs a primary function and for PSR, we have an obvious name for this function:

Explain( fact ){

// Place the main body of our PSR program here...

}

Nice start. But, man, that is some main body we have to build! Do we need a switch case for every possible fact??? What's a switch case you ask? Just think of is as a quicker way of saying "if this then that, otherwise..." many times over. Like this:


Explain( fact ){

switch( fact ){

"Baby is born" return "Sperm met egg"

"Lightening" return "There is a thunder storm"

"Child is crying" return "Bozo the Clown is present"

"Joe broke the window" return "Joe is a nut"


}

}


You get the picture. If we want a complete PSR program, imagine how many cases we need in our switch statement. Perhaps we need to implement a database to store all the possible facts and their given explanations. Good idea.

But I want to be able to brew coffee with this PSR baby. It should explain something to the bare bone, my friend! So when I get an explanation, I want an explanation for my explanation. Now we're talking! Ah, here comes the beauty of recursion. Once I get an answer from my explanation function, all I have to do is pass it back into the same function:


Explain( fact ){

/* First lets call the database and get our answer. We'll implement the function to get stuff from the database later. */

explanation = GetExplanation( fact )

/* Loop until we get the real reason at the bottom of it all */

while( explanation is not unknown ){

rootExplanation = Explain( explanation )
explanation = rootExplanation

}

return rootExplanation

}

See what's happening? We just loop around until we can't find an explanation. When we can't, we return the last one we found. Sweet! We now have our root explanation, the thing that really explains it! But wait a minute. Isn't our PSR database going to include every possible fact and its explanation? Unknown is not a permitted value. Holly smoke! We'll never get an answer! Unless we run it for... maybe... 1,000,000 years? No, shoot, make that an infinite amount of time. I think we have what philosophers refer to as an infinite regress. In programming jargon, we simply refer to it to as an endless loop.

What can you do? It is what it is. If we want the real reason, I suppose we'll just have wait forever. Perhaps we can at least introduce an argument to tell us how far down the rabbit hole we should go. One thing is for sure: since our explanation will never be Unknown, we can scrap that from the code.



Explain( fact, maxDepth ){

explanation = GetExplanation( fact )
depth = 0

/* Loop as far down as we want to go */

while( maxDepth is Infinity or depth is less than maxDepth ){

explanation = Explain( explanation )
depth = depth + 1

}

return explanation

}

If we really want to go all the way and have all the time in the Universe, we will just pass Infinity as our maxDepth into the function. For you code junkies out there, Infinity could just be a defined integer constant with, say, a value of -1.

That's it, right? Actually I'd like to improve our PSR program. This thing ain't cooking a cup of java quite yet. We may be getting the root explanation (or the explanation at a given depth), but we loose all the reasons between root and the fact itself. We should retain them so we can reconstruct our whole chain of reasoning at some point. We need a way to chain the answers together.


Explain( fact, maxDepth ){

reasons = Array( maxDepth );

reasons[0] = GetExplanation( fact )
depth = 1

while( maxDepth is Infinity or depth is less than maxDepth ){

reasons[ depth] = GetExplanation( reasons[depth-1] )
depth = depth + 1

}

return reasons

}


An array is a collection of ordered elements that can be accessed by an index (reasons[0], reasons[1], reasons[2]...). Since we know how far we want to go in explaining our initial fact, we can allocate the size of our array at the outset. Superb. Now we can walk through the whole chain of reasoning again once we have evaluated our function. Code junkies: OK, you got me. Infinity can no longer be a static integer constant with value -1. Now we really do need infinity. Ouch, I think we are going to need a loot of memory ladies and gentlemen. About... hmm... roughly one infinite Universe.

Hold on! If we need an infinite amount of Universe to store our result, where are we going to run the program?? Never mind. I don't think infinity is so picky if you add a few extra bites. Phew! Infinity is really useful. Maybe we don't even need to improve our program given the vast amount of memory and time available. So that's it.

But I sense something is missing, something that leads me into the tricky domain of meaning. What is in fact a fact? If I say "She walked out the door", is that a fact? What about "She walked out the door because she was angry"? Or "She walked out the door because she was angry and refused to continue the discussion"? Maybe none of them are facts. Maybe the only fact is that her cells converted chemical to kinetic energy. I don't know. We better err on the safe side. Anything that can be stated and is true is a fact. So once you attach a reason to a reason, you get a new fact! When you get to the very root reason about an infinity later, you have the real complete and ultimate fact. Which means, if we want the true root reason for a specific fact, we will have to pipe the whole chain of reasons as a fact back into our function.


ExplainEverything( fact, maxDepth ){

reasons = Explain( fact, maxDepth )

bigFact = Combine( reasons )

return Explain( bigFact )

}

Explain( fact, maxDepth ){

reasons = Array( maxDepth );

reasons[0] = GetExplanation( fact )
depth = 1

while( maxDepth is Infinity or depth is less than maxDepth ){

reasons[ depth] = GetExplanation( reasons[depth-1] )
depth = depth + 1

}

}


OK, Let's run it. Here we go:


ExplainEverything( "Exactly my dear Watson", 1000 )


Awesome! That was a little unexpected. What about this:


ExplainEverything( "Bozo the Clown", 1000 )


That's scary, man. Wow. What now? You know what I want, I want the big answer. If I only had a computer the size of the Universe. Wait. Isn't time continuous? And space too? That means there's infinite time in 1 second and infinite space in a nanometer. Thank you Zeno! I don't need a quantum computer. Quanta are like discrete, and, yeah it won't do. What I need is a subquantal continuum computer with infinitesimal clock speed. Hey, why didn't anyone think of that? Let's build it!

That was easier than I thought. OK, so let's run PSR for real. Wait. I forgot something. I need to explain PSR itself! Without PSR, the big fact is missing the process of explaining its own process of explanation.


ExplainAbsolutelyEverything( fact ){

allReasons = ExplainEverything( fact, Infinity )

megaFact = Combine( allReasons )

/*Now lets make the function itself into a fact and then attach it to big picture to make the mother of all facts*/

selfExplanation = Explain( ExplainAbsolutelyEverything )
megaFact = Combine (megaFact, selfExplanation)

return Explain( megaFact )

}

ExplainEverything( fact, maxDepth ){

reasons = Explain( fact, maxDepth )

bigFact = Combine( reasons )

return Explain( bigFact )

}

Explain( fact, maxDepth ){

reasons = Array( maxDepth );

reasons[0] = GetExplanation( fact )
depth = 1

while( maxDepth is Infinity or depth is less than maxDepth ){

reasons[ depth] = GetExplanation( reasons[depth-1] )
depth = depth + 1

}

}


Finally, now lets run it. What fact should I start with? Hmmm, I guess I'll have to start with what I know for sure. Je doubte, donc je pense, donc je suis! I can't wait!


ExplainEverything( "Andreas exists", Infinity)

Seriously? I...think I've...I think I'm God...Hello? Is there anyone out there? I mean...in there...?

No comments: