Sonntag, Dezember 18, 2016

Consciousness is not a quantum phenomenon

Consciousness is weird. Quantum physics is weird. There's this temptation to conclude that therefore, they must be related, but they're almost certainly not. In fact, I want to explore an argument that consciousness cannot be a quantum phenomenon but must necessarily be classical.

We don't really understand consciousness, but many people have tried. A compelling argument pushed by Douglas Hofstadter is that consciousness is a product of certain sufficiently complex "strange loops", self-reflexive processes. Put simply, the mind observes the body, but it also observes itself observing the body, and it observes itself observing itself observing the body, and so on. On some level, this endlessly reflexive process of self-observation is consciousness.

Part of this self-reflexive process is the simulation of simplified models of the world, including ourselves and other people. This allows us to anticipate the effects of possible actions, which helps us choose the actions that we ultimately take. (Much or even most of our daily decision making doesn't use this complicated process and simply uses subconscious pattern matching. But we're focusing on the conscious part of the mind here.) Running multiple simulations to choose from a set of possible actions requires starting the simulation with the same initial state multiple times. In other words, it requires copying the initial state.

If consciousness were a quantum phenomenon, this would imply copying some quantum states. However, it is physically impossible to copy a quantum state due to the no-cloning theorem, just like it is impossible to change the amount of energy in the universe.

This immediately gives us a very nice explanation for why we are unable to perceive quantum states. Nothing can copy quantum states, and so a conscious mind that perceives quantum states cannot develop, since perception and memory of states of the world certainly requires making copies of those states (at least partial ones).

There is some wiggle-room in this argument. Even a mind that only perceives, remembers, and computes on internal representations of classical states might still use quantum physical processes for this computation. And at a certain level, it is actually obviously true that our brains do this: our brains are full of chemistry, and chemistry is full of quantum physics. The point is that this is just an irrelevant implementation detail. Those quantum processes could just as well be simulated by something classical.

And keep in mind that if we believe in the importance of "strange loops", then the mind itself is one of the things that the mind perceives. The mind cannot perceive quantum states, and so any kind of quantum-ness in the operation of the mind must be purely incidental. It cannot be a part of the "strange loop", and so it must ultimately be of limited importance.

There is yet more wiggle-room. We know that some computational tasks can be implemented much more efficiently on a quantum computer than on a classical computer - at least in theory. Nobody has ever built a true quantum computer that is big enough to demonstrate a speed-up over classical computers and lived to tell the tale published it. Perhaps consciousness requires the solution of computational tasks that can only be solved efficiently using quantum computing?

I doubt it. It looks increasingly like even in theory, quantum computers can only speed up a few very specialized mathematical problems, and that's not what our minds are particularly good at.

It's always possible that this whole argument will turn out to be wrong, once we learn more about consciousness in the future (and wouldn't that be interesting!), but for now, the bottom line for me is: Strange information processing loops most likely play an important role in consciousness. Such loops cannot involve quantum states due to the no-cloning theorem. Hence, consciousness is not a quantum phenomenon.

Mittwoch, Dezember 07, 2016

Bedingungsloses Grundeinkommen: Die Finanzierung ist nicht das Problem

Gestern hat Joerg Wellbrock auf dem Spiegelfechter einen Beitrag geschrieben, in dem er einige Kritik am Konzept des Bedingungslosen Grundeinkommen (BGE) übt. Ich teile vieles der Kritik zumindest als Skepsis.

Aber wenn er die Finanzierung des BGE hinterfragt, steige ich aus. Er sieht ein Finanzierungsproblem, wo in Wirklichkeit keins ist. Denn der Staat, zumindest der monetär souveräne Staat, kann finanzieren was und wie viel er will. Zu glauben, ein monetär souveräner Staat könne irgendwo ein Finanzierungsproblem haben ist ungefähr so, als würde man glauben, dass beim Spiel Monopoly die Bank pleite gehen kann. Kann sie nicht - und wenn das gedruckte Geld ausgeht, dann behilft man sich eben irgendwie anders. So steht es in den Regeln.

Moment! ruft der geneigte Leser jetzt innerlich, aber ist das nicht Gelddrucken und kommt dann nicht die Inflation? Nein, Gelddrucken ist das nicht. Auch beim Monopoly-Spielen würde man das "Problem" eher nicht durch Gelddrucken lösen. Aber ja, natürlich kann Geldausgeben grundsätzlich immer zu Inflation führen, den Umständen entsprechend. Diese Möglichkeit führt ja auch Wellbrock schon als potentielles Problem des BGE an.

