Sử dụng NVM để tiếp tục hoạt động mạnh mẽ bất cứ khi nào bị hủy bỏ


8

Chúng tôi sẽ cố gắng viết một chương trình ghi nhớ những gì nó đã làm cho đến nay và tiếp tục hướng tới mục tiêu của nó nếu bị hủy bỏ chạy lại. Đây là một chương trình ngoan cường . Nó sẽ sử dụng Bộ nhớ không biến động để lưu trữ thông tin qua các lần chạy, như một số cits , là các bit có tài khoản về những gì xảy ra khi hủy bỏ. Tôi đã từng phỏng đoán rằng với N cits , bất kỳ mục tiêu nào dài đến 2 (NK) đều có thể đạt được, đối với một số cố định nhỏ K. Bây giờ tôi đang nghiêng về suy nghĩ mục tiêu không thể đạt được :-(

Nó được yêu cầu một chương trình ngoan cường với mục tiêu 01 , đó đã là một mục tiêu không tầm thường ; hoặc một bằng chứng nghiêm ngặt về sự bất khả thi.

Một chương trình ngoan cường được định nghĩa là một chương trình:

  1. Bất cứ khi nào chạy , thực thi bắt đầu từ cùng một điểm nhập cảnh, không có đầu vào và có thể chia sẻ thông tin qua các lần chạy độc quyền bằng phương tiện của N cits (được xác định bên dưới); mọi thông tin khác đều có cùng một nội dung khi bắt đầu mỗi lần chạy, có nội dung không thể đoán trước khi bắt đầu chạy, không thể thay đổi (chính chương trình) hoặc không thể đọc được ( đầu ragiá trị trước đó ).
  2. Có phải là khi chạy trong một phiên, nó có thể dừng lại một cách rõ rệt (sử dụng một tính năng của ngôn ngữ của nó), trong một số độ trễ bị ràng buộc kể từ khi bắt đầu chạy, trừ khi bị hủy bỏ trước khi tạm dừng; hủy bỏ xảy ra bất kỳ lúc nào tùy ý và ngăn hoạt động cho đến khi chạy khác (nếu có).
  3. Có phải là sự kết hợp theo thứ tự thời gian của các ký tự mà nó tạo ra là cùng một chuỗi hữu hạn ( mục tiêu ) trong bất kỳ phiên phân xử tùy ý nào, bao gồm ít nhất một lần chạy mà chương trình bị bỏ chạy cho đến khi dừng.
  4. Kết quả đầu ra ký tự sử dụng một thiết bị nguyên tử : nhận được một giá trị giữa 0 1 2 3 đặt bởi chương trình, và kết quả đầu ra0(resp.1) Cho các giá trị trong 0 hoặc 2 (resp 1 hoặc 3) khi và chỉ khi giá trị đó là khác biệt so với trước đây giá trị đặt, giả sử là 0 cho lần đặt đầu tiên trong phiên.

Chương trình ngoan cường tồn tại! Bất kỳ chương trình nào chỉ đơn giản đặt một số lần cố định một giá trị cố định hợp lệ, sau đó tạm dừng, sẽ kiên trì với mục tiêu là trống (nếu số hoặc giá trị là 0), 0(nếu số là dương và giá trị là 2) hoặc 1(nếu không). Bất kỳ mục tiêu dài hơn yêu cầu NVM.

Mỗi cit mô hình một bit NVM với tài khoản cho hiệu ứng của một lần chạy bị hủy bỏ trong khi ghi vào cit. Tại bất kỳ thời điểm nào, một cit là ở một trong ba trạng thái có thể 0 1hoặc U. Giá trị đọc từ một cit luôn là 0 hoặc 1; nó cũng phù hợp với nhà nước trừ khi U. Một cit được khởi tạo để trạng thái 0trước khi chạy lần đầu tiên trong một phiên và nếu không thì chỉ thay đổi trạng thái khi một lệnh ghi vào nó được lệnh bởi chương trình, có hiệu lực tùy thuộc vào những gì được viết, liệu lần chạy đó có bị hủy bỏ trong quá trình ghi hay không và từ tiểu bang cũ của 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

Các HAL cho trên được khai báo trong C như sau:

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

Nỗ lực đầu tiên của chúng tôi tại một chương trình ngoan cường với mục tiêu 01là:

#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 thực hiện một phiên đầu tiên, khiến cuộc chạy đầu tiên tạm dừng và kết thúc phiên; đầu ra của phiên là đầu ra của một lần chạy 01; càng xa càng tốt.
Trong một phiên khác, Murphy hủy bỏ lần chạy đầu tiên trong khi w(3,1)để lại trạng thái U; trong lần chạy thứ hai, Murphy quyết định đó r(3)là 1 (cit đang ở trạng thái U) và khiến chương trình bị dừng (chú ý cách w(3,1)không thay đổi trạng thái của cit); trong lần chạy thứ ba, Murphy quyết định r(3)là 0, hủy bỏ sau đó p(2)và kết thúc phiên.
Đầu ra được nối của phiên thứ hai là 010(một ký tự cho mỗi lần chạy) nhưng khác với 01phiên đầu tiên, do đó chương trình không ngoan cường, vì điều kiện 3 không được đáp ứng.


Ngôn ngữ là miễn phí, điều chỉnh giao diện C phù hợp với ngôn ngữ. Tôi sẽ chọn câu trả lời tốt nhất dựa trên số lượng trích dẫn thấp nhất được sử dụng; sau đó số trường hợp ghi thấp nhất từ ​​trường hợp chạy đến đầu ra (hoặc tạm dừng nếu không có đầu ra); sau đó số lần ghi thấp nhất trước khi tạm dừng trong một phiên không hủy bỏ; sau đó chương trình ngắn nhất. Chỉ đếm mã cuộc gọi, không phải giao diện hoặc cách thực hiện, không cần thiết. Một bằng chứng nghiêm ngặt về sự bất khả thi sẽ loại bỏ bất kỳ chương trình nào (và gây ngạc nhiên cho tôi) ; Tôi sẽ chọn đơn giản nhất để nắm bắt.

Vui lòng kiểm tra kỹ xem chương trình có thực sự đạt được mục tiêu theo 3 hay không, bất kể số lượng và nội dung của việc hủy bỏ; thật khó!

Cập nhật: Tôi đã thêm một câu trả lời ứng cử viên . Hãy thoải mái để đánh bại nó. Oh, hammar đã làm điều đó trong vài phút bằng một chương trình có hệ thống!

Tình trạng : Cho đến nay chúng tôi không có giải pháp; biết chắc chắn rằng không có giải pháp nào với 1 hoặc 2 cits; nhưng không có bằng chứng về sự bất khả thi với 3 cits trở lên. Tuyên bố chưa được tìm thấy mơ hồ. Vấn đề sẽ có một giải pháp nếu chúng ta thay đổi ma trận cit một chút (ví dụ: đặt ở 1 ở dưới cùng bên phải, trong trường hợp ví dụ trên là chính xác).


Tôi cảm thấy như một câu hỏi tương tự đã được hỏi - có lẽ liên quan nhiều hơn đến bộ nhớ flash / sức mạnh tăng vọt, tôi nghĩ - nhưng dường như tôi không thể tìm thấy nó.
Gaffi

1
@Gaffi: Tôi đã đặt câu hỏi hai tuần trước khi hỏi một chương trình có các thuộc tính tương tự cho số thập phân của Pi-3 ở độ dài tối đa có thể được cung cấp cho một số cits và các nội dung khác, được cắt bằng điện thay vì hủy bỏ . Nó đã gặp phải sự chỉ trích (tích cực) hỏi làm thế nào người ta sẽ xác định câu trả lời hợp lệ. Tôi nhận ra rằng có khả năng tôi không thể, và loại bỏ câu hỏi. Với môn đánh gôn được diễn đạt tỉ mỉ này, tôi tự tin rằng mình có thể kiểm tra chương trình, hoặc đăng một bài ngắn hơn, cho nhiều ngôn ngữ. Điều hối tiếc duy nhất của tôi là tôi nên làm cho mục tiêu trở nên gợi cảm hơn.
fgrieu

1
Bạn có chắc chắn muốn điều này là mã golf? Dường như với tôi rằng thách thức là viết một chương trình như vậy (và chứng minh tính đúng đắn của nó); một khi đã hoàn thành, chơi golf nó sẽ trở thành một bài tập khá tầm thường (và hơi khó hiểu, do chúng ta được phép điều chỉnh giao diện). Có lẽ chỉ cần làm cho nó thách thức mã thay thế?
Ilmari Karonen

Một câu hỏi khác: sẽ chứng minh sự bất khả thi của các chương trình ngoan cường không tầm thường được tính là một giải pháp? (Tôi chưa có bằng chứng như vậy, nhưng tôi bắt đầu nghĩ rằng đó có thể là trường hợp.)
Ilmari Karonen

@IlmariKaronen: Bằng chứng về sự bất khả thi sẽ là vua! Tôi đã đăng một giải pháp có thể hợp lệ. Xem cho chính mình.
fgrieu

Câu trả lời:


6

Mặc dù tôi không có giải pháp cũng như bằng chứng về sự bất khả thi, tôi đã hình dung rằng tôi sẽ đăng bài kiểm tra của mình cho bất kỳ ai muốn chơi với điều này, vì tôi đã bỏ cuộc khá nhiều vào thời điểm này.

Đây là một triển khai của các chương trình mô hình hóa HAL với tư cách là một đơn vị Haskell. Nó kiểm tra độ bền bằng cách thực hiện tìm kiếm theo chiều rộng qua các phiên có thể để kiểm tra các phiên mà 1. đã dừng một lần mà không tạo ra đầu ra chính xác hoặc 2. đã tạo ra một đầu ra không phải là tiền tố của một phiên mong muốn (điều này cũng bắt các chương trình sản xuất đầu ra vô hạn).

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

Dưới đây là chương trình ví dụ được đưa ra bởi OP được chuyển đổi thành 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

Và đây là đầu ra tương ứng, cho thấy chương trình không ngoan cường.

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)]
==============================================================================

