def vectorial_delete_one_subtree(self, state):

        # here i make only crossovers between eqs1 resp. and eqs 2

        prev_state = copy.deepcopy(state)

        game = Game(self.voc, prev_state)

        ast = game.convert_to_ast()
        rpn = prev_state.reversepolish
        #print('entering delete with', game.state.reversepolish, game.state.formulas)

        # throw away the last '1' (== halt) if exists:
        if rpn[-1] == 1:
            array = np.asarray(rpn[:-1])
        else:
            array = np.asarray(rpn)

        start = 2

        # get all topnodes of possible subtrees
        positions = np.where(array >= start)[0]

        if positions.size > 0:
            maxretries = 10
            gotone = False
            count = 0
            while gotone is False and count < maxretries:
                which = np.random.choice(positions)
                getnonleafnode = which + 1
                # get the node
                operatornode = ast.from_ast_get_node(ast.topnode,
                                                     getnonleafnode)[0]
                before_swap_rpn = ast.from_ast_to_rpn(operatornode)
                bfstate = State(self.voc, before_swap_rpn, self.calculus_mode)
                bef_game = Game(self.voc, bfstate)
                _, vec_number, _ = bef_game.from_rpn_to_critical_info()
                grandparent = operatornode.parent
                count += 1
                if before_swap_rpn[
                        -1] in self.voc.arity2symbols and grandparent is not None:
                    gotone = True
                    count = 0
                    for child in grandparent.children:
                        if child == operatornode:
                            index = count
                        count += 1

            if gotone == False:
                return False, prev_state

            else:
                #print('le node selectionne est', ast.from_ast_to_rpn(operatornode))
                #print('fils gauche', ast.from_ast_to_rpn(operatornode.children[0]))
                #print('fils droit', ast.from_ast_to_rpn(operatornode.children[1]))

                #print('ready:', before_swap_rpn, bef_game.state.formulas)
                vecs = []
                for child in operatornode.children:
                    rpnchild = ast.from_ast_to_rpn(child)
                    #print('ici', rpnchild)
                    statechild = State(self.voc, rpnchild, self.calculus_mode)
                    gamechild = Game(self.voc, statechild)
                    _, vec_number, _ = gamechild.from_rpn_to_critical_info()
                    vecs.append(vec_number)

                #print('then vec numbers', vecs)
                if vecs == [0, 0]:
                    if random.random() < 0.5:
                        newnode = operatornode.children[0]
                        #print('delete right')
                    else:
                        newnode = operatornode.children[1]
                        #print('delete left')

                elif vecs == [0, 1]:
                    newnode = operatornode.children[1]
                    #print('delete left')

                elif vecs == [1, 0]:
                    newnode = operatornode.children[0]
                    #print('delete right')

                elif vecs == [1, 1] and before_swap_rpn[
                        -1] != self.voc.dot_number:  #exclude dot product
                    if random.random() < 0.5:
                        newnode = operatornode.children[0]
                        #print('delete right')

                    else:
                        newnode = operatornode.children[1]
                        #print('delete left')

                else:  #le cas du doot product
                    return False, prev_state

                grandparent.children[index] = newnode
                # get the new reversepolish:
                newrpn = ast.from_ast_to_rpn(ast.topnode)

        # else cant delete tree
        else:
            return False, prev_state

        # returns the new states
        state = State(self.voc, newrpn, self.calculus_mode)
        #print('finally', state.reversepolish, state.formulas)
        #game = Game(self.voc, state)
        #game.from_rpn_to_critical_info()
        #print('bug?')

        return True, state
    def vectorial_crossover(self, state1, state2):

        # here i make only crossovers between eqs1 resp. and eqs 2

        prev_state1 = copy.deepcopy(state1)
        prev_state2 = copy.deepcopy(state2)

        game1 = Game(self.voc, prev_state1)
        game2 = Game(self.voc, prev_state2)

        ast1 = game1.convert_to_ast()
        ast2 = game2.convert_to_ast()

        rpn1 = prev_state1.reversepolish
        rpn2 = prev_state2.reversepolish

        # throw away the last '1' (== halt) if exists:
        if rpn1[-1] == 1:
            array1 = np.asarray(rpn1[:-1])
        else:
            array1 = np.asarray(rpn1)

        if rpn2[-1] == 1:
            array2 = np.asarray(rpn2[:-1])
        else:
            array2 = np.asarray(rpn2)

        # topnode has the max absolute label, so you dont want it/ you want only subtrees, hence the [:-1]
        # subtrees can be scalars == leaves, hence >= 2
        start = 2  # + len(self.voc.arity0symbols)

        # get all topnodes of possible subtrees
        positions1 = np.where(array1 >= start)[0][:-1]
        positions2 = np.where(array2 >= start)[0][:-1]

        if positions1.size > 0 and positions2.size > 0:
            # choose two
            which1 = np.random.choice(positions1)
            which2 = np.random.choice(positions2)

            getnonleafnode1 = which1 + 1
            getnonleafnode2 = which2 + 1

            # get the nodes
            node1 = ast1.from_ast_get_node(ast1.topnode, getnonleafnode1)[0]
            node2 = ast2.from_ast_get_node(ast2.topnode, getnonleafnode2)[0]

            before_swap_rpn1 = ast1.from_ast_to_rpn(node1)
            before_swap_rpn2 = ast2.from_ast_to_rpn(node2)

            bfstate1 = State(self.voc, before_swap_rpn1, self.calculus_mode)
            bfstate2 = State(self.voc, before_swap_rpn2, self.calculus_mode)

            bef_game1 = Game(self.voc, bfstate1)
            bef_game2 = Game(self.voc, bfstate2)

            _, vec_number1, _ = bef_game1.from_rpn_to_critical_info()
            _, vec_number2, _ = bef_game2.from_rpn_to_critical_info()

            if vec_number1 == vec_number2:
                # swap parents and children == swap subtrees
                prev1 = node1.parent
                c = 0
                for child in prev1.children:
                    if child == node1:
                        prev1.children[c] = node2
                    c += 1

                c = 0
                prev2 = node2.parent
                for child in prev2.children:
                    if child == node2:
                        prev2.children[c] = node1
                    c += 1

                # get the new reversepolish:
                rpn1 = ast1.from_ast_to_rpn(ast1.topnode)
                rpn2 = ast2.from_ast_to_rpn(ast2.topnode)

                # but dont crossover at all if the results are eqs longer than maximal_size (see GP_QD) :
                if len(rpn1) > self.maximal_size or len(
                        rpn2) > self.maximal_size:
                    return False, prev_state1, prev_state2
            else:  #cant crossover vector and scalar
                return False, prev_state1, prev_state2

        # else cant crossover
        else:
            return False, prev_state1, prev_state2

        # returns the new states
        state1 = State(self.voc, rpn1, self.calculus_mode)
        state2 = State(self.voc, rpn2, self.calculus_mode)

        if self.usesimplif:
            state1 = game_env.simplif_eq(self.voc, state1)
            state2 = game_env.simplif_eq(self.voc, state2)

            # game1 = Game(self.voc, state1)
            # game1.simplif_eq()
            # state1 = game1.state

            # game2 = Game(self.voc, state2)
            # game2.simplif_eq()
            # state2 = game2.state
        game1 = Game(self.voc, state1)
        game2 = Game(self.voc, state2)
        #print('checkcrossovers enter with', game1.state.reversepolish)

        # print('checkcrossovers end with', game11.state.reversepolish)
        toreturn = []

        # crossover can lead to true zero division thus :
        if self.voc.infinite_number in state1.reversepolish:
            toreturn.append(prev_state1)
            # print('fail')

        # also, if it returns too many nested functions, i dont want it (sort of parsimony)
        elif game1.getnumberoffunctions() > config.MAX_DEPTH:
            toreturn.append(prev_state1)
            # print('fail')
        else:
            toreturn.append(state1)
            # print('succes')

        if self.voc.infinite_number in state2.reversepolish:
            toreturn.append(prev_state2)
            # print('fail')

        elif game2.getnumberoffunctions() > config.MAX_DEPTH:
            toreturn.append(prev_state2)
            # print('fail')

        else:
            toreturn.append(state2)
            # print('succes')

        return True, toreturn[0], toreturn[1]