Aber es ist eben wichtig, dass das Potential für Inflation das einzige Problem ist. Es gibt kein Finanzierungsproblem. Vielleicht gibt es ein Inflationsproblem. Der Unterschied ist wichtig, und zwar aus zwei Gründen.

Erstens geben wir den sogenannten Kreditgebern und Finanzmärkten zu viel Macht, wenn wir an ein Finanzierungsproblem glauben. Dieser Glaube führt dazu, dass unsere Politiker in Angst leben vor den sogenannten Finanzmärkten. Und weil diese so diffus sind und nicht klar definiert, gibt diese Angst dann de facto Macht an die Hohepriester bei Banken und Think Tanks, die als Interpreten des Marktwillens gelten. Neutrale Beobachter sind das auf keinen Fall, und das Wohl der breiten Bevölkerung haben die meisten von ihnen auch nicht im Blick. Wir leben aber in einer Demokratie. Deren Politik muss natürlich die Beschränkungen der Realität anerkennen, aber sie darf nicht grundlos Macht an nicht legitimierte Gruppen abgeben.

Zweitens schwingt beim Gedanken an Finanzierung und Kredite immer automatisch mit, dass das Geld zurück gezahlt werden soll, womöglich noch mit Gewinn. Effizienz ist natürlich auch für demokratische Politik ein sinnvolles Ziel, aber Profitwirtschaft darf kein Ziel sein. Außerdem gibt es gute Gründe dafür, dass der Staatsaushalt im langfristigen Mittel gar nicht ausgeglichen werden darf. Es kann vereinzelt Perioden geben, in denen ein Überschuss im Staatshaushalt sinnvoll ist. Aber im langfristigen Mittel muss ein inflationsneutraler Staatshaushalt von normalen, monetär souveränen Staaten im Defizit sein.

Besser also, wenn man erkennt, dass der Kaiser keine Kleider hat. Inflationsprobleme kann es für monetär souveräne Staaten geben, Finanzierungsprobleme nicht.

Zurück zum BGE. Ich finde das Konzept sympathisch, aber ich teile die Bedenken, dass ein BGE vermutlich wegen der Inflationsproblematik nicht so realisierbar ist, wie sich die Befürworter das wünschen. Je näher die Roboterutopie kommt, um so realitischer wird ein BGE natürlich. Ich bezweifle, dass wir heute schon so weit sind, muss aber zugeben, dass es letztlich eine empirische Frage ist, die man nur experimentell beantworten kann.

Und als kleines Nachwort noch: Die Überlegungen zum Staatshaushalt oben gehen von einem monetär souveränen Staat aus. Deutschland ist nicht mehr monetär souverän, sondern Mitglied der Eurozone. Diese hat keinen Souverän, und ich würde sagen, dass genau darin das Kernproblem der Eurozone liegt. Um die Eurozone langfristig politisch zu stabilisieren, bräuchte es einen Haushalt auf Euroebene, der wichtige Stabilisatorenaufgaben übernimmt. Dazu gehören auch Elemente des Sozialstaats, und die BGE-Befürworter täten gut daran, für ein BGE auf Euro-Ebene zu werben. Aber all das ist ein anderes Thema.

Freitag, November 11, 2016

Was Trump und Hitler (vielleicht) gemeinsam haben

Den zukünftigen US-Präsidenten mit Faschisten zu vergleichen ist nicht neu, aber eine Facette des Vergleichs habe ich bisher selten gesehen. In seiner Rede zum Wahlsieg hat Trump von groß angelegten Investitionsprogrammen gesprochen. Tatsächlich kann die USA das sehr gut gebrauchen. Schon seit Jahren beklagen Bauingenieure dort den schlechten Zustand der Infrastruktur, und natürlich wäre ein solches Investitionsprogramm gut für die Wirtschaft und könnte flächendeckend die Nachfrage nach Arbeit stärken.

Das ist wichtig, denn man muss sich klar machen, dass es ganze Schichten in den USA gibt, an denen die Erholung von der Wirtschaftskrise vollkommen vorbeigegangen ist. Diese Menschen beklagen sich zurecht über den Status Quo.

Das vermischt sich dann oft mit den für mich illegitimen Klagen von Weißen, die einfach nur Angst vor dem Verlust des gefühlten Privilegs der Mehrheit haben. Werdet endlich erwachsen!, möchte ich diesen Menschen zurufen. Aber wer sie dann deswegen als Rassisten abstempelt und den legitimen Teil ihrer Beschwerden schlicht ignoriert macht es sich auch zu einfach. Man riskiert damit nämlich genau den Aufstieg von Gefährdern wie Trump.