4

Trừ khi ai đó có thể tìm thấy một lỗi trong chương trình này, tôi nghĩ rằng nó sẽ kiểm tra và từ chối mọi chương trình hai thành phần có liên quan.

Tôi lập luận rằng nó đủ để xem xét các chương trình đọc tất cả các cits và bật một số được hình thành bởi tập hợp. Mỗi nhánh của công tắc sẽ là một chuỗi các ghi và đặt. Không bao giờ có bất kỳ điểm nào đặt cùng một số nhiều hơn một lần trong một nhánh hoặc đặt chữ số đầu ra thứ hai trước số thứ nhất. (Tôi chắc chắn về mặt đạo đức rằng không có điểm nào xuất ra chữ số đầu tiên ngoài đầu chữ số hoặc chữ số thứ hai khác ở cuối, nhưng hiện tại tôi đang tránh sự đơn giản hóa đó).

Sau đó, mỗi nhánh có một tập hợp các cits mà nó muốn đặt và di chuyển về phía nó bằng cách đặt các bit mà nó muốn là 0 là 0 và các bit mà nó muốn là 1 là 0 rồi 1; các hoạt động viết này có thể được đặt hàng theo nhiều cách khác nhau. Không có điểm nào thiết lập một chút thành 1 trừ khi bạn đã đặt nó thành 0 trong lần chạy đó, hoặc đó có thể là một nop.

