Verwenden Sie NVM, um den Betrieb bei jedem Abbruch beharrlich wieder aufzunehmen

8

Wir werden versuchen, ein Programm zu schreiben, das sich daran erinnert, was es bisher getan hat, und das seinem Ziel näher kommt, wenn eine Wiederholung abgebrochen wird. Dies ist ein hartnäckiges Programm. Es wird ein nichtflüchtiger Speicher verwendet , um Informationen über Läufe hinweg als eine Anzahl von Cits zu speichern , die Bits sind, die berücksichtigen, was beim Abbruch passiert. Ich habe einmal vermutet, dass mit N Cits jedes Ziel bis zur Länge 2 (NK) für ein kleines festes K erreichbar ist. Ich neige jetzt dazu zu denken, dass das Ziel nicht erreicht werden kann :-(

Es wird um ein hartnäckiges Programm mit Ziel gebeten 01, das bereits ein nicht triviales Ziel ist ; oder ein strenger Beweis der Unmöglichkeit.

Ein hartnäckiges Programm ist definiert als eines, das:

  1. Wird bei jeder Ausführung ab demselben Einstiegspunkt ohne Eingabe ausgeführt und kann Informationen über Läufe ausschließlich über N Cits (unten definiert) austauschen . Jede andere Information hat entweder zu Beginn jedes Laufs denselben Inhalt, zu Beginn des Laufs unvorhersehbaren Inhalt, ist unveränderlich (das Programm selbst) oder nicht lesbar (vorherige Ausgabe und Wert ).
  2. Ist so, dass es beim Ausführen innerhalb einer Sitzung erkennbar anhält (unter Verwendung einer Funktion seiner Sprache), innerhalb einer begrenzten Verzögerung seit dem Start des Laufs, sofern es nicht vor dem Anhalten abgebrochen wird ; Der Abbruch erfolgt zu einem beliebigen Zeitpunkt und verhindert den Betrieb bis zu einem weiteren Lauf (falls vorhanden).
  3. Ist so , dass die Verkettung in chronologischer Reihenfolge der Zeichen es gibt ist die gleiche endliche Zeichenfolge (das Ziel ) in jeder Sitzung von arbitrarilly viele Läufe mindestens einen Lauf aufweist , wo das Programm ausgeführt wurde , nach links , bis er anhält.
  4. Gibt Zeichen mit einem Gerät aus, das atomar : einenvom Programm gesetzten Wert unter 0 1 2 3empfängt, und gibt(bzw.) Werte zwischen 0 oder 2 (bzw. 1 oder 3) aus, wenn sich dieser Wert vom vorherigen unterscheidet Wert put, angenommen 0 für den ersten Put in einer Sitzung.01

Hartnäckige Programme existieren! Jedes Programm, das einfach eine feste Anzahl von Malen eines gültigen festen Werts setzt und dann anhält, ist hartnäckig, wobei das Ziel entweder leer ist (wenn Zahl oder Wert 0 ist) 0(wenn Zahl positiv ist und Wert 2 ist) oder 1(anderweitig). Jedes längere Ziel erfordert NVM.

Jeder Cit modelliert ein NVM-Bit unter Berücksichtigung der Auswirkung eines Laufs, der während eines Schreibvorgangs in den Cit abgebrochen wird . Zu jedem Zeitpunkt befindet sich eine Stadt in einem von drei möglichen Zuständen 0 1oder U. Der aus einer Cit gelesene Wert ist immer 0 oder 1; es entspricht auch dem Zustand, es sei denn U. Ein cit wird so initialisiert, dass es 0vor dem ersten Durchlauf in einer Sitzung angezeigt wird, und ändert ansonsten den Status nur, wenn das Programm einen Schreibvorgang anordnet. Dies hängt davon ab, was geschrieben wurde, ob der Lauf während des Schreibvorgangs abgebrochen wird oder nicht, und von der Cit's ehemaliger Staat:

         Former state  0   1   U    Rationale given by hardware guru
Operation
  Write 0 completed    0   0   0    Discharging returns cit to 0
  Write 0 aborted      0   U   U    Aborted discharging leaves cit unspecified
  Write 1 aborted      U   1   U    Aborted    charging leaves cit unspecified
  Write 1 completed    1   1   U    Charging a non-discharged cit is inhibited

Die HAL für das oben Genannte wird in C wie folgt deklariert:

/* file "hal.h"              unspecified parameter values give undefined behavior */
#define  N 26                       /* number of  cits                            */
void     p(unsigned v);             /* put value v; v<4                           */
unsigned r(unsigned i);             /* read from  cit at i; returns 0 or 1;  i<N. */
void     w(unsigned i, unsigned b); /* write b to cit at i;    b is 0 or 1;  i<N. */
/*                            all functions return in bounded time unless aborted */

Unser erster Versuch eines hartnäckigen Programms mit Ziel 01ist:

#include "hal.h"                    /* discount this line's length                */
main(){                             /* entry point, no parameters or input        */
    if (r(3)==0)                    /* cit 3 read as 0, that is state 0 or U      */
        w(3,0),                     /* write 0 to cit 3, to ensure state 0        */
        p(2);                       /* put 2 with output '0' initially            */
    w(3,1),                         /* mark we have output '0' (trouble spot!)    */
    p(1);                           /* put 1 with output '1'                      */
}                                   /* halt (but we can be re-run)                */

Murphy macht eine erste Sitzung, beendet den ersten Lauf und beendet die Sitzung. Die Ausgabe der Sitzung ist die Ausgabe des einzelnen Laufs 01. So weit, ist es gut.
In einer anderen Sitzung bricht Murphy einen ersten Lauf ab w(3,1)und lässt cit im Zustand U; In einem zweiten Durchlauf entscheidet Murphy, dass r(3)1 ist (dass sich cit im Status befindet U), und lässt das laufende Programm stehen (beachten Sie, dass w(3,1)der Status des cit nicht geändert wurde). In einem dritten Lauf entscheidet Murphy, dass r(3)es 0 ist, bricht ab p(2)und beendet die Sitzung.
Die verkettete Ausgabe der zweiten Sitzung ist 010(ein Zeichen pro Lauf), unterscheidet sich jedoch von 01der ersten Sitzung, sodass das Programm nicht hartnäckig ist, da Bedingung 3 nicht erfüllt ist.


Die Sprache ist kostenlos. Passen Sie die C-Oberfläche an die Sprache an. Ich werde die beste Antwort basierend auf der niedrigsten Anzahl der verwendeten Cits auswählen. dann niedrigste Anzahl von Schreibvorgängen im ungünstigsten Fall vom Lauf zur Ausgabe (oder anhalten, wenn keine Ausgabe erfolgt); dann niedrigste Anzahl von Schreibvorgängen vor dem Anhalten in einer Sitzung ohne Abbruch; dann kürzestes Programm. Zählen Sie nur den aufrufenden Code, nicht die Schnittstelle oder deren Implementierung, die nicht benötigt wird. Ein strenger Beweis der Unmöglichkeit würde jedes Programm eliminieren (und mich überraschen) ; Ich würde das am einfachsten zu erfassende auswählen.

Bitte überprüfen Sie dreimal, ob das Programm das Ziel gemäß 3 wirklich erreicht, unabhängig von der Anzahl und dem Zeitpunkt der Abbrüche. das ist schwierig!

Update: Ich habe eine Kandidaten Antwort . Fühlen Sie sich frei, es zu trounzen. Oh, Hammar hat das in wenigen Minuten mit einem systematischen Programm gemacht!

Status : Bisher haben wir keine Lösung; sicher wissen, dass es keine Lösung mit 1 oder 2 Cits gibt; habe aber keinen Beweis der Unmöglichkeit mit 3 oder mehr Cits. Die Aussage wurde nicht als mehrdeutig befunden. Das Problem hätte eine Lösung, wenn wir die Cit-Matrix geringfügig ändern würden (z. B. rechts unten auf 1 setzen. In diesem Fall ist das obige Beispiel korrekt).

fgrieu
quelle
Ich habe das Gefühl, dass eine ähnliche Frage gestellt wurde - vielleicht mehr in Bezug auf Flash-Speicher / Spannungsspitzen, denke ich -, aber ich kann sie scheinbar nicht finden.
Gaffi
1
@Gaffi: Ich habe vor zwei Wochen eine Frage gestellt, in der ich ein Programm mit ähnlichen Eigenschaften für Dezimalstellen von Pi-3 in Binärform auf die maximal mögliche Länge gestellt habe, wenn eine Reihe von Cits und andere Dinge mit Stromausfall und nicht mit Abbruch formuliert wurden . Es wurde (positiv) kritisiert, wie man gültige Antworten ermitteln könne. Ich erkannte, dass ich es wahrscheinlich nicht konnte und entfernte die Frage. Mit diesem akribisch formulierten Code-Golf bin ich zuversichtlich, dass ich das Programm für viele Sprachen überprüfen oder ein kürzeres hartnäckiges veröffentlichen kann. Ich bedaure nur, dass ich das Ziel ein bisschen sexy hätte machen sollen.
fgrieu
1
Sind Sie sicher, dass dies Code-Golf sein soll? Es scheint mir, dass die Herausforderung darin besteht, ein solches Programm überhaupt zu schreiben (und seine Richtigkeit zu beweisen); Sobald dies erreicht ist, wird das Golfen zu einer ziemlich trivialen Übung (und etwas unklar, da wir die Benutzeroberfläche anpassen dürfen). Vielleicht machen Sie es stattdessen einfach Code-Challenge ?
Ilmari Karonen
Eine andere Frage: Würde es als Lösung gelten, die Unmöglichkeit nicht trivialer hartnäckiger Programme zu beweisen? (Ich habe noch keinen solchen Beweis, aber ich fange an zu denken, dass dies der Fall sein könnte.)
Ilmari Karonen
@IlmariKaronen: Beweis der Unmöglichkeit wäre König! Ich habe eine Lösung veröffentlicht, die möglicherweise gültig ist. Überzeugen Sie sich selbst.
fgrieu

Antworten:

6

Ich habe zwar weder eine Lösung noch einen Beweis für die Unmöglichkeit, aber ich dachte, ich würde mein Testgeschirr für jeden veröffentlichen, der damit herumspielen möchte, da ich zu diesem Zeitpunkt so ziemlich aufgegeben habe.

Es ist eine Implementierung der HAL-Modellierungsprogramme als Haskell-Monade. Es prüft die Hartnäckigkeit, indem es eine Breitensuche über die möglichen Sitzungen durchführt, um nach Sitzungen zu suchen, die entweder 1. einmal angehalten wurden, ohne die richtige Ausgabe zu erzeugen, oder 2. eine Ausgabe erzeugt haben, die kein Präfix der gewünschten ist (dies fängt auch Programme ab, die eine unendliche Ausgabe erzeugen).

{-# LANGUAGE GADTs #-}

module HAL where

import Control.Monad
import Data.List

import Data.Map (Map)
import qualified Data.Map as Map

import Data.Set (Set)
import qualified Data.Set as Set

newtype CitIndex = Cit Int
  deriving (Eq, Ord, Show)

data CitState = Stable Int | Unstable
  deriving (Eq, Ord, Show)

data Program a where
  Return :: a -> Program a
  Bind :: Program a -> (a -> Program b) -> Program b
  Put :: Int -> Program ()
  Read :: CitIndex -> Program Int
  Write :: CitIndex -> Int -> Program ()
  Log :: String -> Program ()
  Halt :: Program ()

instance Monad Program where
  return = Return
  (>>=) = Bind

data Session = Session
  { cits :: Cits
  , output :: [Int]
  , lastPut :: Int
  , halted :: Bool
  } deriving (Eq, Ord, Show)

data Event
  = ReadE CitIndex Int
  | PutE Int
  | WriteSuccessE CitIndex Int
  | WriteAbortedE CitIndex Int
  | LogE String
  | HaltedE
  deriving (Eq, Ord, Show)

type Log = [(Event, Cits)]

check :: Program () -> Int -> [Int] -> IO ()
check program n goal =
  case tenacity (program >> Halt) goal of
    Tenacious  -> putStrLn "The program is tenacious."
    Invalid ss -> do
      putStrLn "The program is invalid. Example sequence:"
      forM_ (zip [1..] ss) $ \(i, (log, s)) -> do
        ruler
        putStrLn $ "Run #" ++ show i ++ ", Initial state: " ++ formatState n s
        ruler
        mapM_ (putStrLn . formatEvent n) log
  where ruler = putStrLn $ replicate 78 '='

run :: Program a -> Session -> [(Maybe a, Log, Session)]
run (Return x) s = [(Just x, [], s)]
run (Bind x f) s = do
  (r1, l1, s1) <- run x s
  case r1 of
    Just y  -> [(r2, l1 ++ l2, s2) | (r2, l2, s2) <- run (f y) s1]
    Nothing -> [(Nothing, l1, s1)]
run (Put x) s = [(Just (), [(PutE x, cits s)], s')]
  where s' | lastPut s /= x = s { lastPut = x, output = output s ++ [x `mod` 2] }
           | otherwise      = s
run (Read cit) s =
  case lookupCit cit (cits s) of
    Stable x -> [(Just x, [(ReadE cit x, cits s)], s)]
    Unstable -> [(Just x, [(ReadE cit x, cits s)], s) | x <- [0, 1]]
run (Write cit x) (s @ Session { cits = cits }) =
  [(Just (), [(WriteSuccessE cit x, completed)], s { cits = completed }),
   (Nothing, [(WriteAbortedE cit x, aborted  )], s { cits = aborted })]
  where state = lookupCit cit cits
        completed = updateCit cit newState cits 
          where newState = case (x, state) of
                             (0, _)        -> Stable 0
                             (1, Unstable) -> Unstable
                             (1, Stable _) -> Stable 1

        aborted = updateCit cit newState cits
          where newState = case (x, state) of
                             (0, Stable 0) -> Stable 0
                             (0, _)        -> Unstable
                             (1, Stable 1) -> Stable 1
                             (1, _)        -> Unstable
run (Halt) s = [(Just (), [(HaltedE, cits s)], s { halted = True })] 
run (Log msg) s = [(Just (), [(LogE msg, cits s)], s)]

newSession :: Session
newSession = Session
  { cits = initialCits
  , output = []
  , lastPut = 0
  , halted = False }

newtype Cits = Cits (Map CitIndex CitState)
  deriving (Eq, Ord, Show)

initialCits = Cits (Map.empty)

lookupCit :: CitIndex -> Cits -> CitState
lookupCit cit (Cits m) = Map.findWithDefault (Stable 0) cit m

updateCit :: CitIndex -> CitState -> Cits -> Cits
updateCit index (Stable 0) (Cits m) = Cits $ Map.delete index m 
updateCit index newState (Cits m) = Cits $ Map.insert index newState m

data Tenacity = Tenacious | Invalid [(Log, Session)]
  deriving (Eq, Ord, Show)

tenacity :: Program () -> [Int] -> Tenacity
tenacity program goal = bfs Set.empty [(newSession, [])]
  where
    bfs :: Set Session -> [(Session, [(Log, Session)])] -> Tenacity
    bfs visited [] = Tenacious
    bfs visited ((s, pred) : ss)
      | Set.member s visited = bfs visited ss
      | valid s   = bfs (Set.insert s visited) $ ss ++ [(s', (l, s) : pred) | (_, l, s') <- run program s]
      | otherwise = Invalid $ reverse (([], s) : pred)

    valid :: Session -> Bool
    valid Session { output = output, halted = halted }
      | halted    = output == goal
      | otherwise = output `isPrefixOf` goal

formatState :: Int -> Session -> String
formatState n s = "[cits: " ++ dumpCits n (cits s) ++ "] [output: " ++ dumpOutput s ++ "]"

formatEvent :: Int -> (Event, Cits) -> String
formatEvent n (event, cits) = pad (78 - n) text ++ dumpCits n cits 
  where text = case event of
                 ReadE (Cit i) x         -> "read " ++ show x ++ " from cit #" ++ show i
                 PutE x                  -> "put " ++ show x
                 WriteSuccessE (Cit i) x -> "wrote " ++ show x ++ " to cit #" ++ show i
                 WriteAbortedE (Cit i) x -> "aborted while writing " ++ show x ++ " to cit #" ++ show i
                 LogE msg                -> msg
                 HaltedE                 -> "halted"

dumpCits :: Int -> Cits -> String
dumpCits n cits = concat [format $ lookupCit (Cit i) cits | i <- [0..n-1]]
  where format (Stable i) = show i
        format (Unstable) = "U" 

dumpOutput :: Session -> String
dumpOutput s = concatMap show (output s) ++ " (" ++ show (lastPut s) ++ ")"

pad :: Int -> String -> String
pad n s = take n $ s ++ repeat ' '

Hier ist das Beispielprogramm des OP, das in Haskell konvertiert wurde.

import Control.Monad (when)

import HAL

-- 3 cits, goal is 01
main = check example 3 [0, 1]

example = do
  c <- Read (Cit 2)
  d <- Read (Cit c)
  when (0 == c) $ do
    Log "in first branch"
    Write (Cit 2) 0
    Write (Cit 1) 0
    Write (Cit 1) (1 - d)
    Write (Cit 2) 1
  Write (Cit 0) 0
  when (d == c) $ do
    Log "in second branch"
    Put 2
    Write (Cit 2) 0
  Write (Cit 0) 1
  Put 1

Und hier ist die entsprechende Ausgabe, die zeigt, dass das Programm nicht hartnäckig ist.

The program is invalid. Example sequence:
==============================================================================
Run #1, Initial state: [cits: 000] [output:  (0)]
==============================================================================
read 0 from cit #2                                                         000
read 0 from cit #0                                                         000
in first branch                                                            000
wrote 0 to cit #2                                                          000
wrote 0 to cit #1                                                          000
wrote 1 to cit #1                                                          010
wrote 1 to cit #2                                                          011
wrote 0 to cit #0                                                          011
in second branch                                                           011
put 2                                                                      011
wrote 0 to cit #2                                                          010
wrote 1 to cit #0                                                          110
put 1                                                                      110
halted                                                                     110
==============================================================================
Run #2, Initial state: [cits: 110] [output: 01 (1)]
==============================================================================
read 0 from cit #2                                                         110
read 1 from cit #0                                                         110
in first branch                                                            110
wrote 0 to cit #2                                                          110
wrote 0 to cit #1                                                          100
wrote 0 to cit #1                                                          100
aborted while writing 1 to cit #2                                          10U
==============================================================================
Run #3, Initial state: [cits: 10U] [output: 01 (1)]
==============================================================================
read 1 from cit #2                                                         10U
read 0 from cit #1                                                         10U
wrote 0 to cit #0                                                          00U
aborted while writing 1 to cit #0                                          U0U
==============================================================================
Run #4, Initial state: [cits: U0U] [output: 01 (1)]
==============================================================================
read 0 from cit #2                                                         U0U
read 0 from cit #0                                                         U0U
in first branch                                                            U0U
wrote 0 to cit #2                                                          U00
wrote 0 to cit #1                                                          U00
wrote 1 to cit #1                                                          U10
wrote 1 to cit #2                                                          U11
wrote 0 to cit #0                                                          011
in second branch                                                           011
put 2                                                                      011
wrote 0 to cit #2                                                          010
wrote 1 to cit #0                                                          110
put 1                                                                      110
halted                                                                     110
==============================================================================
Run #5, Initial state: [cits: 110] [output: 0101 (1)]
==============================================================================
Hammar
quelle
4

Es sei denn, jemand kann einen Fehler in diesem Programm finden. Ich denke, es überprüft und lehnt jedes relevante Zwei-Cit-Programm ab.

Ich behaupte, dass es ausreicht, Programme zu betrachten, die alle Cits lesen und eine durch die Menge gebildete Zahl einschalten. Jeder Zweig des Schalters besteht aus einer Reihe von Schreib- und Put-Vorgängen. Es macht nie Sinn, dieselbe Zahl mehr als einmal in einen Zweig zu setzen oder die zweite Ausgangsziffer vor die erste zu setzen. (Ich bin moralisch sicher, dass es keinen Sinn macht, die erste Ziffer anders als am Anfang eines Zweigs oder die zweite Ziffer anders als am Ende auszugeben, aber im Moment vermeide ich diese Vereinfachung).

Dann hat jeder Zweig einen Zielsatz von Cits, die er setzen möchte, und bewegt sich darauf zu, indem er die Bits, die 0 sein sollen, auf 0 und die Bits, die 1 sein sollen, auf 0 und dann auf 1 setzt; Diese Schreibvorgänge können auf verschiedene Arten angeordnet werden. Es macht keinen Sinn, ein Bit auf 1 zu setzen, es sei denn, Sie haben es in diesem Lauf bereits auf 0 gesetzt, oder es ist wahrscheinlich ein Nein.

Es werden 13680577296 mögliche Programme berücksichtigt. Eine 4-Kern-Maschine benötigte knapp 7 Stunden, um alle zu überprüfen, ohne eine einzige Lösung zu finden.

import java.util.*;

// State is encoded with two bits per cit and two bits for the output state.
//    ... [c_2=U][c_2=1/U][c_1=U][c_1=1/U][output_hi][output_lo]
// Output state must progress 0->1->2.
// Instruction (= program branch) is encoded with three or four bits per step.
//      The bottom two bits are the cit, or 0 for output/loop
//      If they're 0, the next two bits are 01 or 10 for output state, or 11 for halt.
//      Otherwise the next two bits are the value to write to the cit.
public class CitBruteForcer implements Runnable {

    static final int[] TRANSITION_OK = new int[]{
        // Index: write curr_hi curr_lo
        0,  // write 0 to 0 => 0
        0,  // write 0 to 1 => 0
        0,  // write 0 to U => 0
        -1, // invalid input
        1,  // write 1 to 0 => 1
        1,  // write 1 to 1 => 1
        2,  // write 1 to U => U
        -1  // invalid input
    };
    static final int[] TRANSITION_ABORT = new int[]{
        // Index: write curr_hi curr_lo
        0,  // write 0 to 0 => 0
        2,  // write 0 to 1 => U
        2,  // write 0 to U => U
        -1, // invalid input
        2,  // write 1 to 0 => U
        1,  // write 1 to 1 => 1
        2,  // write 1 to U => U
        -1  // invalid input
    };

    private final int[] possibleInstructions;
    private final int numCits, offset, step;
    private long tested = 0;

    private CitBruteForcer(int numCits, int[] possibleInstructions, int offset, int step)
    {
        this.numCits = numCits;
        this.possibleInstructions = possibleInstructions;
        this.offset = offset;
        this.step = step;
    }

    public void run()
    {
        int numStates = 1 << numCits;
        int n = possibleInstructions.length;
        long limit = pow(n, numStates);

        for (long i = offset; i < limit; i += step) {
            // Decode as a base-n number.
            int[] instructions = new int[numStates];
            long tmp = i;
            for (int j = 0; j < numStates; j++, tmp /= n) instructions[j] = possibleInstructions[(int)(tmp % n)];
            Program p = new Program(numCits, instructions);
            if (p.test()) System.out.println("Candidate: " + i);
            tested++;
        }
    }

    public static void main(String[] args) {
        int numCits = 2;
        int numThreads = 4;
        int[] possibleInstructions = buildInstructions(numCits);

        int numStates = 1 << numCits;
        int n = possibleInstructions.length;
        System.out.println(n + " possible instructions");
        long limit = pow(n, numStates);

        CitBruteForcer[] forcers = new CitBruteForcer[numThreads];
        for (int i = 0; i < numThreads; i++) {
            forcers[i] = new CitBruteForcer(numCits, possibleInstructions, i, numThreads);
            new Thread(forcers[i]).start();
        }

        int pc = 0;
        while (pc < 100) {
            // Every 10 secs is easily fast enough to update
            try { Thread.sleep(10000); } catch (InterruptedException ie) {}

            long tested = 0;
            for (CitBruteForcer cbf : forcers) tested += cbf.tested; // May underestimate because the value may be stale
            int completed = (int)(100 * tested / limit);
            if (completed > pc) {
                pc = completed;
                System.out.println(pc + "% complete");
            }
        }
        System.out.println(limit + " programs tested");
    }

    private static int[] buildInstructions(int numCits) {
        int limit = (int)pow(3, numCits);
        Set<Integer> instructions = new HashSet<Integer>();
        for (int target = 0; target <= limit; target++) {
            int toSetZero = 0, toSetOne = 0;
            for (int i = 0, tmp = target; i < numCits; i++, tmp /= 3) {
                if (tmp % 3 == 0) toSetZero |= 1 << i;
                else if (tmp % 3 == 1) toSetOne |= 1 << i;
            }
            buildInstructions(0xc, toSetZero, toSetOne, false, false, instructions);
        }
        int[] rv = new int[instructions.size()];
        Iterator<Integer> it = instructions.iterator();
        for (int i = 0; i < rv.length; i++) rv[i] = it.next().intValue();
        return rv;
    }

    private static void buildInstructions(int suffix, int toSetZero, int toSetOne, boolean emitted0, boolean emitted1, Set<Integer> instructions)
    {
        if (!emitted1) {
            buildInstructions((suffix << 4) + 0x8, toSetZero, toSetOne, false, true, instructions);
        }
        if (!emitted0) {
            buildInstructions((suffix << 4) + 0x4, toSetZero, toSetOne, true, true, instructions);
        }
        if (toSetZero == 0 && toSetOne == 0) {
            instructions.add(suffix);
            return;
        }

        for (int i = 0; toSetZero >> i > 0; i++) {
            if (((toSetZero >> i) & 1) == 1) buildInstructions((suffix << 3) + 0x0 + i+1, toSetZero & ~(1 << i), toSetOne, emitted0, emitted1, instructions);
        }
        for (int i = 0; toSetOne >> i > 0; i++) {
            if (((toSetOne >> i) & 1) == 1) buildInstructions((suffix << 3) + 0x4 + i+1, toSetZero | (1 << i), toSetOne & ~(1 << i), emitted0, emitted1, instructions);
        }
    }

    private static long pow(long n, int k) {
        long rv = 1;
        while (k-- > 0) rv *= n;
        return rv;
    }

    static class Program {
        private final int numCits;
        private final int[] instructions;
        private final Set<Integer> checked = new HashSet<Integer>();
        private final Set<Integer> toCheck = new HashSet<Integer>();

        Program(int numCits, int[] instructions) {
            this.numCits = numCits;
            this.instructions = (int[])instructions.clone();
            toCheck.add(Integer.valueOf(0));
        }

        boolean test() {
            try {
                while (!toCheck.isEmpty()) checkNext();
            } catch (Exception ex) {
                return false;
            }

            // Need each reachable state which hasn't emitted the full output to be able to reach one which has.
            Set<Integer> reachable = new HashSet<Integer>(checked);
            for (Integer reached : reachable) {
                checked.clear();
                toCheck.clear();
                toCheck.add(reached);
                while (!toCheck.isEmpty()) checkNext();
                boolean emitted = false;
                for (Integer i : checked) {
                    if ((i.intValue() & 3) == 2) emitted = true;
                }
                if (!emitted) return false;
            }

            return true;
        }

        private void checkNext() {
            Integer state = toCheck.iterator().next();
            toCheck.remove(state);
            checked.add(state);
            run(state.intValue());
        }

        private void run(final int state) {
            // Check which instructions apply
            for (int i = 0; i < instructions.length; i++) {
                boolean ok = true;
                for (int j = 1; j <= numCits; j++) {
                    int cit = (state >> (2 * j)) & 3;
                    if (cit == 2 || cit == ((i >> (j-1)) & 1)) continue;
                    ok = false; break;
                }
                if (ok) run(state, instructions[i]);
            }
        }

        private void run(int state, int instruction) {
            while (true) {
                int cit = instruction & 3;
                if (cit == 0) {
                    int emit = (instruction >> 2) & 3;
                    if (emit == 3) break;
                    if (emit > (state & 3) + 1 || emit < (state & 3)) throw new IllegalStateException();
                    state = (state & ~3) | emit;
                    instruction >>= 4;
                }
                else {
                    int shift = 2 * cit;
                    int transitionIdx = (instruction & 4) + ((state >> shift) & 3);
                    int stateMasked = state & ~(3 << shift);
                    consider(stateMasked | (TRANSITION_ABORT[transitionIdx] << shift));
                    state = stateMasked | (TRANSITION_OK[transitionIdx] << shift);
                    instruction >>= 3;
                }
                // Could abort between instructions (although I'm not sure this is strictly necessary - this is "better" than the mid-instruction abort
                consider(state);
            }
            // Halt or loop.
            consider(state);
        }

        private void consider(int state) {
            if (!checked.contains(state)) toCheck.add(state);
        }
    }
}
Peter Taylor
quelle
Wenn ich meine Annahme über die Platzierung von Ausgaben verwende, sinkt die Anzahl der 2-Cit-Programme erheblich und die Überprüfungszeit beträgt weniger als eine Minute, aber selbst mit dieser Annahme beträgt die Anzahl der 3-Cit-Programme mehr als 2 ^ 80 oder a Faktor von etwa 2 ^ 47 mehr als die 2-Cit-Programme in 7 Stunden überprüft. Mit anderen Worten, nicht einigermaßen brutal.
Peter Taylor
0

Das heißt war mein bester Versuch auf meine Frage zu beantworten. Ich bin mir nicht sicher, ob es die Anforderung 3 erfüllt, und bin offen für Widerlegungen. Es ist nicht hartnäckig :-(

/*  1 */    #include "hal.h"
/*  2 */    main(){
/*  3 */        unsigned c = r(2);  // get cit 2 into c
/*  4 */        unsigned d = r(c);  // get cit c into d
/*  5 */    // here if d==c then we have not output 1 yet  
/*  6 */    //              else we have     output 0   
/*  7 */        if (0==c)
/*  8 */            w( 2, 0 ),      // cit 2 to 0
/*  9 */            w( 1, 0 ),      // cit 1 to 0
/* 10 */            w( 1,!d ),      // cit 1 to complement of d
/* 11 */            w( 2, 1 );      // cit 2 to 1
/* 12 */        w( 0, 0 );          // cit 0 to 0
/* 13 */        if (d==c)
/* 14 */            p( 2 ),         // put 2, first one outputs 0
/* 15 */            w( 2, 0 );      // cit 2 to 0
/* 16 */        w( 0, 1 );          // cit 0 to 1
/* 17 */        p( 1 );             // put 1, first one outputs 1
/* 16 */    }                       // halt
fgrieu
quelle
2
Mein Testprogramm sagt, dass das nicht hartnäckig ist: 1. Führen Sie das Programm vollständig aus. Ausgabe : 01, Cits : 110. 2. Abbruch während # 15. Cits : 10U. 3. Lesen Sie c = 1, brechen Sie während # 12 ab. Cits : U0U. 4. Lesen Sie c = 0, d = 0und das Programm wird 01erneut gedruckt .
Hammar
Entschuldigung, der erste Abbruch sollte in Zeile 11 und nicht in Zeile 15 erfolgen.
Hammar