Use o NVM para retomar a operação tenazmente sempre que abortado

8

Nós estaremos tentando escrever um programa que se lembre do que está fazendo até agora e continue em direção ao seu objetivo, se abortado uma repetição. Este é um programa tenaz . Ele estará usando uma memória não volátil para armazenar informações entre as execuções, como um número de cits , que são bits, levando em consideração o que acontece no cancelamento. Certa vez, conjeturei que, com N cits , qualquer objetivo até o comprimento 2 (NK) é possível, para alguns pequenos K. fixos. Agora, estou inclinado a pensar que o objetivo não pode ser alcançado :-(

É solicitado um programa tenaz com objetivo 01 , que já é um objetivo não trivial ; ou uma prova rigorosa de impossibilidade.

Um programa tenaz é definido como aquele que:

  1. Sempre que executado , é executado a partir do mesmo ponto de entrada, sem entrada e pode compartilhar informações entre execuções exclusivamente por meio de N cits (definidos abaixo); todas as outras informações têm o mesmo conteúdo no início de cada execução, conteúdo imprevisível no início da execução, são imutáveis ​​(o próprio programa) ou ilegíveis ( saída e valor anteriores ).
  2. É tal que, quando executado dentro de uma sessão, ele detém (usando um recurso de seu idioma), dentro de algum atraso desde o início da execução, a menos que seja interrompido antes da interrupção; O cancelamento ocorre em qualquer instante arbitrário e impede a operação até outra execução (se houver).
  3. É tal que a concatenação em ordem cronológica dos caracteres que produz é a mesma sequência finita (o objetivo ) em qualquer sessão de arbitrariamente várias execuções compreendendo pelo menos uma execução em que o programa foi deixado em execução até parar.
  4. Emite caracteres usando um dispositivo que atomicamente : recebe um valor entre 0 1 2 3 colocado pelo programa e gera0(resp.1) Valores entre 0 ou 2 (resp 1 ou 3) se e somente se esse valor for diferente do anterior valor put, assumido como 0 para o primeiro put em uma sessão.

Existem programas tenazes! Qualquer programa que simplesmente coloque um número fixo de vezes que um valor fixo válido e, em seguida, pare, é tenaz com a meta vazia (se o número ou o valor for 0), 0(se o número for positivo e o valor for 2) ou 1(caso contrário). Qualquer objetivo mais longo requer NVM.

Cada cit modela um bit NVM, levando em consideração o efeito de uma execução interrompida durante uma gravação no cit. A qualquer instante, um cit está em um dos três estados possíveis 0 1ou U. O valor lido de um cit é sempre 0 ou 1; também corresponde ao estado, a menos que U. Um cit é inicializado para declarar 0antes da primeira execução em uma sessão e, de outra forma, muda de estado apenas quando uma gravação é comandada pelo programa, com efeito dependendo do que está gravado, se a execução é interrompida durante a gravação ou não e da antigo estado de 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

O HAL para o acima mencionado é declarado em C como:

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

Nossa primeira tentativa de um programa tenaz com a meta 01é:

#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 faz uma primeira sessão, deixa a primeira corrida parada e termina a sessão; a saída da sessão é a saída da execução única 01; Por enquanto, tudo bem.
Em outra sessão, Murphy aborta uma primeira corrida durante w(3,1), deixando cit no estado U; em uma segunda execução, Murphy decide que r(3)é 1 (que cit está no estado U) e deixa o programa em execução (observe como w(3,1)não mudou o estado do cit); na terceira execução, Murphy decide que r(3)é 0, aborta depois p(2)e termina a sessão.
A saída concatenada da segunda sessão é 010(um caractere por execução), mas é diferente da 01primeira sessão, portanto, o programa não é tenaz, pois a condição 3 não é atendida.


O idioma é gratuito, adapte a interface C de acordo com o idioma. Selecionarei a melhor resposta com base no menor número de cits usados; o menor número de gravações no pior caso da execução para a saída (ou interromper se não houver saída); depois, o menor número de gravações antes de parar em uma sessão sem interrupção; programa mais curto. Conte apenas o código de chamada, não a interface ou sua implementação, que não é necessária. Uma prova rigorosa de impossibilidade eliminaria qualquer programa (e seria uma surpresa para mim) ; Eu selecionaria o mais simples de entender.

Verifique três vezes se o programa realmente cumpre a meta de acordo com 3, independentemente do número e instantes de abortos; isso é difícil!

Atualização: adicionei uma resposta de candidato . Sinta-se livre para rejeitar isso. Oh, hammar fez isso em minutos usando um programa sistemático!

Status : Até agora não temos solução; saiba com certeza que não há solução com 1 ou 2 cits; mas não há provas de impossibilidade com 3 ou mais citações. A declaração não foi encontrada ambígua. O problema teria uma solução se alterássemos ligeiramente a matriz cit (por exemplo, coloque 1 no canto inferior direito, caso em que o exemplo acima está correto).

fgrieu
fonte
Sinto que uma pergunta semelhante foi feita - talvez relacionada a mais memória flash / surtos de energia, eu acho -, mas não consigo encontrá-la.
Gaffi
1
@ Gaffi: Eu fiz uma pergunta há duas semanas, solicitando a um programa com propriedades semelhantes decimais de Pi-3 em binário até o comprimento máximo possível, dado um número de cits e outras coisas, redigidas com corte de energia em vez de abortar . Foi recebido com críticas (positivas) perguntando como alguém determinaria respostas válidas. Percebi que provavelmente não podia, e tirei a pergunta. Com esse código de golfe meticulosamente redigido, estou confiante de que posso verificar o programa, ou publicar um mais curto e tenaz, em muitos idiomas. Meu único arrependimento é que eu deveria ter feito o gol um pouco mais sexy.
precisa saber é
1
Tem certeza de que deseja que isso seja código de golfe? Parece-me que o desafio está em escrever um programa desse tipo (e provar sua correção); uma vez realizado, o golfe se torna um exercício bastante trivial (e um pouco mal definido, já que podemos adaptar a interface). Talvez seja apenas um desafio ao código ?
Ilmari Karonen
Outra pergunta: provar a impossibilidade de programas tenazes não triviais contaria como solução? (Eu não tenho essa prova ainda, mas eu estou começando a pensar que pode ser o caso.)
Ilmari Karonen
@IlmariKaronen: Prova de impossibilidade seria rei! Publiquei uma solução que pode ser válida. Veja por si mesmo.
fgrieu

Respostas:

6

Embora eu não tenha uma solução nem uma prova de impossibilidade, achei que publicaria meu equipamento de teste para quem quisesse brincar com isso, pois já desisti nesse momento.

É uma implementação dos programas de modelagem HAL como uma mônada de Haskell. Ele verifica a tenacidade fazendo uma pesquisa abrangente das sessões possíveis para verificar as sessões que 1. pararam uma vez sem produzir a saída correta ou 2. produziram uma saída que não é um prefixo da desejada ( também captura programas que produzem resultados infinitos).

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

Aqui está o programa de exemplo fornecido pelo OP convertido em 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

E aqui está a saída correspondente, mostrando que o programa não é tenaz.

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

A menos que alguém possa encontrar um erro neste programa, acho que ele verifica e rejeita todos os programas relevantes de duas citações.

Argumento que basta considerar programas que leem todos os cits e ligam um número formado pelo conjunto. Cada ramo do comutador será uma série de gravações e colocações. Nunca há sentido colocar o mesmo número mais de uma vez em uma ramificação ou colocar o segundo dígito de saída antes do primeiro. (Estou moralmente certo de que não há sentido em emitir o primeiro dígito, exceto no início de uma ramificação ou o segundo dígito, exceto no final, mas por enquanto estou evitando essa simplificação).

Então, cada ramificação tem um conjunto de cits de destino que deseja definir e se move em direção a ela, definindo os bits que deseja que sejam 0 como 0 e os bits que deseja que sejam 1 como 0 e 1; essas operações de gravação podem ser ordenadas de várias maneiras. Não há nenhum ponto em definir um pouco para 1, a menos que você já o tenha definido como 0 nessa execução, ou provavelmente é um nop.

Considera 13680577296 programas possíveis; uma máquina de quatro núcleos demorou menos de 7 horas para verificá-las sem encontrar uma solução única.

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
fonte
Se eu usar minha suposição sobre o posicionamento das saídas, o número de programas de 2 cit diminui consideravelmente e o tempo de verificação é menor que um minuto, mas mesmo com essa suposição, o número de programas de 3 cit é superior a 2 ^ 80, ou um fator de cerca de 2 ^ 47 a mais do que os programas de 2 cit registrados em 7 horas. Não é razoavelmente brutal, em outras palavras.
Peter Taylor
0

Esta é a minha melhor tentativa de responder a minha própria pergunta. Não tenho certeza de que atende ao requisito 3 e estou aberto a refutação. Não é tenaz :-(

/*  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
fonte
2
Meu programa de teste diz que isso não é tenaz: 1. Execute o programa até a conclusão. Saída: 01, Cits: 110. 2. Abortar durante o # 15. CITS: 10U. 3. Leia c = 1, aborte durante o # 12. CITS: U0U. 4. Leia c = 0, d = 0eo programa irá imprimir 01novamente.
hammar
Desculpe, o primeiro aborto deve estar na linha 11, não 15.
hammar