Nó xem xét 13680577296 chương trình có thể; phải mất một máy 4 lõi chỉ dưới 7 giờ để kiểm tra tất cả mà không tìm thấy một giải pháp duy nhất.

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);
        }
    }
}

Nếu tôi sử dụng giả định của mình về vị trí đầu ra, số lượng chương trình 2-cit giảm đáng kể và thời gian kiểm tra ít hơn một phút, nhưng ngay cả với giả định này, số lượng chương trình 3-cit là hơn 2 ^ 80, hoặc một hệ số khoảng 2 ^ 47 nhiều hơn các chương trình 2-cit được kiểm tra trong 7 giờ. Nói cách khác, không phải là vũ phu, nói cách khác.
Peter Taylor

0

Đây nỗ lực tốt nhất của tôi để trả lời câu hỏi của riêng tôi. Tôi không chắc chắn rằng nó đáp ứng yêu cầu 3, và sẵn sàng để bác bỏ. Nó không ngoan cường :-(

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

2
Chương trình thử nghiệm của tôi nói rằng điều đó không ngoan cường: 1. Chạy chương trình để hoàn thành. Đầu ra : 01, Cits : 110. 2. Hủy bỏ trong thời gian # 15. Trích dẫn : 10U. 3. Đọc c = 1, hủy bỏ trong thời gian # 12. Trích dẫn : U0U. 4. Đọc c = 0, d = 0và chương trình sẽ in 01lại.
hammar

Xin lỗi, lần hủy bỏ đầu tiên phải ở dòng # 11, không phải số 15.
hammar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.