1 Introduction

In the framework of non-conventional computing, new models of computation have been proposed by introducing new operations on data inspired by the nature [11]. In this work, we focus our attention on biologically inspired models of computation. This approach is not new in the history of computing: Artificial Neural Networks and Genetic Algorithms were formulated many years ago by taking into account biological aspects of information processing in nature. Currently, these models can be considered classical models of computation. We are mostly interested in the new models that have been formulated with new operations based at the molecular level (mainly, the DNA recombination and mutation) or cellular level (mainly, by using the structure and organization of the living cell, and the way it processes information).

This work is highly related to the Networks of Evolutionary Processors (NEP) [9, 10]. That model was inspired by point mutations and evolutive selection on DNA, in a similar way as in genetic algorithms mutation and INSDEL genome evolution. The Networks of Splicing Processors (NSPs) [13] directly use splicing operations over strings instead of point mutation of NEPs. Finally, the Networks of Genetic Processors (NGPs) [6], use only substitution mutations together with recombination (crossover), so it is an alternative way of formulating genetic algorithms working in parallel, in a distributed way. All these models can be considered as Networks of Bio-inspired Processors (NBPs) [4], and all these models have been proved to be equivalent to Turing machines, and they have been used to solve NP-complete problems in polynomial time (in several cases, with a constant number of processors) [7, 9, 12,13,14].

In the last few years, the Networks of Polarized Evolutionary Processors (NPEP) have been proposed [1, 5]. In this case, the operations over strings are those proposed in the NEP model, the processors are positively, negatively or neutral polarized and all the strings in the network are numerically valuated. Again, these models have been proved to be computationally complete, and they have been proposed to solve hard problems efficiently.

In this work, we study the computational power of Networks of Genetic Processors as generating devices. It has been proved that this model is equivalent to Turing machines as an accepting device [6]. In addition, it was proved that they are equivalent to parallel genetic algorithms with full migration rates and synchronization, and they can solve hard problems efficiently [7].

The structure of this work is the following: First, we introduce basic concepts on classical language theory and generative grammars. Then, we formally define the Generating Networks of Genetic Processors (GNGP), and we relate them directly to genetic algorithms showing the evidences about why GNGPs can be considered parallel and distributed genetic algorithms with certain restrictions in the migration and selection processes through fitness functions. We propose different network structures to characterize each of the language classes defined in the Chomsky hierarchy, and we define each of the processors involved in the mentioned structures. In addition, we formally establish, through an inductive proof, that the proposed topologies effectively characterize upper limits in the language classes under study. Finally, we discuss our results, and we describe future research on this topic.

2 Basic concepts and notation

In the following, we introduce basic concepts about generative formal grammars and formal language theory [15, 18].

An alphabet is a finite non-empty set of elements named symbols. A string is an ordered finite sequence of symbols of an alphabet. The empty string is denoted by \(\varepsilon\) and it is defined as the string with no symbols. Given a string w, the length of the string is the number of symbols that it contains and it is denoted by |w| (observe that \(|\varepsilon |=0\)). The infinite set of all the strings defined over a given alphabet V is denoted by \(V^*\). Given the alphabet V, the set \(V^+\) is defined as \(V^+ = V^* - \{\varepsilon \}\). Given the string \(x\in V^*\), alph(x) denotes the minimal subset \(W \subseteq V\) such that \(x \in W^{*}\). Given the string \(x\in V^*\), the set of segments of x is defined by \(seg(x) = \{\beta \in V^{*} : x= \alpha \beta \gamma\) with \(\alpha , \gamma \in V^*\}\). Obviously, given any string \(x \in V^*\) the set alph(x) is a subset of seg(x). A language defined over an alphabet V is a subset of \(V^*\).

A grammar is a tuple \(G=(N,T,P,S)\), where N is an alphabet of auxiliary symbols, T is an alphabet of terminal symbols, with \(N \cap T = \emptyset\), \(S \in N\) is an axiom or initial symbol, and P is a finite set of production rules. Every production rule is a pair \((\alpha , \beta )\) (also written as \(\alpha \rightarrow \beta\)), with \(\alpha \in (N \cup T)^* N (N \cup T)^*\) and \(\beta \in (N \cup T)^*\). Given two strings of terminal and auxiliary symbols, v and w, we say that w can be obtained from v in a direct derivation according to G, and we denote it by \(v \underset{G}{\Rightarrow } w\), if \(v=v_1 \alpha v_2\), \(w = v_1 \beta v_2\) and \(\alpha \rightarrow \beta \in P\). Observe that the direct derivation is a relation between strings formed by terminal and auxiliary symbols, and we can define the reflexive and transitive closure of \(\underset{G}{\Rightarrow }\) as the derivation relation between any pair of strings v and w, that is denoted by \(v \overset{*}{\underset{G}{\Rightarrow }} w\), and it is defined iff one of the following conditions hold:

  1. 1.

    \(v=w\) (no production rule is applied over v), or,

  2. 2.

    \(v \underset{G}{\Rightarrow } u \overset{*}{\underset{G}{\Rightarrow }} w\) (a positive number of rules are applied to obtain w from u).

In addition, we denote i derivation steps by the symbol \(\overset{i}{\underset{G}{\Rightarrow }}\).

The language generated by \(G=(N,T,P,S)\) is defined as follows

$$\begin{aligned} L(G) = \{ w \in T^* : S \overset{*}{\underset{G}{\Rightarrow }} w \}. \end{aligned}$$

The grammars \(G_1\) and \(G_2\) are equivalent if \(L(G_1)=L(G_2)\), and \(G_1\) is quasi-equivalent to \(G_2\) if \(L(G_1) = L(G_2) - \{ \varepsilon \}\).

The Chomsky hierarchy is a framework to study large formal language classes. It is based on the classification of generative grammars according to the forms of the production rules. It establishes four classes of grammars that we can enumerate as follows:

  1. 1.

    Regular grammars (right linear grammars)

    The productions of the grammar must be in one of the following forms

    • \(A \rightarrow aB\), with \(A,B \in N\) and \(a \in T\)

    • \(A \rightarrow a\), with \(A \in N\) and \(a \in T \cup \{ \varepsilon \}\)

  2. 2.

    Context-free grammars

    The productions of the grammar must be in the form \(A \rightarrow \alpha\), with \(A \in N\), and \(\alpha \in (N \cup T)^*\).

    The Chomsky Normal Form for context-free grammars is defined whenever the productions are in one of the following forms:

    • \(A \rightarrow BC\), with \(A,B,C \in N\)

    • \(A \rightarrow a\), with \(A \in N\) and \(a \in T\)

    It is well known that for every context-free grammar there exists a quasi-equivalent grammar in Chomsky Normal Form.

  3. 3.

    Context-sensitive grammars

    The derivations of the grammar are length increasing (with the exception of the derivation of \(\varepsilon\)). We can establish the Kuroda Normal Form for context-sensitive grammars. It is defined by the following production forms:

    • \(A \rightarrow a\), with \(A \in N\) and \(a \in T\)

    • \(A \rightarrow B\), with \(A,B \in N\)

    • \(A \rightarrow BC\) with \(A,B,C \in N\)

    • \(AB \rightarrow CD\) with \(A,B,C,D \in N\)

    In addition, we can add the production rule \(S \rightarrow \varepsilon\), whenever S does not appear in the right side of any production rule. In such a case, the grammar can generate the empty string.

  4. 4.

    Phrase structure grammars

    There are no restrictions in the form of the production rules. Nevertheless, we can establish the following production rules, as an extended Kuroda Normal Form:

    • \(S \rightarrow \varepsilon\)

    • \(A \rightarrow a\), with \(A \in N\) and \(a \in T\)

    • \(A \rightarrow B\), with \(A,B \in N\)

    • \(A \rightarrow BC\) with \(A,B,C \in N\)

    • \(AB \rightarrow AC\) with \(A,B,C,D \in N\)

    • \(AB \rightarrow CB\), with \(A,B,C \in N\)

    • \(AB \rightarrow B\), with \(A,B \in N\)

    The initial symbol S may appear only in the left-hand sides of the production rules.

The Chomsky hierarchy establishes the relationship of the language classes defined by the previously established classes of formal grammars. So, REG, CF, CS and RE refer to the languages generated by the previously defined grammars, and we have the following inclusions (the Chomsky hierarchy):

$$\begin{aligned} REG \subset CF \subset CS \subset RE. \end{aligned}$$

3 Generating networks of genetic processors

In the following, we define the Generating Networks of Genetic Processors. The basic elements of the model are inspired by previous works on Networks of Evolutionary Processors (NEPs) [9, 10], and Networks of Splicing Processors (NSPs) [13, 14]. In addition, the main ingredients of Generating Networks of Genetic Processors were previously defined as Accepting Networks of Genetic Processors [6].

Given the alphabet V, a mutation rule \(a \rightarrow b\), with \(a,b \in V\), can be applied over the string xay to produce the new string xby. A mutation rule can be viewed as a substitution rule introduced in [10].

