Gunakan NVM untuk melanjutkan operasi kapan pun dibatalkan

8

Kami akan mencoba untuk menulis sebuah program yang mengingat apa yang telah ia lakukan sejauh ini dan terus menuju tujuannya jika dibatalkan kembali. Ini adalah program yang ulet . Ini akan menggunakan Memori Non-Volatile untuk menyimpan informasi lintas, sebagai sejumlah kutipan , yang merupakan bit dengan memperhitungkan apa yang terjadi pada batalkan. Saya pernah menduga bahwa dengan kutipan N , setiap tujuan hingga panjang 2 (NK) dapat dicapai, untuk beberapa K. tetap kecil. Saya sekarang condong ke arah berpikir tujuan tidak dapat dicapai :-(

Itu diminta program ulet dengan tujuan 01 , yang sudah merupakan tujuan non-sepele ; atau bukti kuat ketidakmungkinan.

Sebuah ulet Program didefinisikan sebagai salah satu yang:

  1. Setiap kali dijalankan , dijalankan mulai dari titik entri yang sama, tanpa input, dan dapat berbagi informasi lintas berjalan secara eksklusif dengan menggunakan N kutipan (didefinisikan di bawah); setiap informasi lain memiliki konten yang sama pada awal setiap proses, memiliki konten yang tidak dapat diprediksi pada awal proses, tidak dapat diubah (program itu sendiri), atau tidak dapat dibaca ( output dan nilai sebelumnya ).
  2. Adalah sedemikian sehingga ketika dijalankan dalam suatu sesi itu dapat dikenali berhenti (menggunakan fitur bahasanya), dalam beberapa penundaan terbatas sejak mulai dijalankan, kecuali dibatalkan sebelum dihentikan; batalkan terjadi kapan saja sembarang arbitrase dan mencegah operasi sampai menjalankan lain (jika ada).
  3. Sedemikian rupa sehingga rangkaian dalam urutan kronologis dari karakter yang dihasilkannya adalah string berhingga yang sama ( tujuan ) dalam setiap sesi arbitrase banyak run yang terdiri dari setidaknya satu run di mana program dibiarkan berjalan sampai berhenti.
  4. Output karakter menggunakan perangkat yang secara atom : menerima nilai di antara 0 1 2 3 dimasukkan oleh program, dan output0(resp.1) Untuk nilai di antara 0 atau 2 (resp 1 atau 3) jika dan hanya jika nilai itu berbeda dari sebelumnya nilai put, dianggap 0 untuk put pertama dalam suatu sesi.

Ada program ulet! Setiap program yang hanya menempatkan beberapa kali nilai tetap yang valid, kemudian berhenti, adalah ulet dengan tujuan baik kosong (jika angka atau nilainya 0), 0(jika angka positif dan nilainya 2), atau 1(jika tidak). Setiap tujuan yang lebih lama membutuhkan NVM.

Setiap cit memodelkan satu NVM bit dengan akun untuk efek run yang dibatalkan saat menulis ke cit. Kapan saja cit berada di salah satu dari tiga kemungkinan negara 0 1atau U. Nilai yang dibaca dari cit selalu 0 atau 1; itu juga cocok dengan keadaan kecuali U. Cit diinisialisasi untuk menyatakan 0sebelum menjalankan pertama dalam suatu sesi dan sebaliknya mengubah hanya menyatakan ketika menulis untuk itu diperintahkan oleh program, dengan efek tergantung pada apa yang tertulis, apakah menjalankan dibatalkan pada saat penulisan atau tidak, dan dari negara bekas cit:

         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

The HAL untuk di atas dinyatakan dalam C sebagai:

/* 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 */

Upaya pertama kami pada program ulet dengan tujuan 01adalah:

#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 membuat sesi pertama, membiarkan lari pertama berhenti, dan mengakhiri sesi; output sesi adalah output single run 01; sejauh ini bagus.
Di sesi lain, Murphy membatalkan putaran pertama selama w(3,1), meninggalkan cit dalam keadaan U; dalam menjalankan kedua Murphy memutuskan itu r(3)adalah 1 (bahwa cit dalam keadaan U), dan meninggalkan program berhenti (perhatikan bagaimana w(3,1)tidak mengubah keadaan cit); dalam menjalankan ketiga Murphy memutuskan itu r(3)adalah 0, dibatalkan setelah p(2), dan mengakhiri sesi.
Output gabungan sesi kedua adalah 010(satu karakter per run) tetapi berbeda dari 01pada sesi pertama, sehingga program tidak ulet, karena kondisi 3 tidak terpenuhi.


Bahasa gratis, sesuaikan antarmuka C sesuai bahasa. Saya akan memilih jawaban terbaik berdasarkan jumlah kutipan terendah yang digunakan; kemudian jumlah terburuk terburuk dari penulisan dari jalankan ke output (atau berhenti jika tidak ada output); lalu jumlah penulisan terendah sebelum berhenti dalam sesi tanpa dibatalkan; maka program terpendek. Hitung hanya kode panggilan, bukan antarmuka atau implementasinya, yang tidak diperlukan. Sebuah bukti ketidakmungkinan akan menghilangkan program apa pun (dan mengejutkan saya) ; Saya akan memilih yang paling sederhana untuk dipahami.

Harap periksa tiga kali bahwa program benar-benar memenuhi tujuan sesuai 3, terlepas dari jumlah dan jumlah aborsi; itu sulit!

Pembaruan: Saya menambahkan jawaban kandidat . Jangan ragu untuk mengalahkannya. Oh, hammar melakukannya dalam hitungan menit menggunakan program yang sistematis!

Status : Sejauh ini kami tidak punya solusi; tahu pasti bahwa tidak ada solusi dengan 1 atau 2 kutipan; tetapi tidak memiliki bukti ketidakmungkinan dengan 3 kutipan atau lebih. Pernyataan itu tidak ditemukan ambigu. Masalahnya akan memiliki solusi jika kita mengubah matriks cit sedikit (misalnya diletakkan di 1 di kanan bawah, dalam hal ini contoh di atas sudah benar).

fgrieu
sumber
Saya merasa seperti pertanyaan serupa ditanyakan - mungkin lebih berkaitan dengan memori flash / lonjakan daya, saya pikir - tetapi saya tidak bisa menemukannya.
Gaffi
1
@ Gaffi: Saya membuat pertanyaan dua minggu yang lalu menanyakan sebuah program dengan sifat yang mirip untuk desimal Pi-3 dalam biner dengan panjang maksimum yang mungkin diberikan sejumlah kutipan, dan hal-hal lain, ditulis dengan pemadaman listrik daripada dibatalkan . Itu bertemu dengan kritik (positif) yang menanyakan bagaimana seseorang akan menentukan jawaban yang valid. Saya menyadari bahwa kemungkinan saya tidak bisa, dan menghilangkan pertanyaan itu. Dengan kode-golf yang ditulis dengan cermat ini, saya yakin bahwa saya dapat memeriksa program, atau memposting yang ulet lebih pendek, untuk banyak bahasa. Satu-satunya penyesalan saya adalah bahwa saya seharusnya membuat tujuan sedikit lebih seksi.
fgrieu
1
Apakah Anda yakin ini golf kode? Tampak bagi saya bahwa tantangannya adalah dalam menulis program semacam itu sama sekali (dan membuktikan kebenarannya); setelah itu selesai, bermain golf menjadi latihan yang cukup sepele (dan agak tidak jelas, mengingat bahwa kita diizinkan untuk menyesuaikan antarmuka). Mungkin hanya membuatnya sebagai tantangan kode saja?
Ilmari Karonen
Pertanyaan lain: akankah membuktikan ketidakmungkinan dari program ulet non-sepele dianggap sebagai solusi? (Saya belum memiliki bukti seperti itu, tetapi saya mulai berpikir bahwa mungkin itulah masalahnya.)
Ilmari Karonen
@IlmariKaronen: Bukti ketidakmungkinan akan menjadi raja! Saya telah memposting solusi yang mungkin valid. Lihat diri mu sendiri.
fgrieu

Jawaban:

6

Sementara saya tidak punya solusi atau bukti ketidakmungkinan, saya pikir saya akan memasang test harness saya untuk siapa pun yang ingin bermain-main dengan ini, karena saya sudah cukup banyak menyerah pada saat ini.

Ini merupakan implementasi dari program pemodelan HAL sebagai Haskell monad. Ini memeriksa keuletan dengan melakukan pencarian pertama-lebar atas sesi yang mungkin untuk memeriksa sesi yang 1. telah dihentikan sekali tanpa menghasilkan output yang benar, atau 2. telah menghasilkan output yang bukan awalan dari yang diinginkan (ini juga menangkap program yang menghasilkan keluaran tanpa batas).

{-# 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 ' '

Berikut adalah contoh program yang diberikan oleh OP yang dikonversi ke Haskell.

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

Dan di sini adalah output yang sesuai, menunjukkan bahwa program ini tidak ulet.

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
sumber
4

Kecuali seseorang dapat menemukan bug dalam program ini, saya pikir itu memeriksa dan menolak setiap program dua-cit yang relevan.

Saya berpendapat bahwa cukup untuk mempertimbangkan program yang membaca semua kutipan dan mengaktifkan nomor yang dibentuk oleh set. Setiap cabang switch akan menjadi serangkaian tulisan dan penempatan. Tidak pernah ada titik menempatkan nomor yang sama lebih dari sekali di cabang, atau menempatkan digit output kedua sebelum yang pertama. (Secara moral saya yakin bahwa tidak ada gunanya mengeluarkan digit pertama selain di awal cabang atau digit kedua selain di akhir, tetapi untuk sekarang saya menghindari penyederhanaan itu).

Kemudian setiap cabang memiliki set target cit yang ingin ditetapkan, dan bergerak ke arah itu dengan mengatur bit yang ingin menjadi 0 sebagai 0, dan bit yang ingin menjadi 1 sebagai 0 lalu 1; operasi penulisan ini dapat dipesan dengan berbagai cara. Tidak ada gunanya mengatur sedikit ke 1 kecuali Anda sudah mengaturnya ke 0 dalam menjalankan itu, atau kemungkinan nop.

Itu mempertimbangkan 13680577296 program yang mungkin; butuh mesin 4-inti di bawah 7 jam untuk memeriksa semuanya tanpa menemukan solusi tunggal.

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
sumber
Jika saya menggunakan asumsi saya tentang penempatan output, jumlah program 2-cit turun jauh dan waktu pengecekan kurang dari satu menit, tetapi bahkan dengan asumsi ini jumlah program 3-cit lebih dari 2 ^ 80, atau faktor sekitar 2 ^ 47 lebih dari program 2-cit diperiksa dalam 7 jam. Dengan kata lain tidak cukup kasar.
Peter Taylor
0

Ini adalah upaya terbaik saya untuk menjawab pertanyaan saya sendiri. Saya tidak yakin apakah memenuhi persyaratan 3, dan terbuka untuk sanggahan. Itu tidak ulet :-(

/*  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
sumber
2
Program pengujian saya mengatakan itu tidak ulet: 1. Jalankan program sampai selesai. Output: 01, CITS: 110. 2. Batalkan selama # 15. CITS: 10U. 3. Baca c = 1, batalkan selama # 12. CITS: U0U. 4. Baca c = 0, d = 0dan program akan mencetak 01lagi.
hammar
Maaf, aborsi pertama harus di baris # 11, bukan # 15.
hammar