Die Parallele zu Hitler, dessen Regierungsprogramm ja trotz allem Negativen tatsächlich auch durch massive Investitionen erst einmal die Leben vieler Menschen verbessert hat, ist mir deswegen so wichtig, weil sie so unglaublich traurig ist. Warum konnten sich die Demokraten der Weimarer Republik nicht zu großen Investitionsprogramm zusammenreißen? Warum gelang es in den USA in den letzten Jahren nicht? Und warum gelingt es auch heute in Deutschland wieder nicht und schafft so den Nährboden für die AfD? Warum lassen liberale, progressive Parteien und Politiker ihre Flanken so ungeschützt? Man könnte ja durchaus die positiven Seiten eines expansiven und inklusiven Wirtschaftsprogramms übernehmen ohne deswegen gleich dem globalen Klimawandel die Tür zu öffnen, alle Juden zu vernichten, oder einen Weltkrieg anzuzetteln.

Wenn ich heute mit Menschen darüber rede, begegne ich leider immer wieder Fehlinformationen über unser Wirtschaftssystem. Bei Hitler heißt es sofort, das wäre ja alles in Wirklichkeit schlecht gewesen wegen der Schuldenaufnahme (dem zweiten beliebten Argument bei Hitler, nämlich der Kritik am Rüstungsfokus, stimme ich zu - aber es gibt so viele sinnvolle Dinge, in die man investieren kann, es muss wirklich nicht das Militär sein!). Auch im heutigen Deutschland ist die Ideologie der schwarzen Null das große Hindernis. Genauso haben in den USA in den letzten Jahren die Republikaner gerne mit Verweis auf das Haushaltsdefizit blockiert. Letzteres mag Zweifel aufbringen, ob es unter Trump große Investitionsprogramme geben wird, aber die Republikaner haben ja auch immer wieder bewiesen, dass ihnen Haushaltsdefizite nur so lange wichtig sind, wie sie damit demokratische Vorschläge blockieren können. Paul Ryans (republikanischer Speaker of the House) eigene Budgetentwürfe enthalten, wenn man sie nüchtern analysiert, immer gigantische Haushaltsdefizite. Vielleicht kommt Trump mit seinem Investitionsprogramm trotzdem nicht durch den Kongress, aber die Chancen stehen nicht schlecht.

In Wirklichkeit sind Schulden und Defizite für monetär souveräne Staaten schlicht kein Problem - zumindest nicht so, wie die meisten Menschen das zu wissen glauben. In der Eurozone verkompliziert die fehlende Souveränität die Situation, aber das ist ein Thema für ein andermal.

Natürlich ist ein Investitionsprogramm alleine nicht genug. Auch an Bildung muss gearbeitet werden und an regionalen Strukturen, und sicherlich an noch mehr. Aber ein Investitionsprogramm ist ein guter, klar sichtbarer und medienwirksamer Anfang, mit dem es einfach ist, in die richtige Richtung zu gehen.

Unsere Demokratie ist zu wichtig, um sie einer ökonomischen Ideologie zu opfern.

Montag, Oktober 24, 2016

Compiling shaders: dynamically uniform variables and "convergent" intrinsics

There are some program transformations that are obviously correct when compiling regular single-threaded or even multi-threaded code, but that cannot be used for shader code. For example:

 v = texture(u_sampler, texcoord);  
 if (cond) {  
   gl_FragColor = v;  
 } else {  
   gl_FragColor = vec4(0.);  
 }  
   
 ... cannot be transformed to ...
   
 if (cond) {
   // The implicitly computed derivate of texcoord
   // may be wrong here if neighbouring pixels don't
   // take the same code path.
   gl_FragColor = texture(u_sampler, texcoord);
 } else {
   gl_FragColor = vec4(0.);  
 }

 ... but the reverse transformation is allowed.

Another example is:

 if (cond) {
   v = texelFetch(u_sampler[1], texcoord, 0);
 } else {
   v = texelFetch(u_sampler[2], texcoord, 0);
 }

 ... cannot be transformed to ...

 v = texelFetch(u_sampler[cond ? 1 : 2], texcoord, 0);
 // Incorrect, unless cond happens to be dynamically uniform.

 ... but the reverse transformation is allowed.

Using GL_ARB_shader_ballot, yet another example is:

 bool cond = ...;
 uint64_t v = ballotARB(cond);
 if (other_cond) {
   use(v);
 }

 ... cannot be transformed to ...

 bool cond = ...;
 if (other_cond) {
   use(ballotARB(cond));
   // Here, ballotARB returns 1-bits only for threads/work items
   // that take the if-branch.
 }

 ... and the reverse transformation is also forbidden.