A crossover operation is an operation over strings defined as follows: Let x and y be two strings, then \(x \bowtie y = \{ x_1y_2, y_1x_2 : x = x_1 x_2\) and \(y= y_1 y_2 \}\). Observe that \(x,y \in x \bowtie y\) given that \(\epsilon\) is a prefix and a suffix of any string. The operation is extended over languages as \(L_1 \bowtie L_2 = \bigcup _{x\in L_1, y\in L_2} x \bowtie y\). The crossover operation is a splicing operation over strings where the contexts of the strings are empty [17].

Let P and F be two disjoint subsets of an alphabet V, and let \(w \in V^*\). We define the predicate \(\varphi\) as follows:Footnote 1

$$\begin{aligned} \varphi (w,P,F) \equiv (P=\emptyset \vee alph(w) \cap P \ne \emptyset ) \wedge (F \cap alph(w) = \emptyset ) \end{aligned}$$

We can extend the predicate to act over segments instead of symbols. Let P and F be two disjoint sets of finite strings over V, and let \(w \in V^*\), then

$$\begin{aligned} \varphi (w,P,F) \equiv (P=\emptyset \vee seg(w) \cap P \ne \emptyset ) \wedge (F \cap seg(w) = \emptyset ). \end{aligned}$$

In the following, we work with this extension over segments instead of symbols. The predicate \(\varphi\) is based on random-context conditions defined by the sets P (permitting contexts) and F (forbidding contexts). Let V be an alphabet and \(L \subseteq V^{*}\), then \(\varphi (L,P,F)=\{w \in L : \varphi (w,P,F) \}\).

In the following, we define a genetic processor that can be viewed as an abstract machine that can apply mutation rules or crossover operations over a multiset of strings.

Definition 1

Let V be an alphabet. A genetic processor over V is defined by the tuple \((M_R,A,PI,FI,PO,FO,\alpha )\), where

  • \(M_R\) is a finite set of mutation rules over V

  • A is a multiset of strings over V with a finite support and an arbitrary large number of copies of every string.Footnote 2

  • \(PI,FI \subseteq V^*\) are finite sets with the input permitting/forbidding contexts

  • \(PO,FO \subseteq V^*\) are finite sets with the output permitting/forbidding contexts

  • \(\alpha \in \{m,c\}\) defines the function mode as follows:

    • If \(\alpha =m\) the processor applies mutation rules.

    • If \(\alpha =c\) the processor applies crossover operations, and \(M_R = \emptyset\).

In any genetic processor, and for any word \(w \in V^*\), there is an input filter \(\rho (w)=\varphi (w,PI,FI)\) and an output filer \(\tau (w)=\varphi (w,PO,FO)\). That is, \(\rho (w)\) (resp. \(\tau (w)\)) indicates whether or not the word w passes the input (resp. the output) filter of the processor. We can extend the filters to act over languages. So, \(\rho (L)\) (resp. \(\tau (L)\)) is the subset of L with the words that can pass the input (resp. output) filter of the processor.

Once we have defined the main component of the model, that is the genetic processor, we can formulate the Generating Networks of Genetic Processors as follows:

Definition 2

A Generating Network of Genetic Processors (GNGP) is defined by the tuple \(\varPi = (V,V_{out},N_{1},N_{2},\ldots ,N_{n},G,{{\mathcal {N}}},N_{out})\), where V is an alphabet, \(V_{out} \subseteq V\) is an output alphabet, \(G=(X_G,E_G)\) is a graph, \(N_{i} (1 \le i \le n)\) is a genetic processor over V, \({{\mathcal {N}}}: X_G \rightarrow \{N_{1},N_{2},\ldots ,N_{n} \}\) is a mapping that associates the genetic processor \(N_i\) to the node \(i \in X_G\), and the processor \(N_{out} \in \{ N_1, \cdots , N_n\}\) is the output processor.

A configuration of a GNGP \(\varPi = (V,V_{out},N_{1},N_{2},\ldots ,N_{n},G,{{\mathcal {N}}},N_{out})\) is defined by the tuple \(C=(L_{1},L_{2},\ldots ,L_{n})\), where \(L_{i}\) is a multiset of strings defined over V for all \(1 \le i \le n\). A configuration represents the multisets of strings that every processor holds at a given time (remember that every string appears in an arbitrarily large number of copies). The initial configuration of the network is \(C_{0}=(A_{1},A_{2},\ldots ,A_{n})\).

