 I'd like to thank the organizers, especially Krishna, for inviting me. So I'm at this age where you start your talks with a motto. So this is a quote from Dana Scott, which says that transducers are better than automata. It's kind of funny because if you go through the old automata literature, there is like a cut-off point around 1950-something, where it starts to become understandable what they're saying. And before they talk about nerve nets and sequential circuits, it's very hard. And then there's actually the Rabin-Scott paper, for which they got the Turing Award, and suddenly it's clear. It could have been published last year. And the first thing that they do in the paper, they say, oh, there's this automata, they're interesting, but the people they study, you know, there's these output functions, this is so complicated, let's simplify the model and make it yes-no. So actually the person who, so this is like Dana Scott, who went from transducers, they started out with transducers, then they went to automata, then Dana Scott says let's come back to transducers, I don't know, and now again we're in transducer territory today. And clearly I agree with this statement, and the reason is that, I think I've said it many times before, but that there's one nice thing that you can do with functions that you can't do with languages, and that is composing them. And that's very useful, which really helps with the theory. So in this presentation I have several slides about simpler models, which have also been surveyed by Gabriele, so I'll try to go over that rather quickly. So I begin with the smallest class of functions, which is the rational functions, these are unambiguous, so there exists exactly one accepting run, or at most one accepting run if you want a partial function, automata that are non-nidermalistic and yet unambiguous, which have output and transitions. So for example you take the union of these two automata, because it's a union of two things, because it has to say two initial states, it's an unambiguous automaton. I think this is, there's a mistake in the letters, so don't read the letters. It's meant to show that there's circles and arrows, that's the whole point of this slide. So that's a very nice, well-behaved class of string-to-string functions, and its niceness can be seen in the fact that it has several different characterizations, but let's ignore that. That's a very small class. And now a bigger class, and this is the one that was discussed in much more detail by Gabriele and also by Luc, it's called regular, so it can be described in terms of two-way deterministic finite automata with output, and this is a beautiful model. Everybody sees the name, everybody understands what it does. And this, I think it appears for the first time in the Shephardtson paper, where he makes a note where he says, although two-way deterministic finite automata in this paper are used to accept or reject, they can also produce outputs. So that's a very old model. But it's equivalent to these streaming, so to MSL transductions. So this was all, you mentioned MSL transductions. You said you will not mention them. So the idea is to describe the output string in terms of the input string by means of logic. Something like positions of the output string are the even-numbered positions of the input string, and they're ordered in the opposite way with respect to the order that they have in the input string. And then you give logical formulas which describe that. The logic that you use is MSO because this is the logic automata people use. And then you get a function which describes the output string by using the language of logic in terms of the input string. I mean, of course, one has to give the proper definition. And these two models are equivalent to a very nice result of Engelfried and Hoheobom, but I think it dates back to slightly earlier work by Engelfried with Blum. And then there's the streaming string trans... It's very hard to pronounce. It's like, I don't know why. Streaming string transducers by Alur and Czerny. This is a very influential model. So it's a one-way model. That's why it's called streaming. It inputs a string. It goes one way. It has a finite state control. And it has registers which store pieces of the output string. And then it concatenates them, and in the end, in a designated register, you find the output string. And this model is equivalent. And then there's another line of research, which was initiated by Alur, Freyli, and Ragotaman, which is... it's like regular expressions. And the idea is that you start with simple transducers, and then it's like a regular expression. You start with, like, one-letter languages, and then you combine them using union, concatenation, and Czerny star. So the idea is similar here, although the list of combinators is longer. And... but you can do that. And so together with, maybe, with Krishna and Lohdavio, we had an alternative approach to these combinators. So let me try to explain that to you by trying to code it live. So this is my implementation of the programming language. It's called the Haskell interpreter. And let's try to write some basic functions. For example, let's try to write the function, which... that's a bit strange, which doubles the string. In Haskell, you would write it like this. Okay? So I duplicate the string. But in the language that we designed with Krishna, the plus-plus is not a thing. Although it could be, because it's definable, as I will show to you right now. But just as an exercise, let's try to get this thing. So before we get string duplication, let's consider the following function, which maps something to a singlet on this. So like it maps a letter to a one-letter list. Okay? This is, again, not a primitive function. So I'll have to program it. But it is not so hard, because what I will do is consider the following function. It inputs... I pair two functions. So maybe it's easier to see it on an example. What I did here is I have a function which inputs an argument, and then I apply two functions to it. The identity function and the constant empty list function. And I pair the results. Okay? Is it clear? So that's... I get a function which does this. And now what I can do is I take the prepend function, and I... This is function composition in Haskell. So the prepend function, it inputs... Well, it's insert an element... It takes an element and a list, and it adds that element to the beginning of the list. So prepend is one of the atomic functions. One of the programming language says you can compose functions. So if you have two already defined functions, then you can compose them. If you have two already defined functions, you can pair them. One of the atomic functions is the identity functions. I mean, it's hard to argue with that as a... as a building block. Actually, you could argue with it, because it can be derived from the others, but it's not very important. Another thing here is any constant function is fine. Okay? For example, the constant empty list function. And now that we have that, let's... My goal is to define the function f3, which goes to... which does this. Again, I'm not allowed to do this, but I need to derive it. So how do I derive that? I guess I should go something like... No, no, sorry. It should have been f1. I sort of read it the same argument, except instead of this, I had the singleton list function that I had before. So as a result, I input an element, and I map it to this. And now if I take f4 equals prepend composed with f3, I should get what I want, almost what I want. Well, I get f3, at least. That should have been f3, actually. I get this function because... Let's apply it to, say, 2. I get this. And now I'm almost done with duplication because what I can do is now I can... You see, what is f4? It's a function which inputs something and outputs a list that contains that something twice. It's actually a family of functions, depending on the type of the input. And the type of the input does not necessarily need to be a finite alphabet. It could be, for example, lists. And I will use that, actually, because, for example, what I could do is I could apply a 4 to a list, like 1, 2, 3. Okay? So my duplication function is actually going to be... And I get almost what I want, but I get a list of lists, and now I can apply a primitive of Haskell, which is list concatenation, compose that with a 4. Sorry, it's just hard to avoid if you're Polish to make some spelling mistakes. And then we have what we want. Okay? So the idea behind this programming language is that you have certain functions that you begin with, very basic primitive functions, like list concatenation, prepending an element to a list, pairing functions... Well, pairing is not a function. The identity. And then you have certain ways of combining existing functions, such as pairing functions, composing functions. And then you have this kind of programming language. So that's what we did. So we proved that the regular functions are exactly the compositions... Oh, let's forget that. Or exactly, this is not what it's supposed to say, are exactly that programming language. So there's a nice programming language perspective, and we will see that continue in the next slides. Okay? So the class of regular functions is very well behaved. So one thing it does is that if you apply a regular function and then you have a finite automaton on the output, which says yes or no, then you can create a new finite automaton which runs directly on the input and gives you the right answer. So that's some people call this continuity. They're closed under composition, which is kind of obvious, say, combinators because they have composition as a basic building block. For other models, it's less obvious. So either it's a result or it follows from equivalence with the other models. But for, for example, Femme is so transparent, so it's not obvious. There can be a value in linear time. It's most obvious maybe with a two-way deterministic automaton. Just run it and it takes linear time. And equivalence is decidable, which is what was mentioned by Gabriel. Okay? And then actually, so this is a bigger class than that. It's maybe not clear, but it was already discussed by Luc and Gabrielle before. So this class generalizes this one. So you could imagine, consider the decision problem where you're given a function from here and might ask if it's here and this is also decided. Okay? So that's the picture so far. And in my talk, I want to discuss a third class of functions, which I call the polyregular functions. So the polyregular functions, as the name implies, they're supposed to have something to do with polynomials. And these functions, they have linear output size. Because if you, for example, run a deterministic two-way automaton, then it can visit every position, if it has five states, then it can visit every position at most five times because if it visits it six times, then some state will be duplicated, seen twice, and it will enter an infinite loop. So two-way deterministic two-way automaton, if it has n states, then it will visit every position at most n times. So, well, n is a bad choice of thing. So the output size is at most number of input positions times number of states. So that's linear, assuming a fixed number of states. It's easy to see for the others. So they are linear functions in this sense. And actually, there seems to be a connection with linear logic because if, for example, the register automata, they have something called a single-use restriction, which means that you can use your, some arguments exactly once, and this is the founding principle of linear logic, apart from having linear output size, which is also coincidental. But there are results about this that are starting to appear now. So now this is a class of functions that I want to present in the talk right now, which is the Polaroid regular functions, and they will have a quadratic output growth, for example. But apart from that, they will behave just as well as the other model. In particular, they will have a lot of equivalent characterizations. So maybe I begin. So my running example is going to be the following function. You input a string, and then you output all of the prefixes of that string, but each one in reverse order, just to have some features in this function. And I will give you four or five different models, which I would say are different. Like, you don't see that they're the same, but they are the same. Okay, so the first one is a model that's existed for quite some time, which is Pebble Transducers. So a Pebble Transducer is like a two-way automaton, except it has Pebbles, which it can place on the input to mark positions so that when it visits them later on, it remembers, oh, I visited that position previously. And this model was introduced by Globerman and Kraler, Kraler as Yes, No, Automata, and as transducers by Milo Sucumdian. But there is a very important restriction, which is called stack discipline. And that means that there's a main Pebble, if there's two Pebbles, for example. There's a main Pebble, and there's a secondary Pebble. And if you want to move the main Pebble, you need to take away the secondary Pebble. Okay? So generally speaking, the Pebbles are organized in a stack, and you're only allowed to move the topmost Pebble on the stack. The others have to remain fixed. If you want to move a Pebble, you need to pop the entire stack above it. If you don't have that restriction, the model is equivalent to lock space and has no finite automata properties whatsoever. So if you want to do... So here's a visual representation of this function that gives you all prefixes in reverse order. So what you do is you have the main Pebble. It sort of ranges over the all-possible prefixes. So it tries the prefix of length one, then the prefix of length two, then the prefix of length three, then the prefix of length four, and so on. And then for each prefix, it outputs that prefix but in reverse order, so it launches the second Pebble. And what you see, while the sub-Pebble moves, the main Pebble doesn't move. That's the stack discipline. And if you don't have, as I said, if you don't have stack discipline, this gives you exactly lock space and some odd results. The model without stack discipline, it's not an automaton model. It's outside the scope of automaton here. Okay, so that's one model which existed before, and let's define the poly-regular functions to be the functions computed by Pebble Automata. But the whole point of having two different names, something like this more general name, is that there's other models which are equivalent. So let me describe the second one, which this model and all the later ones are new, which I would call for transducers, and I think it's a super simple model. Here's an example. It's a Python program. So for every position in the input string, in left to right order, then for every position in the input string from right to left order, I'm going to do this function from, you know, I might be lazy about the separators. So you have the main position, which roughly ranges over the places where the separator is going to be. And then you start moving backwards, and then you only start producing output if you're before Y, and because it's in right to left order, this is in the opposite order. So the feature, oh, I even have a separator. Great. So you have almost all of the features of a forward transducer here. So you have position variables, which range over positions in the input string, and you're only allowed to just range over them in a loop which goes first to last or last to first. You're not allowed to go like this. This is not allowed, which is something you typically want to do in a two-way automaton. You cannot do that. Okay? So there's one more feature that's missing here, which is Boolean variables. And you're allowed to ask questions how they're ordered. You're allowed to ask questions what is the label of this position in the input string, and then you're allowed to output something. The one more feature which is missing here is Boolean variables, so you can have a Boolean variable, and then you can write something like this, or maybe if a, then a. So Boolean variables, which have various true and false. So that's the entire content of four programs. So for example, how would you compute a one-way letter-to-letter transducer? Or maybe even how would you compute an automaton? So it just says yes or no. So it outputs yes or no at the end of the input string, depending on whether or not some regular property is satisfied. What you would do is you would have one loop which goes left to right, and you would use the Boolean variables to store the state of the automaton. So you'd have log Q states, Boolean variables, and you would just update it as you go along. That's one thing you could do. It's much less clear how would you directly, how would you simulate a two-way automaton, but it turns out you can. So what you have here is that this model is sort of like this. If you think about it, maybe let me come back here. It's kind of clear to see that it's a special case of a Pebble transducer. This is the main Pebble, this is the secondary Pebble, and you know it could have 100 Pebbles, but they're nested, which is a feature of a programming language. So it's easy to see that this is a special case of a Pebble transducer, the Boolean variables you store in your state. But as it will turn out, this is the same thing as that. So to convert from here to here, that requires some ideas, but it's true. So it sort of says that, even if you start with a one Pebble transducer, which is the same thing as a two-way automaton, how do you go from a two-way automaton here? That's not completely obvious, but it turns out that, even though they seem to be turning a lot to a transducer, that's not really the case. They don't reverse too much in a certain sense, which is made formal by the equivalence of these models. So now there's a third model, which is a functional programming language. So instead of giving you the slide, I'll just give you some examples in Haskell. So we have these programs here. There was an important programming feature that was not used, which is binding variables. So the previous formalism was variable-free. This is known as combinatorial logic, more of a combinatorial programming language. And they're nice because they have a very small number of primitives, and they don't have variables, but it's a nightmare to work with it. There's a reason why nobody uses, I guess nobody uses combinatorial programming languages in industry. So what we're going to do now is we're going to say, let's add variables, as you would do in a function. So for example, this is okay now. We're allowed to bind a variable and write a function which uses it. Here's another one. Let's try to do a squaring function. So I want the function that if it inputs 1, 2, 3, then the output is going to be 1, 2, 3. Oops, sorry, I pressed the wrong key. I want a squaring function which inputs a string and I'll write that string, it replaces every letter in the string by that string itself. So the squaring function is going to be what? It's you input a string and then you map every position y in that string by the string itself. And once you do that, then I think you need to concatenate them because you get a list of lists and now you want to have this. Oops. And I think, okay, let me be a bit more... made a mistake somewhere. Okay, let me go slower. Okay, so let's... f1 is going to be... I input a string and then I map that string by the function which replace everything by x. And this. That's at least compiled. Square is equal to concatenation. Okay, so that works. Okay. So now, just by adding lambdas, you get to have... even though our primitives were linear sized functions, one of the primitives is the map function. It's also a primitive of the previous linear programming language so it preserves linearity somehow. If you input a list and then you map a linear function to every distellament, then the entire thing is also going to have linear growth. However, by virtue of having lambda abstraction, you create nonlinear things like quadratic things here. So it turns out that lambda abstraction, well, it didn't turn out yesterday, is very useful. It's also called programming and, well, at least functional programming. But it allows you to have a much more pleasant programming language. And it turns out that if you want to get the poly-regular functions, all you need to add is... you start with the previous function, so the basic ones like map, pair, and prepend and stuff like that. And the only things you need to add is lambda abstraction like here and one more thing which is, like, is split. So what does this do? It's almost like squaring, but it's a little bit more powerful. So you split a list into every possible... you split it into two pieces so that initially the first piece contains the entire list and then the second piece contains nothing. Then the first piece starts to contain progressively less and less and the second piece has progressively more and more. And once you have that, then you can do all sorts of things. So here I should maybe... I don't have too much time, so... but I'll try anyway. I'll try to give you reverse as a result of that, which is how do you do it? We're going to go like this. We have this list and then we're going to map the second coordinate to every element. Okay? And now the idea would be to map head to take the head of every list and concatenate the result. This is almost true, but it wouldn't work because I used a special version of head. If I used the usual head, then I would get an empty list exception. But I used a special version of head and this is actually the version of head in the programming language, which has the output type is a disjoint union that's left or right. So it's either an error element for empty lists or an actual element of the list. And then you continue a little bit and you can eliminate their element and keep just three to one and then you get the reverse of the list. So this, as opposed to the combinators, this is quite an enjoyable functional programming language and you can program in it without observing that it's not touring complete programming language. And why is it not touring complete? The reason is that when we define functions, we're not allowed to have recursion. So it's not okay to write a function which says, like many functions you would do, you write factorial of x equals blah, blah, blah, and then you use factorial of x minus one in the body of it. That's not allowed. So these are non-recursive functions. And so then I will skip over the lambda terms because we discussed this. It turns out that this functional programming language is equivalent to the first. And there's another characterization which is maybe like assembly language which says whether the simplest functions that you need to generate everything. So it's kind of also in the spirit of this except that here is what basic primitives do you need in the presence of the lambda calculus while here it's going to be what primitive string to string functions do you need in the presence of composition and composition on. So let's have a look at our running example. I input one, two, three, four. Then I could first append an N marker. That's a very simple-minded function. Then I could apply squaring. So this is a special version of squaring which writes the list as many times, replaces each position by the list except that there's this red color here which means that you indicate which element is coming. This is one of the primitive functions. And then what you do is that for every block you keep only the prefix up to and including the red position and then you iterate, you reverse every block. Sometimes I call this iterate, reverse, sometimes math, reverse. And it turns out that what you see here is exactly the primitives that you need. So what we have is these rational functions that I discussed at the very beginning. So these are letter-to-letter functions, well, not letter-to-letter functions but non-deterministic finite state automata. One function called iterated reverse which has a separator and reverses everything between the separator and one function called squaring which is this. The rational functions, they are also subject to decomposition. This is a Kron-Rodz theorem which tells you, well, it's a corollary of the Kron-Rodz theorem which tells you that every rational function can be decomposed into, especially in the presence of reversing, can be decomposed into two types of functions, one which is reversible one-way automata and the other is one specific function which is similar to the until operator in LTL. So in the end you get five basic building blocks and that's a very small amount of primitive functions. By the way, you can do the same thing for the lower classes. So for rational, it's roughly speaking the Kron-Rodz theorem. For regular, there's some other primitive functions that you need to have to be slightly weaker. Anyway, the theorem is that all of these models are equivalent and maybe I don't have time to, clearly I don't have time to prove it. Oh, it's looking good. So I mean, I discuss here the way it's proved in the paper that is an archive with this and I hope that that paper will live for some time and then it will become a journal paper when the thing settles down. This proof has already improved now, but I... So if you want to go from paper transducers, this looks like the hardest thing to compositions of atomic functions. One way you could do it is using the factorization forest theorem of Imre Schimann and just rolling up your sleeves and doing the work. Four transducers are a special case of paper transducers. So there's this... And this is kind of nice because I think it's a type of technology that is not so often used in automata theory. I mean, it's there, but there's more attention. It's about the number of calculus. So the way you do it is as follows. If you have a functional programming language, the semantics of functional programming languages is that you have like a term and then it computes, which means it substitutes something and substitutes and substitutes and so on. And it turns out that these semantics can be more or less directly... Don't read the text. Maybe oh, let me hide it so they don't read it. These semantics can be directly implemented by these transducers. So the transducer model, which is something that deserves more attention, has the property that it can transform a state of a programming language into a simpler state of a programming language, just the semantics of better reduction can be implemented by a transducer. And even if you do it carefully, you can do it so that there's not so many times you need to apply it a constant number of times and then you can evaluate restricted programs of a restricted functional programming language via transducers. They're actually a very good machine model for that and therefore they're equivalent. But I won't go into the detail. The last thing I wanted to mention is... Oh, I forgot about this. Oh, but this is sort of easy because these things are closed under composition, so all you need to do is implement the basic functions. And if you apply the Cronro's theorem to the rational function, then you have a list of five functions and you just need to program each one of them. It's a little bit painful, but you can do it. So let's forget that. There's one more model where there's two models which are missing from this list. MSO transductions are missing from this list and they appear now. I'll discuss this in a moment. So this is subsequent work that I did together with Sandra Kiefer and Nathan Lott, which was this year at ICAR. And there's one more model which is streaming transducers. I don't know. I'll get there later. But let's begin with MSO interpretation. So it is the same idea as MSO transduction, except MSO transduction, which I didn't describe to you in detail. So maybe I won't describe it in detail. I'll just go straight to what I would call MSO interpretations. And let's just do it on this particular example and you'll figure out what's going on. It's the same thing as first-order interpretations except with the logic MSO. If I want to describe the output string using logic in terms of the input string, then I would say the following thing. Positions of the output, I think here maybe without this. What's a position of the output string corresponds to a pair of positions in the input string? Like, one position which identifies which block it is and one position which identifies what is the offset in it. So I would say positions are those pairs of input positions such that y is smaller than x. Then I would call this dimension two because it means that one output position is interpreted in two input positions. In MSO transductions, you have dimension one. That's why they're linear output size. They're sort of by design. Here they can be quadratic or cubic or whatever. And then you have to say what is the order on the output positions? So here, it's roughly speaking the lexicographic order. It's on the first coordinate, it's first coordinate ordered in the usual way and then the second coordinate ordered in the opposite way. So it happens to be, I'm not sure if this is the right formula, but it's meant to be the lexicographic order with the second component done in the opposite way. Then you have to say to finally, we already described what are the positions. We actually described how they are ordered. And now we have to describe what are their labels. So again, we use a formula of logic. So we say a position x, y will have label a in the output string, if y has label a in the input string. And a position x, y will have label b in the output string if it has label b in the input string. So generally speaking, these things are allowed to be, here I had quantifier free formulas, but in general you're allowed to have MSO formulas. That's an MSO interpretation. And that's the end of the definition. And what we show is that this is exactly equivalent to Pebble Automata. Now if you've worked with MSO, you would be surprised by this. And it's also, I guess, it's also the reason why the supernatural model was supernatural is the opposite of what I wanted to say, I guess. This very natural model has not been used before. Because if you write it out like this, then the natural reaction is going to be, this is going to be an undecidable formula, because you can produce a grid. But that's not true. Because the key thing is that the types of grids, remember you have to produce a string on the output. So maybe there's some implicit grid, but it has to be linearized as the first thing. And then the second thing is that would still be problematic. For example, if you, you can write out all pairs in a string in some kind of zigzag way, and that would still be quite problematic. And then there's the second feature, which is that here I require the MSO formula to require the order on the output positions. And it turns out that this kills all undecidable ideas. If you were just required to define the successor on the output positions, you would get the undecidable models. But it turns out that if you require to produce the order, then for some mysterious reasons it's, it becomes, it can be done. And it's actually equivalent to the models before for reasons which are complicated and which we don't properly understand. So we have five models. And as I said, there's a missing model, which is the streaming model. It's not clear what the streaming model should hold in its registers. It's not going to be strings. It should be strings with some kind of substitutions, but it's hard to come up exactly with the kind of substitutions that are needed. So I, there are some preliminary results, but I don't think they're ready yet for, to discuss. So that's roughly speaking then, maybe just two more comments about what we have. So here's something that's kind of obvious, especially if you have these compositions of atomic functions because they're continuous and composition, continuous functions are closed under composition. So that means a corollary, and this is all effective, so a corollary is that, for example, the problem, given a polyregular function, does there exist at least one output of even length? This problem is decidable, because you take the set of output strings of even length, which is a regular language, you compute its pre-image under the function, and you check if it's empty. So that's, these type of problems are decidable. They're closed under composition, which is roughly evident from that. This is something kind of nice. It's not literally true. Let me start with being evaluated in linear time, AC0 later. What does that even mean? I mean, the output is quadratic. So it means that the evaluation is linear in terms of combined input and output size. And then you can have even stronger results, which say that you can have even random access, constant time random access to positions in the output string, so it's really, although it can be quite complicated. And in AC0, that requires a little bit more refining the definitions, but it's maybe not what people usually understand under AC0, but it's not far away. But it's definitely consistent with the idea that AC0 is parallel computation. And finally, there's two problems. One which is solved, it's still unpublished, that's why I have the question mark, and this is the last then on my presentation. You could consider the problem of, you're given a poly-regular function, they generalize the regular one, so you might want to say, maybe it's already regular. And this has been solved by, it's an upcoming paper by Nathan Lott, and he proves that it's decidable, he proves much more, which is that he proves that if you have a poly-regular function and its outputs are quadratic size, then it's necessarily recognized by a two-pebble transducer. And if its outputs are cubic size, then it's recognized by a three-pebble transducer, which is kind of what you would expect, and it's true. In particular, if it's linear size, then it's recognized by a one-pebble transducer, and of course it's if and only if. So the regular functions are exactly the linear output size fragment of this. And I think the big remaining open problem is equivalence. So the computational problem of given two poly-regular functions represented whichever way you like, decide if they're the same function. It seems to be hard, but that's it. So that's all I have to say, so thank you.