These restrictions are all related to the GPU-specific SPMD/SIMT execution model, and they need to be taught to the compiler. Unfortunately, we partially fail at that today.

Here are some types of restrictions to think about (each of these restrictions should apply on top of any other restrictions that are expressible in the usual, non-SIMT-specific ways, of course):

  1. An instruction can be moved from location A to location B only if B dominates or post-dominates A.

    This restriction applies e.g. to instructions that take derivatives (like in the first example) or that explicitly take values from neighbouring threads (like in the third example). It also applies to barrier instructions.

    This is LLVM's convergent function attribute as I understand it.

  2. An instruction can be moved from location A to location B only if A dominates or post-dominates B.

    This restriction applies to the ballot instruction above, but it is not required for derivative computations or barrier instructions.

    This is in a sense dual to LLVM's convergent attribute, so it's co-convergence? Divergence? Not sure what to call this.

  3. Something vague about not introducing additional non-uniformity in the arguments of instructions / intrinsic calls.

    This last one applies to the sampler parameter of texture intrinsics (for the second example), to the ballot instruction, and also to the texture coordinates on sampling instructions that implicitly compute derivatives.

For the last type of restriction, consider the following example:

 uint idx = ...;
 if (idx == 1u) {
   v = texture(u_sampler[idx], texcoord);
 } else if (idx == 2u) {
   v = texture(u_sampler[idx], texcoord);
 }

 ... cannot be transformed to ...

 uint idx = ...;
 if (idx == 1u || idx == 2u) {
   v = texture(u_sampler[idx], texcoord);
 }

In general, whenever an operation has this mysterious restriction on its arguments, then the second restriction above must apply: we can move it from A to B only if A dominates or post-dominates B, because only then can we be certain that the move introduces no non-uniformity. (At least, this rule applies to transformations that are not SIMT-aware. A SIMT-aware transformation might be able to prove that idx is dynamically uniform even without the predication on idx == 1u or idx == 2u.)

However, the control flow rule is not enough:

 v1 = texture(u_sampler[0], texcoord);
 v2 = texture(u_sampler[1], texcoord);
 v = cond ? v1 : v2;

 ... cannot be transformed to ...

 v = texture(u_sampler[cond ? 0 : 1], texcoord);

The transformation does not break any of the CFG-related rules, and it would clearly be correct for a single-threaded program (given the knowledge that texture(...) is an operation without side effects). So the CFG-based restrictions really aren't sufficient to model the real set of restrictions that apply to the texture instruction. And it gets worse:

 v1 = texelFetch(u_sampler, texcoord[0], 0);
 v2 = texelFetch(u_sampler, texcoord[1], 0);
 v = cond ? v1 : v2;

 ... is equivalent to ...

 v = texelFetch(u_sampler, texcoord[cond ? 0 : 1], 0);

After all, texelFetch computes no implicit derivatives.

Calling the three kinds of restrictions 'convergent', 'co-convergent', and 'uniform', we get:

 texture(uniform sampler, uniform texcoord) convergent (co-convergent)
 texelFetch(uniform sampler, texcoord, lod) (co-convergent)
 ballotARB(uniform cond) convergent co-convergent
 barrier() convergent

For the texturing instructions, I put 'co-convergent' in parentheses because these instructions aren't inherently 'co-convergent'. The attribute is only there because of the 'uniform' function argument.

Actually, looking at the examples, it seems that co-convergent only appears when a function has a uniform argument. Then again, the texelFetch function can be moved freely in the CFG by a SIMT-aware pass that can prove that the move doesn't introduce non-uniformity to the sampler argument, so being able to distinguish functions that are inherently co-convergent (like ballotARB) from those that are only implicitly co-convergent (like texture and texelFetch) is still useful.

For added fun, things get muddier when you notice that in practice, AMDGPU doesn't even flag texturing intrinsics as 'convergent' today. Conceptually, the derivative-computing intrinsics need to be convergent to ensure that the texture coordinates for neighbouring pixels are preserved (as in the very first example). However, the AMDGPU backend does register allocation after the CFG has been transformed into the wave-level control-flow graph. So register allocation automatically preserves neighbouring pixels even when a texture instruction is sunk into a location with additional control-flow dependencies.

When we reach a point where vector register allocation happens with respect to the thread-level control-flow graph, then texture instructions really need to be marked as convergent for correctness. (This change would be beneficial overall, but is tricky because scalar register allocation must happen with respect to the wave-level control flow graph. LLVM currently wants to allocate all registers in one pass.)