Every copy of any string in \(L_i\) can be changed by applying a genetic step, according to the mutation rules or the crossover operations in the processor \(N_i\). Formally, we say that the configuration \(C_{1}=(L_{1},L_{2},\ldots ,L_{n})\) directly changes into the configuration \(C_{2}=(L'_{1},L'_{2},\ldots ,L'_{n})\) by a genetic step, denoted by \(C_{1} \Rightarrow C_{2}\), if \(L'_{i}\) is the multiset of strings obtained by applying the mutation rules or the crossover operations of \(N_{i}\) to the strings in \(L_{i}\). Since an arbitrarily large number of copies of each string is available in every processor, after a genetic step, in each processor, one gets an arbitrarily large number of copies of any string, that can be obtained by using all possible mutation rules or crossover operations associated with that processor. If \(L_{i}\) is empty for some \(1 \le i \le n\), then \(L'_{i}\) is empty as well.

In a communication step, each processor \(N_{i}\) sends all copies of the strings to all the processors connected to \(N_{i}\) according to G, provided that they are able to pass its output filter. In addition, it receives all the copies of the strings sent by the processors connected to \(N_{i}\) according to G, provided that they can pass its input filter. Formally, we say that the configuration \(C'\) is obtained in one communication step from configuration C, denoted by \(C \vdash C'\), iff

$$\begin{aligned} (\forall x \in X_G) \,\, C'(x)=(C(x)-\tau _{x}(C(x))) \cup \bigcup _{\{x,y\}\in E_G} (\tau _{y}(C(y))\cap \rho _{x}(C(y))). \end{aligned}$$

Observe that, if one string leaves any processor together with all its copies, and it cannot enter into any new processor due to its filter restrictions, then the string and all its copies are lost.

Let \(\varPi = (V,V_{out},N_{1},N_{2},\ldots ,N_{n},G,{{\mathcal {N}}},N_{out})\) be a GNGP. A computation in \(\varPi\) is a sequence of configurations \(C_{0},C_{1}, \ldots\), where \(C_{0}\) is the initial configuration of \(\varPi\), \(C_{2i} \Rightarrow C_{2i+1}\) and \(C_{2i+1} \vdash C_{2i+2}\) for all \(i \ge 0\). In the following, we will use the symbol \(\mapsto\) to denote a genetic step followed by a communication step. That is, \(C \mapsto C^{\prime }\) iff \(C \Rightarrow C^{\prime \prime } \vdash C^{\prime }\). In addition, to emphasize that the computation is carried out in the network \(\varPi\) we denote it by the symbol \(\underset{\varPi }{\mapsto }\). Consequently, the reflexive and transitive closure of \(\mapsto\) is denoted by \(\overset{*}{\mapsto }\). In addition, the symbol \(\overset{i}{\underset{\varPi }{\mapsto }}\) denotes i genetic steps plus i communication steps in the usual alternating way. All the strings defined over \(V_{out}\) which are in the output processor \(N_{out}\) at any computation step belong to the language generated by the network. Let \(\varPi = (V,V_{out},N_{1},\ldots ,N_{n},G,{{\mathcal {N}}},N_{out})\) be a GNGP with \(N_{out} = N_k\), the language generated by \(\varPi\) is denoted by \(L(\varPi )\), and it is defined as follows.

$$\begin{aligned} L(\varPi ) = \{ x \in V_{out}^* \cap L_k : (A_0, \ldots , A_k, \ldots A_n) \overset{*}{\underset{\varPi }{\mapsto }} (L_0, \ldots , L_k, \ldots , L_n) \} \end{aligned}$$

Observe that according to the definition any finite language L can be trivially generated by a GNGP by defining \(A_{out}=L\). Hence, the empty string \(\varepsilon\) can be generated by including it as an element of \(A_{out}\). In the following section we will not consider the empty string since, according to the criteria defined above, it can be generated in a trivial way.

3.1 Generating networks of genetic processors are parallel genetic algorithms

Once we have defined the Networks of Genetic Processors as generating devices, we are going to relate them to the classical concept of genetic algorithms and, particularly, to the case of parallel genetic algorithms. We followed this approach in a previous work [6] where we could also formulate genetic algorithms as decision problem solvers, as opposed to the more classical view that implies their definition as optimization algorithms. We have followed fundamentally the reference [16] for the case of genetic algorithms, and [8] for the case of parallel genetic algorithms.

We can see that every string inserted in a genetic processor is an individual of its population with an undefined number of clones. In addition, the mutation and crossover operations are applied in this case in a non-uniform way (the genetic crossover of two individuals is considered as a case where the new individuals can extend their genetic code indefinitely). In our case, the fitness function, used for the selection of different individuals to generate new populations, is limited to the selection of individuals for the migration rates discussed below. In the case of GNGPs, the genetic operators are applied to the entire population without making any exceptions. Mutation and crossover ratios are kept uniform throughout the process and no elitism technique is applied to the selection of individuals. Finally, we want to note that the output processor of the network would contain individuals resulting from computation which, in the case of genetic algorithms, would be the population with all feasible solutions to a given problem.

For the case of parallel and distributed genetic algorihms, [3] and [2] define the main components to be established. We can enumerate these components as follows:

  1. 1.

    The distribution of the individuals in different populations. They can be organized in different topologies: master– slave, multiple populations or islands, fine-grained populations or hierarchical and hybrid populations. In addition, the neighborhood connections can be rings, (mn)-complete, ladders, grids, etc.

  2. 2.

    The synchronicity of evolution and communication of the populations

  3. 3.

    The migration phenomena: migration rates (the percentage of individuals that migrate from one population to a different one), migration selection (the selections of the individuals that migrate) and migration frequency.

The above three aspects are covered in the definition of the GNGPs. The topology of connection of populations, and their initial distribution is made by means of the configuration of the processors connection graph. The evolution and communication of the populations is carried out by means of the universal clock underlying the definition of the operating mode of the networks. Finally, the migration processes are regulated by the definition of the input and output filters of each processor. In other words, the filters defined in the processors are effective procedures for selecting the individuals who can migrate from one population to another.

Therefore, we can conclude that the GNGPs definition meets the main ingredients of parallel and distributed genetic algorithms. In this way, we can initiate a formal study about the generative capacity of the genetic algorithms and how many populations acting in parallel are necessary to be able to generate different populations formalized under the paradigm of the theory of formal languages. This study will be addressed in the following section.

4 Generating formal languages through generating networks of genetic processors

In this section, we propose different Generating Networks of Genetic Processors to generate the formal languages according to the Chomsky hierarchy. The number of processors of every proposed network structure is important in order to generate every language class. A general criterion that has been followed to formulate the different topologies and their use in the theorem proofs is that processors that use crossover are used to increase the lengths of the strings that are generated in the grammar, while processors that use mutation are used to make effective the substitution of non-terminal symbols by new terminal or non-terminal symbols.

In the following, we denote a complete graph with n vertexes by \(K_n\) and the identity function from processors to vertexes by id.

Our first result is related to the regular language class, defined by right linear grammars. We provide the following theorem.

Fig. 1
figure 1

GNGP structure for regular grammars

Theorem 1

Every regular language can be generated by a GNGP with 3 processors.

Proof

Let \(L=L(G)\) and \(G=(N,T,P,S)\) be a right linear grammar. We define the GNGP \(\varPi =(V,T,N_1,N_2,N_{3},K_3,id,N_1)\), where \(V = N \cup T \cup {\hat{N}} \cup [TN]\), with \({\hat{N}} = \{ {\hat{A}} : A \in N \}\) and \([TN] = \{ [aB] : a \in T, B \in N \}\). The processors in \(\varPi\) are defined as follows

  1. 1.

    \(N_{1}=(M_{1},\{S\},N,FI_{1},PO_{1},\emptyset ,m)\)

    \(\begin{array}{l} M_{1}=\{A \rightarrow [bC] : (A \rightarrow bC) \in P\} \cup \{A \rightarrow a : (A \rightarrow a) \in P\}\\ FI_{1}= [TN] \cup {\hat{N}}\\ PO_{1}= [TN] \end{array}\)

  2. 2.

    \(N_{2}=(\emptyset ,A_{2},PI_{2},\emptyset ,PO_{2},\emptyset ,c)\)

    \(\begin{array}{l} A_{2}={\hat{N}} \\ PI_{2}= [TN]\\ PO_{2}= VV \cup (V - {\hat{N}})\\ \end{array}\)

  3. 3.

    \(N_{3}=(M_{3},\emptyset ,PI_{3},\emptyset ,V,FO_{3},m)\)

    \(\begin{array}{l} M_{3}=\{[aA] \rightarrow a : A \in N \wedge a \in T\} \cup \{{\hat{A}} \rightarrow A : A \in N\}\\ PI_{3}=\{[aA]{\hat{A}} : a \in T \wedge A \in N \}\\ FO_{3}= [TN] \cup {\hat{N}}\\ \end{array}\)

The network structure is shown in Fig.  1, and it simulates the derivation process in the regular grammar. Processor \(N_1\) collects the output strings and it applies the productions of the grammar. Observe that the strings of the language cannot leave the processor due to the output filter definition. Processor \(N_2\) is used for the case when a production in the form \(A \rightarrow bC\) has been applied. It applies crossover in order to add a new symbol from \({\hat{N}}\) at the end of the string. Observe that, due to the \(PO_2\) filter definition, all the symbols from \({\hat{N}}\) remain in the processor \(N_2\). Finally, processor \(N_3\) substitutes the symbols from \({\hat{N}}\) and [TN] used by \(N_1\) and \(N_2\) in order to keep the derivation process of the grammar. We propose the following enunciate that allows the formal proof of the theorem:

$$\begin{aligned} S \overset{*}{\underset{G}{\Rightarrow }} \alpha \,\, \text {iff} \,\, (\{S\},A_2, \emptyset ) \overset{*}{\underset{\varPi }{\mapsto }} (L_1, L_2, L_3) \end{aligned}$$

with \(\alpha \in L_1 \cap (N \cup T)^*\)

In order to prove the statement, we carry out an induction process over the number of derivation steps in the grammar G to obtain \(\alpha\). So, we prove that if \(S \overset{*}{\underset{G}{\Rightarrow }} \alpha\) then a configuration \((L_1,L_2,L_3)\) exists such that \(\alpha \in L_1 \cap (N \cup T)^*\)

Induction base

In this case, only one derivation step in the grammar is applied as \(S \underset{G}{\Rightarrow } \alpha\) (observe that we have omitted the trivial case \(S \overset{*}{\underset{G}{\Rightarrow }} S\)). If one derivation step is carried out, the production \(S \rightarrow \alpha \in P\). If \(\alpha = a\) then \(S \rightarrow a \in M_1\), and in the first genetic step S mutates to a and, in the following communication step, a does not leave the processor \(N_1\). So, \((\{S\},A_2, \emptyset ) \underset{\varPi }{\mapsto } (L_1, L_2, L_3)\), \(a \in L_1\) and the statement is true.

If \(\alpha = aB\) then \(S \rightarrow [aB] \in M_1\) and \([aB] \rightarrow a \in M_3\). The following steps are carried out in \(\varPi\): First, S mutates to [aB] in \(N_1\) during the first genetic step, then the string [aB] is communicated to \(N_2\). Here, by applying the crossover operation, the string \([aB]{\hat{B}}\) is obtained and it is communicated to \(N_3\). The other strings that can be obtained by applying the crossover operations are sent out the processor \(N_2\), and they cannot enter into a new processor, so they are lost. In the processor \(N_3\), the symbol [aB] mutates to a and the symbol \({\hat{B}}\) mutates to B in the next two genetic steps. Finally, the string aB is communicated to \(N_1\) and the statement is true.

Induction hypothesis

Let us suppose that for every integer p such that \(S \overset{p}{\underset{G}{\Rightarrow }} \alpha\), with \(1 \le p\), there is a number k such that \((\{S\},A_2,\emptyset ) \overset{k}{\underset{\varPi }{\mapsto }}(L_1,L_2,L_3)\) with \(\alpha \in L_1 \cap (N \cup T)^*\).

Induction step

Finally, let us suppose that \(S \overset{p}{\underset{G}{\Rightarrow }} \beta \underset{G}{\Rightarrow } \alpha\). Here, \(\beta = wA\) with \(w \in T^*\) and \(A \in N\) and, by our induction hypothesis, \((\{S\},A_2,\emptyset ) \overset{k}{\underset{\varPi }{\mapsto }}(L_1,L_2,L_3)\) with \(wA \in L_1\). Now, we consider two cases to obtain \(\alpha\) from wA: First, \(A \rightarrow b \in P\), with \(b \in T\), and \(\alpha =wb\). In this case, the string wA mutates to wb in \(N_1\) given that \(A \rightarrow b \in M_1\). In the following communication step, wb does not leave the processor \(N_1\) and the statement is true. The second case is established whenever \(A \rightarrow bC \in P\) and \(\alpha = wbC\). Here, the string wA is in processor \(N_1\) by our induction hypothesis. Then, the string wA mutates to w[bC] given that \(A \rightarrow [bC] \in M_1\). The string w[bC] is then communicated to \(N_2\) and, in the next genetic step, by applying the crossover operation in \(N_2\) the string \(w[bC]{\hat{C}}\) is obtained and communicated to \(N_3\). In the next two genetic steps, the string \(w[bC]{\hat{C}}\) mutates to wbC which is finally communicated to \(N_1\), and the statement is true.

The second part of the statement can be established as follows:

$$\begin{aligned} \text {if}\,\, (\{S\},A_2,\emptyset ) \overset{*}{\underset{\varPi }{\mapsto }}(L_1,L_2,L_3) \,\, \text {with} \,\, \alpha \in L_1 \cap (N \cup T)^* \,\, \text {then} \,\, S \overset{*}{\underset{G}{\Rightarrow }} \alpha . \end{aligned}$$

Here, we can carry out the induction proof in a way similar to the previous one.

Given that for every string \(w \in L(G)\), \(S \overset{*}{\underset{G}{\Rightarrow }} w\), we have proved that there exists a configuration \((L_1,L_2,L_3)\) with \(w \in L_1\) which can be obtained during the network computation and, consequently, \(w \in L(\varPi )\). So, the theorem is proved to be true. \(\square\)

Example 1

Let G be the regular grammar defined by the following productions

$$\begin{aligned} S \rightarrow aA \mid bB\quad A \rightarrow aA \mid a\quad B \rightarrow bB \mid b \end{aligned}$$

The grammar G generates the language \(L(G) = \{ a^n : n \ge 2 \} \cup \{ b^n : n \ge 2 \}.\)

We define a GNGP \(\varPi =(V,T,N_1,N_2,N_{3},K_3,id,N_1)\) that generates L(G) as follows:

$$\begin{aligned} V= & {} \{ S, A, B, a, b, {\hat{S}}, {\hat{A}}, {\hat{B}}, [aA], [aB], [aS], [bA], [bB], [bS] \}\\ T= & {} \{ a,b \} \end{aligned}$$

The processor \(N_1 = (M_{1},\{S\},\{S,A,B\},FI_{1},PO_{1},\emptyset ,m)\) where \(M_1\) is defined by the rules:

$$\begin{aligned}&\begin{array}{lll} S \rightarrow [aA] &{} S \rightarrow [bB] &{} A \rightarrow [aA] \\ A \rightarrow a &{} B \rightarrow [bB] &{} B \rightarrow b \\ \end{array}\\&FI_1= \{ {\hat{S}}, {\hat{A}}, {\hat{B}}, [aA], [aB], [aS], [bA], [bB], [bS] \},\hbox { and }\\&PO_1 = \{ [aA], [aB], [aS], [bA], [bB], [bS]\} \end{aligned}$$

The processor \(N_{2}=(\emptyset ,A_{2},PI_{2},\emptyset ,PO_{2},\emptyset ,c)\) where

$$\begin{aligned} A_2= & {} \{ {\hat{S}}, {\hat{A}}, {\hat{B}} \},\\ PI_2= & {} \{ [aA], [aB], [aS], [bA], [bB], [bS] \},\hbox { and }\\ PO_2= & {} VV \cup \{ S, A, B, a, b, [aA], [aB], [aS], [bA], [bB], [bS] \} \end{aligned}$$

The processor \(N_{3}=(M_{3},\emptyset ,PI_{3},\emptyset ,V,FO_{3},m)\) where \(M_3\) is defined by the rules:

$$\begin{aligned}&\begin{array}{lll} {[}aS] \rightarrow a &{} [bS] \rightarrow b &{} [aA] \rightarrow a \\ {[}bA] \rightarrow b &{} [aB] \rightarrow a &{} [bB] \rightarrow b \\ {\hat{S}} \rightarrow S &{} {\hat{A}} \rightarrow A &{} {\hat{B}} \rightarrow B\\ \end{array}\\&PI_3 = \{ [aS]{\hat{S}}, [bS]{\hat{S}}, [aA]{\hat{A}}, {[}bA]{\hat{A}}, [aB]{\hat{B}}, [bB]{\hat{B}} \},\hbox { and }\\&FO_ 3 = \{ {\hat{S}}, {\hat{A}}, {\hat{B}}, [aA], [aB], [aS], [bA], [bB], [bS] \} \end{aligned}$$

The functioning of the network is explained in the following: In processor \(N_1\), the productions of the grammar are effectively applied. For example, if the production is \(A \rightarrow a\) then directly the mutation \(A\rightarrow a\) is applied, while if the production \(A \rightarrow aA\) is applied then the mutation \(A \rightarrow [aA]\) mutates the auxiliary symbol. Then the mutated string with the [aA] symbol is sent to the \(N_2\) processor. In processor \(N_2\), by means of crossover operations, strings with the segment \([aA]{\hat{A}}\) are obtained. These strings are sent to processor \(N_3\). In processor \(N_3\) the mutation symbols [aA] are changed to a and the mutation symbols \({\hat{A}}\) are changed to A. The string, which already contains only auxiliary and terminal symbols of the grammar G, is sent back to processor \(N_1\) and a new grammar derivation cycle can be applied. Note that those strings containing only terminal symbols do not leave the processor \(N_1\) and they are the strings generated by the grammar G. \(\square\)

For the class of context-free languages we use an additional processor with respect to the network structure used in the regular case. In Fig.  2, we show the network structure that we use in the following proof.

Fig. 2
figure 2

GNGP structure for context-free grammars

Theorem 2

Every context-free language can be generated by a GNGP with 4 processors.

Proof

Let \(G=(N,T,P,S)\) be a context-free grammar in Chomsky Normal Form and \(L=L(G)\). We define the GNGP \(\varPi =(V,T,N_{1},N_{2},N_{3}, N_{4},K_4,id,N_1)\), where \(V = N \cup T \cup {\hat{N}} \cup {\hat{T}} \cup {\bar{N}} \cup {\bar{T}} \cup [NT] \cup [NN] \cup [TN] \cup [TT] \cup [NT]' \cup [NN]' \cup [TN]' \cup [TT]' \cup [[NN]] \cup \overline{[[NN]]} \cup [[NN]]^{f}\). The alphabets are defined as follows:

$$\begin{aligned} \begin{array}{ll} {\hat{N}} = \{ {\hat{A}} : A \in N \} &{} [NT]' = \{ [Aa]' : A \in N, a \in T \} \\ {\hat{T}} = \{ {\hat{a}} : a \in N \} &{} [NN]' = \{ [AB]' : A,B \in N \} \\ {\bar{N}} = \{ {\bar{A}} : A \in N \} &{} [TN]' = \{ [aA]' : a \in T, A \in N \} \\ {\bar{T}} = \{ {\bar{a}} : a \in T \} &{} [TT]' = \{ [ab]' : a,b \in T \} \\ {[}NT] = \{ [Aa] : A \in N, a \in T \} &{} [[NN]] = \{ [[AB]] : A,B \in N \} \\ {[}NN] = \{ [AB] : A,B \in N \} &{} \overline{[[NN]]} = \{\overline{[[AB]]} : A,B \in N \} \\ {[}TN] = \{ [aA] : a \in T, A \in N \} &{} [[NN]]^{f}= \{ [[AB]]^{f} : A,B \in N \} \\ {[}TT] =\{ [ab] : a,b \in T \} &{} \\ \end{array} \end{aligned}$$

