can a model of computation with infinitely many states be nontrivially decidable?

i'm trying to make a game in which the player faces an infinite (finitely specified) series of enemies and has to specify a strategy that provably defeats all of them (ie defeats enemy n in finite time for all n). i'm intending to do it by having the player describe their strategy in a decidable language, which is then incorporated into a larger program in that decidable language that runs the strategy against each enemy in turn, halting if the player loses. it should then be possible to determine whether that program halts.

if the language is straighforwardly a PDA then this seems like it should work, but my understanding is that a PDA only fails to halt by getting into an infinite loop. i'd like it to be possible for each enemy to be different, say, the nth enemy has n health. but in that case a winning strategy will never loop because each new enemy introduces a never-before-seen state (and also i believe a PDA struggles to represent arbitrarily large numbers, you can have one on the stack as unary or whatever but you can't compare it to others because you lose information about it by reading it? - and the specified strategy is just a fragment of a larger program that may be run repeatedly forever, so it can't read from input, this all has to be on the stack with $$\epsilon$$-transitions). so i'm looking for a model of computation that's nontrivial and decidable but can have a counter that goes up forever.

A one-counter automaton is a finite-state machine that is augmented with a single counter. The finite-state machine can issue a command to increment or decrement the count, or to test whether the counter is zero or not.

The halting problem for one-counter automata is decidable, and there is an efficient algorithm to decide it, by translating the automaton to a PDA. So that might be one option, if it is expressive enough for your needs.

As a rough rule of thumb, in my experience, if you start from such a model and add a little more expressivity, the halting problem quickly becomes undecidable.

Possibly also of interest: Petri nets.

• thankyou! it seems that one-counter automata aren't expressive enough for what i'm doing, but they definitely answer the question. i believe i have found a solution as well - stack automata, which are equivalent to nlogn-bounded TMs. deciding them is slow of course, but for a simple game it looks like it may be okay Feb 8 at 22:43
• @Silver, cool! Perhaps you might like to write an answer to your own question, with some explanation of what stack automata or references for where to learn about them?
– D.W.
Feb 8 at 23:01

If you want a really interesting logic to work with, take a look at Description Logics. They're an astonishingly large fragment of first order logic. They have three major components:

• Individuals - objects to talk about. There can be infinite numbers of individuals. Your fights might be individuals.
• Concepts - concepts are properties that individuals might have. For example, one might have a concept specifying that the player will use a particular tactic. Or there might be a concept indicating that this is a boss fight.
• Roles - Roles connect individuals. You don't have to just have a collection of independent fights. Fights can relate to eachother. Use a tactic too many times, and the boss learns of it and can change their tactics.

There's many description logics. Some are easy to provide proofs. Some are very hard. But they're all decidable. The description logics we study are all decidable logics.

In the Description Logic way of thinking, your user provides an ontology describing what they will do. You, as the developer, provide an ontology describing what the computer will do. Description Logics can naturally be concatenated together, so their concatenation says exactly what will happen. Once you have that, you can ask questions like "Can you prove that the player wins all battles."

I recommend either taking an easy one like $$\mathcal{AL}$$ or a popular one like $$\mathcal{SHION}^{(D)}$$. The simple ones you can code yourself, but the more expressive ones are extremely hard. $$\mathcal{SHION}^{(D)}$$ in particular is extremely difficult, but you can find open source implementations that prove statements in it (e.g. HermiT or Pellet). $$\mathcal{SHION}^{(D)}$$ is decidable in DEXPTIME, which means its incredibly slow in the worst case. But it's an intriguingly powerful language with a lot of extremely intuitive features.

@D.W. gives a good answer to the question as asked which doesn't quite work for my application. the solution i've settled on is to use non-erasing deterministic stack automata.

a stack automaton is a PDA with the additional ability to move up and down the stack in read-only mode, introduced in Ginsberg, Greibach & Harrison (1967) for modelling compilers. Hopcroft & Ullman (1967) proved that a deterministic non-erasing version (ie. pushes to the stack but never pops) is equivalent to an $$nlog_2n$$-bounded turing machine, so about as powerful as you can get while remaining decidable (albeit in exponential time). the proof, incidentally, is lovely - the principle is that although there are infinitely many possible stack configurations, because it can't push while reading down the stack it's effectively a finite automaton for the duration, so there are only finitely many equivalence classes of stack configurations a given machine can distinguish.