def changeRandomModule(self,pString):
        pString = ParametricString.copyFrom(pString)
        available_letters = [m.letter for m in self.template_modules_library.getTemplateModules()]

        # Choose what module we want to change
        modules = pString.getActualModules()
        modules = list(filter(lambda m: m.letter in available_letters,modules))
        index = self.rnd.randint(0,len(modules)-1)
        module_to_change = modules[index]
        #print("We will change module at : " + str(index) + " " + str(module_to_change))

        # Choose what we will change it to, avoid replacing with the same letter
        new_module = self.generateRandomModule(notUsingModules = [module_to_change])
        #print("Changed to " + str(new_module))

        # If parameterized, we make sure that the parameter value remains the same, if possible
        if self.parameterized:
            for i in range(len(new_module.params)):
                if i < len(module_to_change.params):
                    new_module.params[i] = module_to_change.params[i]

        #print("From string " + str(string) + " we change module " + str(string[index]) + " at index " + str(index) + " to a new module " + new_module)
        pString.modulesList[pString.modulesList.index(module_to_change)] = new_module
        #print("Result: " + string)
        return pString
 def setAxiomFromString(self,textString):
     """
     @param textString: Initial string to parse
     @type textString: str
     """
     newPString = ParametricString.fromTextString(textString)
     newPString.setGlobals(self.globalDefines)
     self.axiom = newPString
 def removeModule(self,module,input_pstring):
     #print(module)
     #print(pString)
     output_pstring = ParametricString.copyFrom(input_pstring)
     if module in input_pstring.modulesList:
         index = input_pstring.index(module)
         removeBrackets = self.checkBracketsRemoval(index,output_pstring)
         del output_pstring.modulesList[index]
         if removeBrackets: self.performBracketsRemoval(index,output_pstring)
     return output_pstring
    def removeRandomModule(self,pString):
        pString = ParametricString.copyFrom(pString)
        available_letters = [m.letter for m in self.template_modules_library.getTemplateModules()]
        while True:
            index = self.rnd.randint(0,len(pString)-1)
            if not pString[index].isBracket() and pString[index].letter in available_letters: break

        # We also remove the brackets if no other module is there
        removeBrackets = self.checkBracketsRemoval(index, pString)
        del pString.modulesList[index]
        if removeBrackets: self.performBracketsRemoval(index, pString)
        #TODO: Do something if we completely remove this production
        return pString
    def addRandomModule(self,pString):
        """
        Add a random Module to a ParametricString, chosen from the available ones.
        This may select an unused Module too.
        #TODO: this is actually an "insertInRandomModule"
        """
        #print("Current pString: " + str(pString))
        pString = ParametricString.copyFrom(pString)
        new_module = self.generateWeightedRandomModule()#parametric=True)
        index = self.rnd.randint(0,len(pString))    # Max is len(pString) so that we can also insert at the end
        #print("From string " + str(pString) + " we add at index " + str(index) + " a new Module " + str(new_module))
        pString.modulesList.insert(index,new_module)
        #print("Result: " + str(pString))

        if new_module.letter not in self.currentlyUsedLetters:
            self.currentlyUsedLetters.append(new_module.letter)

        return pString
 def iterate_loop(self, N):
     if N is None: N = self.niterations
     currentParametricString = ParametricString.copyFrom(self.axiom) # We create a copy so to not modify the axiom
     #self.axiom.evaluateDefines()
     #print(self)
     #print(self.globalDefines)
     for i in range(N):
         if self.verbose: print("\nStep " + str(i+1))
         currentParametricString.resetConversions()
         # All productions are applied in parallel
         for prod in self.productions:
             if self.verbose: print("Rule: " + str(prod))
             result = prod.check(currentParametricString,self.rnd)
             #print("Rule evaluates: " +  str(result))
             if result:  currentParametricString = prod.convert(currentParametricString)
         if self.verbose: print("String at step " + str(i+1) + " is " + str(currentParametricString))
         ParametricProduction.resetStochasticState()
     currentParametricString.evaluateDefines()
     return currentParametricString
 def parseSuccessorString(self,string):
     successor = ParametricString()
     successor.setGlobals(self.globalDefines)
     successor.parseString(string)
     return successor
 def parsePredecessorString(self,string):
     predecessorPString = ParametricString()
     predecessorPString.setGlobals(self.globalDefines)
     predecessorPString.parseString(string)    # TODO: Maybe this predecessor should be treated as a 1-module string for consistency, instead of a module?
     assert len(predecessorPString) == 1, 'The predecessor must contain only one module!'
     return predecessorPString[0]   # Only one
 def __init__(self):
     ParametricString.__init__(self)
    print("\nChange predecessor: parametric")
    pm = ParametricModule.fromTextString("A(x)")
    pp.setPredecessorModule(pm)
    print(pp)
    print(pm.letter)

    print("\nChange condition: probability")
    pp.setConditionFromString("0.8")
    print(pp)

    print("\nChange condition: parametric")
    pp.setConditionFromString("x>0.9")
    print(pp)

    print("\nChange successor: parametric")
    ps = ParametricString.fromTextString('F(x)A(p)')
    pp.setSuccessorPstring(ps)
    print(pp)

    import random
    rnd = random.Random()
    print("\nCheck condition")
    ps = ParametricString.fromTextString("A(1)")
    print("Input: " + str(ps))
    result = pp.check(ps, rnd)
    print("Result: " + str(result))

    print("\nConvert and evaluate  (also globals)")
    print("Input: " + str(ps))
    ps = pp.convert(ps)
    print("Result: " + str(ps))
 def insertModuleIntoPstringRandomly(self,new_module,pString):
     pString = ParametricString.copyFrom(pString)
     index = self.rnd.randint(0,len(pString))    # Max is len(pString) so that we can also insert at the end
     pString.modulesList.insert(index,new_module)
     if new_module.letter not in self.currentlyUsedLetters:  self.currentlyUsedLetters.append(new_module.letter)
     return pString
 def appendModuleToPstring(self,new_module,pString):
     pString = ParametricString.copyFrom(pString)
     pString.modulesList.append(new_module)
     if new_module.letter not in self.currentlyUsedLetters:  self.currentlyUsedLetters.append(new_module.letter)
     return pString
 def generateEmptyParametricString(self):
     pstring = ParametricString()
     pstring.setGlobals(self.lsystem.globalDefines)
     return pstring
    def generateRandomParametricString(self, minLength = MIN_GENERATED_STRING_LENGTH, maxLength = MAX_GENERATED_STRING_LENGTH, predecessor_module = None):
        """
        Generates a random string composed of ParametricModules.
        May also randomly open and close branches.
        May also randomly add new defines.
        Forces the string's validity.

        If a predecessor_module is passed, its parameter variables (x,y) need to appear in the generated string
        We add them to the current generated string at the end.
        """
        if self.branchProbability > 0.0: openBranches = 0
        n_modules = self.rnd.randint(minLength,maxLength)
        pstring = ParametricString()
        pstring.setGlobals(self.lsystem.globalDefines)

        for i in range(n_modules):  # We add N modules

            # Generate the module
            new_module = self.generateWeightedRandomModule()#parametric=True)

            # Randomly open branches (NOT: only if the module is a new rotation, otherwise it doesn't make sense)
            if self.branchProbability > 0.0:
                if openBranches > 0 and self.rnd.random() < self.branchCloseProbability:
                    pstring.appendCloseBranch()
                    openBranches -= 1
                if self.rnd.random() < self.branchProbability:   #new_module.isOrientation() and
                    pstring.appendOpenBranch()
                    openBranches += 1

            # Append the module
            pstring.appendModule(new_module)

        # Close the remaining branches
        if self.branchProbability > 0.0:
            for i in range(openBranches): pstring.appendCloseBranch()

        # Change some of the parameters to the predecessor module's variable parameters
        if self.parameterized:
            print("PRED: " + str(predecessor_module))
            if predecessor_module is not None:
                potential_changed_modules = pstring.modulesList
                potential_changed_modules = list(filter(lambda p: not p.isBracket(), pstring.modulesList))

                #print "Potential changed modules: "
                #for m in potential_changed_modules: print m

                # Each predecessor parameter is copied once, if possible
                for param in predecessor_module.params:
                    chosen_module = self.getRandomItemFromList(potential_changed_modules)
                    #if len(chosen_module.params) > 0:
                    index = self.rnd.randint(0,len(chosen_module.params)-1)
                    chosen_module.params[index] = param

        return pstring