The processors in \(\varPi\) are defined as follows

  1. 1.

    \(N_{1}=(M_{1},\{S\},V,FI_{1},PO_{1},\emptyset ,m)\)

    \(\begin{array}{l} M_{1}= \{A \rightarrow [[BC]] : (A \rightarrow BC) \in P\} \cup \{A \rightarrow a : (A \rightarrow a) \in P\}\\ FI_{1}= {\bar{N}} \cup {\bar{T}} \cup {\hat{N}} \cup {\hat{T}} \cup {[}NT] \cup [NN] \cup [TN] \cup [TT] \cup [NN]' \cup \overline{[[NN]]} \cup [[NN]]^{f}\\ PO_{1}= [[NN]] \\ \end{array}\)

  2. 2.

    \(N_{2}=(M_{2},\emptyset ,PI_{2},\emptyset ,V,FO_{2},m)\)

    \(\begin{array}{l} M_{2}= \{ A \rightarrow [BA] : A,B \in (N \cup T) \} \cup \{A \rightarrow [BA]' : A,B \in (N \cup T)\}\\ \qquad \cup \{A \rightarrow {\bar{A}} : A \in (N \cup T)\} \cup \{[[AB]] \rightarrow \overline{[[AB]]} : A,B \in N\}\\ \qquad \cup \{[[AB]] \rightarrow [[AB]]^{f} : A,B \in N\}\\ PI_{2}= [[NN]]\\ FO_{2}= [[NN]] \cup N \cup T\\ \end{array}\)

  3. 3.

    \(N_{3}=(\emptyset ,({\hat{N}} \cup {\hat{T}}),PI_{3},FI_{3},PO_{3},\emptyset ,c)\)

    \(\begin{array}{l} PI_{3}=\{[AB]' : A,B \in (N \cup T)\} \cup \{[[AB]]^{f} : A,B \in N\}\\ FI_{3}= N \cup T \cup {\hat{N}} \cup {\hat{T}} \cup \{[AB][CD] : B \ne C\}\\ \qquad \cup \{[AB][CD]' : B \ne C\} \cup \{\overline{[[AB]]}[CD] : B \ne C\} \\ \qquad \cup \{\overline{[[AB]]}[CD]' : B \ne C\} \cup \{[AB]\overline{[[CD]]} : A,B \in (N \cup T) \wedge C,D \in N\} \\ \qquad \cup \{[AB]'C : A,B \in (N \cup T) \wedge C \in V\} \cup \{{\bar{A}}[BC]' : A,B,C \in (N \cup T)\} \\ \qquad \cup \{{\bar{A}}[BC] : A,B,C \in (N \cup T)\} \cup \{[[AB]]^{f}C : A,B \in N \wedge C \in V\} \\ \qquad \cup \{[AB][[CD]]^{f} : A,B \in (N \cup T) \wedge C,D \in N\}\\ PO_{3}=\{AB : A,B \in V\} \cup (V-({\hat{N}} \cup {\hat{T}}))\\ \end{array}\)

  4. 4.

    \(N_{4}=(M_{4},\emptyset ,PI_{4},\emptyset ,V,FO_{4},m)\)

    \(\begin{array}{l} M_{4}=\{[AB] \rightarrow A : A,B \in (N \cup T)\} \cup \{[AB]' \rightarrow A : A,B \in (N \cup T)\} \\ \qquad \cup \{\overline{[[AB]]} \rightarrow A : A,B \in N\} \cup \{[[AB]]^{f} \rightarrow A : A,B \in N\} \\ \qquad \cup \{{\hat{A}} \rightarrow A : A \in (N \cup T)\} \cup \{{\bar{A}} \rightarrow A : A \in (N \cup T)\}\\ PI_{4}= \{[[AB]]^{f}{\hat{B}} : A,B \in N\} \cup \{[AB]'{\hat{B}} : A,B \in (N \cup T)\}\\ FO_{4}= {\hat{N}} \cup {\hat{T}} \cup {\bar{N}} \cup {\bar{T}} \cup [NT] \cup [NN] \cup [TN] \cup [TT] \cup \overline{[[NN]]} \cup [NT]' \\ \qquad \cup [NN]' \cup [TN]' \cup [TT]' \cup [[NN]]^{f} \end{array}\)

The processor \(N_1\) collects the output strings and, in the network, the following transformations are carried out: Processor \(N_1\) applies the grammar rules in the Chomsky Normal Form. The rule \(A \rightarrow a\) is directly applied, while the rule \(A \rightarrow BC\) needs a sequence of transformations in processors \(N_2\), \(N_3\) and \(N_4\). First, A is transformed into [[BC]] in processor \(N_1\). Then, a string in the form x[[BC]]y, with \(x,y \in (N \cup T)^*\), enters into processor \(N_2\). In processor \(N_2\) the string \(x [[BC]]y_1 y_2 \ldots y_n\), with \(y_j \in N \cup T\) is transformed into the string \({\bar{x}} [[BC]] [Cy_1] [y_1 y_2] \ldots [y_{n-2}y_{n-1}][y_{n-1}y_{n}]'\) and [[BC]] is transformed into \(\overline{[[BC]]}\) or \([[BC]]^f\). The symbol \([[BC]]^f\) is used for the case that y is the empty string and the symbol [[BC]] is at the end of the string. Hence, only the strings in the form \({\bar{x}} [[BC]] [Cy_1] [y_1 y_2] \ldots [y_{n-2}y_{n-1}][y_{n-1}y_{n}]'\) or \({\bar{x}} [[BC]]^f\) can enter into the processor \(N_3\). The rest of transformed strings leave the processor \(N_2\) and cannot enter into a new processor, so they are lost. In processor \(N_3\), crossover is carried out, and the strings \({\bar{x}} [[BC]] [Cy_1] [y_1 y_2] \ldots [y_{n-1}y_{n}]'\hat{y_n}\) or \({\bar{x}} [[BC]]^f{\hat{C}}\) can be obtained. In one communication step, all the strings obtained by crossover leave the processor \(N_3\). Only the strings in the form \({\bar{x}} [[BC]] [Cy_1] \ldots [y_{n-1}y_{n}]'\hat{y_n}\) or \({\bar{x}} [[BC]]^f{\hat{C}}\) can enter into processor \(N_4\). In the processor \(N_4\), all the symbols that have been inserted or transformed in processors \(N_2\) and \(N_3\) are changed to the symbols of the grammar G. So, the string \({\bar{x}} [[BC]] [Cy_1] [y_1 y_2] \ldots [y_{n-1}y_{n}]'\hat{y_n}\) is transformed to \(x BCy_1 y_2 \ldots y_{n-2}y_{n-1}y_{n}\) and the string \({\bar{x}} [[BC]]^f{\hat{C}}\) is transformed to xBC. The transformed strings leave the processor \(N_3\) and they can enter only in processor \(N_1\) where a new sequence of transformation could start again.

Formally, we can prove the following statement

$$\begin{aligned} S \overset{*}{\underset{G}{\Rightarrow }} \alpha \,\, \text {iff} \,\, (\{S\},\emptyset ,({\hat{N}}\cup {\hat{T}}), \emptyset ) \overset{*}{\underset{\varPi }{\mapsto }} (L_1, L_2, L_3, L_4) \,\, \text {with} \,\, \alpha \in L_1 \cap (N \cup T)^* \end{aligned}$$

We carry out an induction process over the number of derivation steps in the grammar G to obtain \(\alpha\). So, we prove that if \(S \overset{*}{\underset{G}{\Rightarrow }} \alpha\) then a configuration \((L_1,L_2,L_3,L_4)\) exists with \(\alpha \in L_1 \cap (N \cup T)^*\)

Induction base

In this case, only one derivation step in the grammar is applied as \(S \underset{G}{\Rightarrow } \alpha\). If one derivation step is carried out, the production \(S \rightarrow \alpha \in P\). If \(\alpha = a \in T\) then \(S \rightarrow a \in M_1\), and in the first genetic step S mutates to a and, in the following communication step, a does not leave the processor \(N_1\). So, \((\{S\},\emptyset ,({\hat{N}}\cup {\hat{T}}), \emptyset ) \overset{*}{\underset{\varPi }{\mapsto }} (L_1, L_2, L_3, L_4)\), \(a \in L_1\) and the statement is true.

If \(\alpha = AB\) then \(S \rightarrow [[AB]] \in M_1\). Then, [[AB]] leaves \(N_1\) and enters into \(N_2\) where it mutates to \([[AB]]^f\). The string \([[AB]]^f\) leaves \(N_2\) and it enters into \(N_3\). In the processor \(N_3\), the strings \([[AB]]^f\) and \({\hat{B}}\) are recombined by crossover to obtain the string \([[AB]]^f{\hat{B}}\) that leaves the processor \(N_3\) and it enters into the processor \(N_4\). Finally, in the processor \(N_4\), the string \([[AB]]^f{\hat{B}}\) is transformed into AB and communicated to the processor \(N_1\) where it enters. So, \((\{S\},\emptyset ,({\hat{N}}\cup {\hat{T}}), \emptyset ) \overset{*}{\underset{\varPi }{\mapsto }} (L_1, L_2, L_3, L_4)\), \(AB \in L_1\) and the statement is true.

Induction hypothesis

Let us suppose that for every integer \(p \ge 1\) such that \(S \overset{p}{\underset{G}{\Rightarrow }} \alpha\), it also holds that \((\{S\},\emptyset ,({\hat{N}}\cup {\hat{T}}), \emptyset ) \overset{*}{\underset{\varPi }{\mapsto }} (L_1, L_2, L_3, L_4) \,\, \text {with} \,\, \alpha \in L_1 \cap (N \cup T)^*\)

Induction step

Let us suppose that \(S \overset{p}{\underset{G}{\Rightarrow }} \beta \underset{G}{\Rightarrow } \alpha\), with \(p \ge 1\). Here, \(\beta = \beta _1A\beta _2\) with \(\beta _1,\beta _2 \in (N\cup T)^*\) and \(A \in N\) and, by our induction hypothesis, \((\{S\},\emptyset ,({\hat{N}}\cup {\hat{T}}), \emptyset ) \overset{*}{\underset{\varPi }{\mapsto }} (L_1, L_2, L_3, L_4) \,\, \text {with} \,\, \beta _1A\beta _2 \in L_1 \cap (N \cup T)^*\). Now, we consider two cases to obtain \(\alpha\) from \(\beta _1A\beta _2\): First, \(A \rightarrow b \in P\) and \(\alpha =\beta _1b\beta _2\). In this case, the string \(\beta _1A\beta _2\) mutates to \(\beta _1b\beta _2\) in \(N_1\) given that \(A \rightarrow b \in M_1\). In the following communication step, \(\beta _1b\beta _2\) does not leave the processors \(N_1\) and the statement is true.

The second case is when \(A \rightarrow BC \in P\) and \(\alpha = \beta _1BC\beta _2\). Here, the string \(\beta _1A\beta _2\) is in processor \(N_1\) as it is established in our induction hypothesis, and it is transformed into the string \(\beta _1BC\beta _2\) through a sequence of operations in the processors \(N_2\), \(N_3\) and \(N_4\) as we have described before. The string \(\beta _1 BC \beta _2\) enters into the processor \(N_1\), and the statement holds.

The second part of the statement can be established as follows:

$$\begin{aligned} \text {if} \,\, (\{S\},A_2,\emptyset ) \overset{*}{\underset{\varPi }{\mapsto }}(L_1,L_2,L_3) \,\, \text {with} \,\, \alpha \in L_1 \cap (N \cup T)^* \,\, \text {then} \,\, S \overset{*}{\underset{G}{\Rightarrow }} \alpha . \end{aligned}$$

Here, we can carry out the induction proof in a way similar to the first part of the statement.

Given that every string \(w \in L(G)\) follows from \(S \overset{*}{\underset{G}{\Rightarrow }} w\), we have proved that there exists a configuration \((L_1,L_2,L_3,L_4)\) such that \(w \in L_1\) that can be obtained during the network computation and, consequently, \(w \in L(\varPi )\). Hence, the theorem is true. \(\square\)

The following class in the Chomsky hierarchy is the class of context-sensitive languages. In this case, we use part of the constructions that we have shown before. In Fig.  3, we show the network structure that we propose in the following result.

Fig. 3
figure 3

GNGP structure for context-sensitive grammars

Theorem 3

Every context-sensitive language can be generated by a GNGP with 6 processors.

Proof

Let \(G=(N,T,P,S)\) be an arbitrary grammar in Kuroda’s normal form. We propose the network \(\varPi =(V,N_{1},N_{2},N_{3},N_{4},N_{5},N_{6},K_6,id,N_1)\) with \(V = N \cup T \cup {\hat{N}} \cup {\hat{T}} \cup {\bar{N}} \cup {\bar{T}} \cup [NT] \cup [NN] \cup [TN] \cup [TT] \cup [NT]' \cup [NN]' \cup [TN]' \cup [TT]' \cup [[NN]] \cup [[NN]]^{f} \cup \overline{[[NN]]} \cup [NNN]^{l} \cup [NNN]^{r}\), where the alphabets are defined as in the proof of Theorem 2, and the new alphabets are defined as \([NNN]^l = \{ [ABC]^l : A,B,C \in N \}\) and \([NNN]^r = \{[ABC]^r : A,B,C \in N \}\) .

The processors are defined as follows:

  1. 1.

    \(N_{1}=(M_{1},\{S\},V,FI_{1},PO_{1},\emptyset ,m)\)

    \(\begin{array}{l} M_{1}= \{A \rightarrow [[BC]] : (A \rightarrow BC) \in P\} \cup \{A \rightarrow a : (A \rightarrow a) \in P\} \\ \qquad \cup \{A \rightarrow B : (A \rightarrow B) \in P\} \cup \{A \rightarrow [ACD]^l : \exists B \in N \wedge (AB \rightarrow CD) \in P\}\\ FI_{1}= {\bar{N}} \cup {\bar{T}} \cup {\hat{N}} \cup {\hat{T}} \cup [NT] \cup [NN] \cup [TN] \cup [TT] \cup [NN]' \cup [[NN]]^{f} \cup \overline{[[NN]]}\\ PO_{1}= [[NN]] \cup \{[ACD]^l : \exists B \in N \wedge (AB \rightarrow CD) \in P\}\\ \end{array}\)

  2. 2.

    \(N_{2}=(M_{2},\emptyset ,PI_{2},\emptyset ,V,FO_{2},m)\)

    \(\begin{array}{l} M_{2}=\{A \rightarrow [BA] : A,B \in (N \cup T)\} \cup \{A \rightarrow [BA]' : A,B \in (N \cup T)\}\\ \qquad \cup \{A \rightarrow {\bar{A}} : A \in (N \cup T)\} \cup \{[[AB]] \rightarrow \overline{[[AB]]} : A,B \in N\}\\ \qquad \cup \{[[AB]] \rightarrow [[AB]]^{f} : A,B \in N\}\\ PI_{2}=[[NN]]\\ FO_{2}=[[NN]] \cup N \cup T\\ \end{array}\)

  3. 3.

    \(N_{3}=(\emptyset ,({\hat{N}} \cup {\hat{T}}),PI_{3},FI_{3},PO_{3},\emptyset ,c)\)

    \(\begin{array}{l} PI_{3}= [NN]' \cup [NT]' \cup [TN]' \cup [TT]' \cup [[NN]]^{f}\\ FI_{3}=\{[AB][CD] : B \ne C\} \cup \{[AB][CD]' : B \ne C\} \cup \{\overline{[[AB]]}[CD] : B \ne C\}\\ \qquad \cup \{\overline{[[AB]]}[CD]' : B \ne C\} \cup \{[AB]\overline{[[CD]]} : A,B \in (N \cup T) \wedge C,D \in N\}\\ \qquad \cup \{[AB]'C : A,B \in (N \cup T) \wedge C \in V\} \cup \{{\bar{A}}[BC]' : A,B,C \in (N \cup T)\}\\ \qquad \cup \{{\bar{A}}[BC] : A,B,C \in (N \cup T)\} \cup \{[[AB]]^{f}C : A,B \in N \wedge C \in V\}\\ \qquad \cup \{[AB][[CD]]^{f} : A,B \in (N \cup T) \wedge C,D \in N\}\\ \qquad \cup N \cup T \cup {\hat{N}} \cup {\hat{T}}\\ PO_{3}=\{AB : A,B \in V\} \cup (V-({\hat{N}} \cup {\hat{T}}))\\ \end{array}\)

  4. 4.

    \(N_{4}=(M_{4},\emptyset ,PI_{4},\emptyset ,V,FO_{4},m)\)

    \(\begin{array}{l} M_{4}=\{[AB] \rightarrow A : A,B \in (N \cup T)\} \cup \{[AB]' \rightarrow A : A,B \in (N \cup T)\}\\ \qquad \cup \{\overline{[[AB]]} \rightarrow A : A,B \in N\} \cup \{[[AB]]^{f} \rightarrow A : A,B \in N\}\\ \qquad \cup \{{\hat{A}} \rightarrow A : A \in (N \cup T)\} \cup \{{\bar{A}} \rightarrow A : A \in (N \cup T)\}\\ PI_{4}=\{[[AB]]^{f}{\hat{B}} : A,B \in N\} \cup \{[AB]'{\hat{B}} : A,B \in (N \cup T)\}\\ FO_{4}={\hat{N}} \cup {\hat{T}} \cup {\bar{N}} \cup {\bar{T}} \cup [NN] \cup [NT] \cup [TN] \cup [TT] \cup \overline{[[NN]]}\\ \qquad \cup [NN]' \cup [NT]' \cup [TN]' \cup [TT]' \cup [[NN]]^{f}\\ \end{array}\)

  5. 5.

    \(N_{5}=(M_{5},\emptyset ,PI_{5},\emptyset ,V,\emptyset ,m)\)

    \(\begin{array}{l} M_{5}=\{B \rightarrow [BCD]^r : \exists A \in N \wedge (AB \rightarrow CD) \in P\}\\ PI_{5}=\{[ACD]^lB : (AB \rightarrow CD) \in P\}\\ \end{array}\)

  6. 6.

    \(N_{6}=(M_{5},\emptyset ,PI_{6},\emptyset ,V,FO_{6},m)\)

    \(\begin{array}{l} M_{6}=\{[ACD]^l \rightarrow C : \exists B \in N \text { with } (AB \rightarrow CD) \in P\}\\ \qquad \cup \{[BCD]^r \rightarrow D : \exists A \in N \text { with } (AB \rightarrow CD) \in P\}\\ PI_{6}=\{[ACD]^l[BCD]^r : (AB \rightarrow CD) \in P\}\\ FO_{6}=\{[ACD]^l : A,C,D \in N\} \cup \{[BCD]^r : B,C,D \in N\}\\ \end{array}\)

As in the proof of Theorem 2, the processor \(N_1\) collects the output strings. The network \(\varPi\) simulates the derivation process in the grammar G. Observe that G is in Kuroda Normal Form. Hence, the productions of the grammar can only be of the following forms:

  1. 1.

    \(A \rightarrow a\), with \(A \in N\) and \(a \in T\)

  2. 2.

    \(A \rightarrow B\), with \(A,B \in N\)

  3. 3.

    \(A \rightarrow BC\) with \(A,B,C \in N\)

  4. 4.

    \(AB \rightarrow CD\) with \(A,B,C,D \in N\)

For the case of productions in the form (1) and (3), the network carries out a set of operations that simulate the rule application as we have described in the proof of Theorem 2. In the case of productions of type (3), the processors \(N_1, N_2, N_3\) and \(N_4\) carry out the sequence of transformations previously described. For the case of productions of type (2), the networks directly applies this production at processor \(N_1\) in a way similar to productions of type (1).

Now, we focus on the productions of type (4). The first transformation is carried out at processor \(N_1\), where, for any production in the form \(AB \rightarrow CD\), the symbol A mutates to the symbol \([ACD]^l\). Then the string is sent out of processor \(N_1\) and it enters into processor \(N_5\) provided that the segment \([ACD]^lB\) appears in the string. Then, the symbol B mutates to \([BCD]^r\), the string is sent out of the processor \(N_5\) and it enters into processor \(N_6\) where \([ACD]^l\) mutates to C and \([BCD]^r\) mutates to D. So, the application of rule \(AB \rightarrow CD\) is completed and the transformed string returns to processor \(N_1\).

We must prove the following statement

$$\begin{aligned}&S \overset{*}{\underset{G}{\Rightarrow }} \alpha \,\, \text {iff} \,\, (\{S\},\emptyset ,({\hat{N}}\cup {\hat{T}}),\emptyset ,\emptyset , \emptyset ) \overset{*}{\underset{\varPi }{\mapsto }} (L_1, L_2, L_3, L_4,L_5,L_6) \,\, \\&\quad \text {with} \,\, \alpha \in L_1 \cap (N \cup T)^* \end{aligned}$$

The proof is similar as in Theorem 2, with the new rule applications that we have explained before. \(\square\)

Finally, we define a GNGP network for the last class in the Chomsky hierarchy, that is the phrase structure (non-restricted) grammars. In this case, we propose the network structure that is shown in the Fig.  4. Observe that we take advantage of the previously proposed topologies, and we add new processors in order to deal with grammar productions in the form \(AB \rightarrow B\). We enunciate the following theorem that can be considered as an universality result for the Generating Networks of Genetic Processors.

Fig. 4
figure 4

GNGP structure for phrase structure (non-restricted) grammars

Theorem 4

Every recursively enumerable language can be generated by a GNGP with 8 processors.

Proof

Let \(G=(N,T,P,S)\) be an arbitrary phrase structure (non-restricted) grammar with the productions in the form established at Sect.  2. We omit the case for the production \(S \rightarrow \varepsilon\).

We propose the network \(\varPi = (V,N_{1},N_{2},N_{3},N_{4},N_{5},N_{6},N_{7},N_{8},K_8,id,N_1)\), with \(V = N \cup T \cup {\hat{N}} \cup {\hat{T}} \cup {\bar{N}} \cup {\bar{T}} \cup {\widetilde{N}} \cup {\widetilde{T}} \cup [NT] \cup [NN] \cup [TN] \cup [TT] \cup [NT]' \cup [NN]' \cup [TN]' \cup [TT]' \cup [[NN]] \cup [[NN]]^f \cup \overline{[[NN]]} \cup [NNN]^l \cup [NNN]^r \cup \langle NN \rangle \cup \langle NT \rangle \cup \langle TN \rangle \cup \langle TT \rangle \cup \langle NX \rangle \cup \langle TX \rangle \cup \overline{\langle NN \rangle } \cup \overline{\langle NT \rangle } \cup \overline{\langle TN \rangle } \cup \overline{\langle TT \rangle } \cup \overline{\langle \langle NN \rangle \rangle } \cup \overline{\overline{\langle \langle NN \rangle \rangle }}\), where \(X \notin (T \cup N)\). In this case, the new alphabets are defined in a way similar to the previous results.

The processors are defined as follows:

  1. 1.

    \(N_{1}=(M_{1},\{S\},V,FI_{1},PO_{1},\emptyset ,m)\)

    \(\begin{array}{l} M_{1}=\{A \rightarrow [[BC]] : (A \rightarrow BC) \in P\} \cup \{A \rightarrow a : (A \rightarrow a) \in P\}\\ \qquad \cup \{A \rightarrow B : (A \rightarrow B) \in P\} \cup \{A \rightarrow \langle \langle AB \rangle \rangle : (AB \rightarrow B) \in P\}\\ \qquad \cup \{A \rightarrow [ACD]^l : \exists B \in N \text { with } (AB \rightarrow CD) \in P\} \\ FI_{1}= {\bar{N}} \cup {\bar{T}} \cup {\hat{N}} \cup {\hat{T}} \cup {\widetilde{N}} \cup {\widetilde{T}} \cup [NN] \cup [NT] \cup [TN] \cup [TT] \cup [NN] \\ \qquad \cup [[NN]]^f \cup \overline{[[NN]]} \cup \langle \langle NN \rangle \rangle \cup \langle NN \rangle \cup \langle NT \rangle \cup \langle TN \rangle \\ \qquad \cup \langle TT \rangle \cup \langle NX \rangle \cup \langle TX \rangle \cup \overline{\langle NN \rangle } \cup \overline{\langle NT \rangle } \cup \overline{\langle TN \rangle } \cup \overline{\langle TT \rangle } \\ PO_{1}=\{[ACD]^l : \exists B \in N \text { with } (AB \rightarrow CD) \in P\} \cup [[NN]] \cup \langle \langle NN \rangle \rangle \\ \end{array}\)

  2. 2.

    \(N_{2}=(M_{2},\emptyset ,PI_{2},\emptyset ,V,FO_{2},m)\)

    \(\begin{array}{l} M_{2}=\{A \rightarrow [BA] : A,B \in (N \cup T)\} \cup \{A \rightarrow [BA]' : A,B \in (N \cup T)\}\\ \qquad \cup \{A \rightarrow {\bar{A}} : A \in (N \cup T)\} \cup \{[[AB]] \rightarrow \overline{[[AB]]} : A,B \in N\}\\ \qquad \cup \{[[AB]] \rightarrow [[AB]]^{f} : A,B \in N\}\\ PI_{2}=[[NN]]\\ FO_{2}= N \cup T \cup [[NN]]\\ \end{array}\)

  3. 3.

    \(N_{3}=(\emptyset ,({\hat{N}} \cup {\hat{T}}),PI_{3},FI_{3},PO_{3},\emptyset ,c)\)

    \(\begin{array}{l} PI_{3}=[NN]' \cup [NT]' \cup [TN]' \cup [TT]' \cup [[NN]]^{f}\\ FI_{3}= N \cup T \cup {\hat{N}} \cup {\hat{T}} \cup \{[AB][CD] : B \ne C\} \cup \{[AB][CD]' : B \ne C\}\\ \qquad \cup \{\overline{[[AB]]}[CD] : B \ne C\} \cup \{\overline{[[AB]]}[CD]' : B \ne C\}\\ \qquad \cup \{[AB]\overline{[[CD]]} : A,B \in (N \cup T) \wedge C,D \in N\}\\ \qquad \cup \{[AB]'C : A,B \in (N \cup T) \wedge C \in V\}\\ \qquad \cup \{{\bar{A}}[BC]' : A,B,C \in (N \cup T)\}\\ \qquad \cup \{{\bar{A}}[BC] : A,B,C \in (N \cup T)\}\\ \qquad \cup \{[[AB]]^{f}C : A,B \in N \wedge C \in V\}\\ \qquad \cup \{[AB][[CD]]^{f} : A,B \in (N \cup T) \wedge C,D \in N\}\\ PO_{3}=\{AB : A,B \in V\} \cup (V-({\hat{N}} \cup {\hat{T}}))\\ \end{array}\)

  4. 4.

    \(N_{4}=(M_{4},\emptyset ,PI_{4},FI_{4},V,FO_{4},m)\)

    \(\begin{array}{l} M_{4}=\{[AB] \rightarrow A : A,B \in (N \cup T)\} \cup \{[AB]' \rightarrow A : A,B \in (N \cup T)\}\\ \qquad \cup \{\overline{[[AB]]} \rightarrow A : A,B \in N\} \cup \{[[AB]]^{f} \rightarrow A : A,B \in N\}\\ \qquad \cup \{{\hat{A}} \rightarrow A : A \in (N \cup T)\} \cup \{{\bar{A}} \rightarrow A : A \in (N \cup T)\}\\ \qquad \cup \{{\widetilde{A}} \rightarrow A : A \in (N \cup T)\} \cup \{\overline{\langle \langle AB \rangle \rangle } \rightarrow B : A,B \in N\}\\ \qquad \cup \{\overline{\overline{\langle \langle AB \rangle \rangle }} \rightarrow B : A,B \in N\} \cup \{\overline{\langle AB \rangle } \rightarrow B : A,B \in (N \cup T)\}\\ \qquad \cup \{\langle AB \rangle \rightarrow B : A,B \in (N \cup T)\}\\ PI_{4}=\{[[AB]]^{f}{\hat{B}} : A,B \in N\} \cup \{[AB]'{\hat{B}} : A,B \in (N \cup T)\} \cup \overline{\langle \langle NN \rangle \rangle }\\ \qquad \cup \overline{\overline{\langle \langle NN \rangle \rangle }}\\ FI_{4}=\{\overline{\langle AB \rangle }C : A,B \in N \wedge C \in V\} \cup \{\overline{\overline{\langle \langle AB \rangle \rangle }}C : A,B \in N \wedge C \in V\}\\ FO_{4}= {\hat{N}} \cup {\hat{T}} \cup {\bar{N}} \cup {\bar{T}} \cup {\widetilde{N}} \cup {\widetilde{T}} \cup [NN] \cup [NT] \cup [TN] \cup [TT] \cup \overline{[[NN]]}\\ \qquad \cup [NN]' \cup [NT] \cup [TN]' \cup [TT]' \cup [[NN]]^{f} \cup \langle NN \rangle \cup \langle NT \rangle \cup \langle TN \rangle \\ \qquad \cup \langle TT \rangle \cup \overline{\langle NN \rangle } \cup \overline{\langle NT \rangle } \cup \overline{\langle TN \rangle } \cup \overline{\langle TT \rangle } \cup \overline{\langle \langle NN \rangle \rangle }\cup \overline{\overline{ \langle \langle NN \rangle \rangle }}\\ \end{array}\)

  5. 5.

    \(N_{5}=(M_{5},\emptyset ,PI_{5},\emptyset ,V,\emptyset ,m)\)

    \(\begin{array}{l} M_{5}=\{B \rightarrow [BCD]^r : \exists A \in N \text { with } (AB \rightarrow CD) \in P\}\\ PI_{5}=\{[ACD]^lB : (AB \rightarrow CD) \in P\}\\ \end{array}\)

  6. 6.

    \(N_{6}=(M_{5},\emptyset ,PI_{6},\emptyset ,V,FO_{6},m)\)

    \(\begin{array}{l} M_{6}=\{[ACD]^l \rightarrow C : \exists B \in N \text { with } (AB \rightarrow CD) \in P\}\\ \qquad \cup \{[BCD]^r \rightarrow D : \exists A \in N \text { with } (AB \rightarrow CD) \in P\}\\ PI_{6}=\{[ACD]^l[BCD]^r : (AB \rightarrow CD) \in P\}\\ FO_{6}=[NNN]^l \cup [NNN]^r\\ \end{array}\)

  7. 7.

    \(N_{7}=(M_{7},\emptyset ,PI_{7},\emptyset ,V,FO_{7},m)\)

    \(\begin{array}{l} M_{7}=\{A \rightarrow {\widetilde{A}} : A \in (N \cup T)\} \cup \{A \rightarrow \langle AB \rangle : A,B \in (N \cup T)\}\\ \qquad \cup \{A \rightarrow \overline{\langle AB \rangle } : A,B \in (N \cup T)\} \cup \{A \rightarrow \langle AX \rangle : A \in (N \cup T)\}\\ \qquad \cup \{\langle \langle AB \rangle \rangle \rightarrow \overline{\langle \langle AB \rangle \rangle } : A,B \in N\} \cup \{\langle \langle AB \rangle \rangle \rightarrow \overline{\overline{\langle \langle AB \rangle \rangle }} : A,B \in N\}\\ PI_{7}=\{\langle \langle AB \rangle \rangle B : (AB \rightarrow B) \in P\}\\ FO_{7}= N \cup T \cup \langle \langle NN \rangle \rangle \\ \end{array}\)

  8. 8.

    \(N_{8}=(\emptyset ,\emptyset ,PI_{8},FI_{8},V,\emptyset ,c)\)

    \(\begin{array}{l} PI_{8}=\overline{\langle \langle NN \rangle \rangle } \cup \overline{\overline{\langle \langle NN \rangle \rangle }}\\ FI_{8}=\{\overline{\langle \langle AB \rangle \rangle }{\widetilde{C}} : A,B \in N \wedge {\widetilde{C}} \in ({\widetilde{N}} \cup {\widetilde{T}})\}\\ \qquad \cup \{\langle AX \rangle B : A \in (N \cup T) \wedge B \in V\}\\ \qquad \cup \{\langle AB \rangle {\widetilde{C}} : A,B,C \in (N \cup T)\}\\ \qquad \cup \{{\widetilde{C}}\langle AB \rangle : A,C \in (N \cup T) \wedge B \in (N \cup T \cup \{X\})\}\\ \qquad \cup \{\overline{\langle AB\rangle }{\widetilde{C}} : A,B,C \in (N \cup T)\}\\ \qquad \cup \{{\widetilde{C}}\overline{\langle AB \rangle } : A,B,C \in (N \cup T)\}\\ \qquad \cup \{\overline{\langle AB \rangle } \langle CD \rangle : A,B,C,D \in (N \cup T)\}\\ \qquad \cup \{\overline{\langle AB \rangle } \overline{\langle CD \rangle } : A,B,C,D \in (N \cup T)\}\\ \qquad \cup \{\overline{\langle AB \rangle } \overline{\langle \langle CD \rangle \rangle } : A,B \in (N \cup T) \wedge C,D \in N\}\\ \qquad \cup \{\overline{\langle \langle AB \rangle \rangle } \langle CD \rangle : B \ne C\} \cup \{\overline{\langle \langle AB \rangle \rangle } \overline{\langle CD \rangle } : B \ne C\}\\ \qquad \cup \{\overline{\langle AB \rangle } \langle CX \rangle : B \ne C\} \cup \{\langle AB \rangle \langle CD \rangle : B \ne C\}\\ \qquad \cup \{\langle AB \rangle \overline{\langle CD \rangle } : B \ne C\}\\ \qquad \cup \{\overline{\langle \langle AB \rangle \rangle } \langle CX \rangle : A,B \in N \wedge C \in (N \cup T)\}\\ \qquad \cup \{\overline{\overline{\langle \langle AB \rangle \rangle }}CD : A,B \in N \wedge C,D \in V\} \\ \qquad \cup \{\overline{\overline{\langle \langle AB \rangle \rangle }}{\widetilde{C}} : A,B \in N \wedge {\widetilde{C}} \in ({\widetilde{N}} \cup {\widetilde{T}})\}\\ \qquad \cup \{\overline{\overline{\langle \langle AB \rangle \rangle }} \langle CD \rangle : A,B \in N \wedge C,D \in (N \cup T)\}\\ \qquad \cup \{\langle CD \rangle \overline{\overline{\langle \langle AB \rangle \rangle }} : A,B \in N \wedge C,D \in (N \cup T)\}\\ \qquad \cup \{\overline{\overline{\langle \langle AB\rangle \rangle }} \overline{\langle CD \rangle } : A,B \in N \wedge C,D \in (N \cup T)\}\\ \qquad \cup \{\overline{\langle CD \rangle } \overline{\overline{\langle \langle AB \rangle \rangle }} : A,B \in N \wedge C,D \in (N \cup T)\} \end{array}\)

In the proposed network we use the structure that we have established at Theorem 3, and we introduce new processors, filters and mutation rules in order to apply the grammar rules in the form \(AB \rightarrow B\). We can summarize the rules application as follows: The rules in the form \(A \rightarrow a\) or \(A \rightarrow B\) are directly applied in processor \(N_1\) through mutation rules. The rules in the form \(A \rightarrow BC\) are simulated by the processors \(N_1, N_2, N_3\) and \(N_4\) in a way similar as in Theorem 2 and Theorem 3. The rules in the form \(AB \rightarrow AC\) and \(AB \rightarrow CB\) are simulated by the processors \(N_1, N_5\) and \(N_6\) in a way similar as in Theorem 3 (observe that these rules are a restricted case of the rules in the form \(AB \rightarrow CD\)). Finally, the rules in the form \(AB \rightarrow C\) are simulated as follows: First, at processor \(N_1\), the symbol A mutates to the symbol \(\langle \langle AB \rangle \rangle\), and the mutated string is sent out of the processor \(N_1\). The string enters into the processor \(N_7\) provided that it contains the segment \(\langle \langle AB \rangle \rangle B\). At processor \(N_7\) the string \(\alpha \langle \langle AB \rangle \rangle B A_1 A_2 \ldots A_n\) mutates to \({\widetilde{\alpha }} \overline{\langle \langle AB \rangle \rangle } \langle B A_1 \rangle \langle A_1 A_2 \rangle \langle A_2 A_3 \rangle \ldots \overline{\langle A_{n-1} A_n \rangle } \langle A_n X \rangle\). Observe that if B is the symbol at the rightmost position then the mutated string should be \({\widetilde{\alpha }} \overline{\overline{\langle \langle AB \rangle \rangle }} \langle B X \rangle\). The string is sent out of the processor \(N_7\) and it enters into the processor \(N_8\) where only crossover is applied in order to eliminate the last symbol of the string. Observe that in processor \(N_8\) only self-crossover is carried out, given that the only string at processor is the mutated one. Finally, after the last symbol elimination, the string enters into processor \(N_4\) where all the marked symbols are restored to the symbols of the grammar and the string is sent out to the processor \(N_1\).

As in the previous theorems we can enunciate and prove the following statement:

$$\begin{aligned}&S \overset{*}{\underset{G}{\Rightarrow }} \alpha \,\, \text {iff} \,\, (\{S\},\emptyset ,({\hat{N}}\cup {\hat{T}}),\emptyset ,\emptyset , \emptyset , \emptyset , \emptyset ) \overset{*}{\underset{\varPi }{\mapsto }} (L_1, L_2, L_3, L_4,L_5,L_6, L_7, L_8) \\&\quad \,\, \text {with} \,\, \alpha \in L_1 \cap (N \cup T)^* \end{aligned}$$

\(\square\)

5 Further remarks and conclusions

First, we remark some achievements of this work: we have proposed the Networks of Genetic Processors as a generative model of computation. In addition, we have justified its definition as parallel genetic algorithms that act with certain restrictions when applying genetic operations, fitness selection and migration procedures between populations. This allows us to see parallel genetic algorithms as computational mechanisms for information generation. We have carried out a study about the generative capacity of the model based on the number of processors that act simultaneously. In our case, the research framework has been that of formal language theory, which is a valid operating framework because it covers all computational processes from the point of view of theoretical computer science. We have been able to prove that three, four, six and eight processors are sufficient to generate the classes of languages according to Chomsky hierarchy which is a generally accepted framework for the study of computatbility theory.

Regarding some improvements that we can address on our proposal, provided that the unitary productions \(A \rightarrow B\) with \(A,B \in N\) can be eliminated in the grammar, then the mutation rules \(A \rightarrow B\) can be removed from the processors. Observe that the formulation of new normal forms for the grammars in the Chomsky hierarchy, can lead to new network structures. We think that the proposed networks are optimal with respect to the number of the processors for every language class, and we will analyze the question in future works. Nevertheless, this is not the case for the alphabet of the network and the filters used to apply the grammar productions. We think that these parameters should be deeply studied in order to produce optimal solutions for the descriptive complexity of the proposed model.

Finally, we would like to remark the roles of the operations in the network: The crossover operation is used only to add or remove new symbols in the strings, while the mutation rules together with the input and output filters are the main core of the processors to apply the grammar rules. Hence, the set of strings of a predefined length obtained in the grammar could be generated by applying only mutation rules. This opens a new aspect of Networks of Bio-inspired Processors in order to propose a complexity measure based in a (semi)uniform approach.