Ignore:
Timestamp:
06/30/20 00:32:56 (4 years ago)
Author:
Maciej Komosinski
Message:

fS: preserved volume during shape-type changes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpp/frams/genetics/fS/fS_oper.cpp

    r967 r969  
    1515                                {"fS_mut_rem_part",         0, 0, "Remove part",              "f 0 100 10", FIELD(prob[FS_REM_PART]),             "mutation: probability of deleting a part",},
    1616                                {"fS_mut_mod_part",         0, 0, "Modify part",              "f 0 100 10", FIELD(prob[FS_MOD_PART]),             "mutation: probability of changing the part type",},
    17                                 {"fS_mut_add_joint",        0, 0, "Add joint",                "f 0 100 10", FIELD(prob[FS_ADD_JOINT]),            "mutation: probability of adding a joint",},
    18                                 {"fS_mut_rem_joint",        0, 0, "Remove joint",             "f 0 100 10", FIELD(prob[FS_REM_JOINT]),            "mutation: probability of removing a joint",},
     17                                {"fS_mut_change_joint",        0, 0, "Change joint",                "f 0 100 10", FIELD(prob[FS_CHANGE_JOINT]),            "mutation: probability of changing a joint",},
    1918                                {"fS_mut_add_param",        0, 0, "Add param",                "f 0 100 10", FIELD(prob[FS_ADD_PARAM]),            "mutation: probability of adding a parameter",},
    2019                                {"fS_mut_rem_param",        0, 0, "Remove param",             "f 0 100 10", FIELD(prob[FS_REM_PARAM]),            "mutation: probability of removing a parameter",},
     
    4140        par.select(this);
    4241        par.setDefault();
    43         supported_format = "S";
     42        supported_format = 'S';
    4443}
    4544
     
    5352                {
    5453                        logPrintf("GenoOper_fS", "checkValidity", LOG_ERROR, "Invalid part size");
    55                         return 1 + errorPosition;
     54                        return errorPosition;
    5655                }
    5756        }
     
    9291                        result = changePartType(genotype, availableTypes);
    9392                        break;
    94                 case FS_ADD_JOINT:
    95                         result = addJoint(genotype);
    96                         break;
    97                 case FS_REM_JOINT:
    98                         result = removeJoint(genotype);
     93                case FS_CHANGE_JOINT:
     94                        result = changeJoint(genotype);
    9995                        break;
    10096                case FS_ADD_PARAM:
     
    214210const char* GenoOper_fS::getSimplest()
    215211{
    216         return "S:C{x=0.80599;y=0.80599;z=0.80599}";
     212        return "C{x=0.80599;y=0.80599;z=0.80599}";
    217213}
    218214
     
    233229                style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_NONE);
    234230        }
    235         else if (isdigit(ch) || strchr(".=", ch)) // Numerical value
     231        else if (isdigit(ch) || strchr(".", ch)) // Numerical value
    236232        {
    237233                style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_NONE);
    238234        }
    239         else if(strchr("()_;[],", ch))
     235        else if(strchr("()_;[],=", ch))
    240236        {
    241237                style = GENSTYLE_CS(0, GENSTYLE_BOLD); // Important char
     
    292288
    293289        Substring substring(&partType, 0, 1);
    294         Node *newNode = new Node(substring, node->modifierMode, node->paramMode, node->cycleMode, node);
     290        Node *newNode = new Node(substring, node);
    295291        // Add random rotation
    296292        string rotationParams[]{ROT_X, ROT_Y, ROT_Z};
     
    298294        {
    299295                for(int i=0; i < 3; i++)
    300                         newNode->params[rotationParams[i]] = RndGen.Uni(-90, 90);
     296                        newNode->params[rotationParams[i]] = RndGen.Uni(-M_PI / 2, M_PI / 2);
    301297        }
    302298        else
    303299        {
    304300                string selectedParam = rotationParams[rndUint(3)];
    305                 newNode->params[selectedParam] = RndGen.Uni(-90, 90);
     301                newNode->params[selectedParam] = RndGen.Uni(-M_PI / 2, M_PI / 2);
    306302        }
    307303        string rParams[]{RX, RY, RZ};
     
    309305        {
    310306                for(int i=0; i < 3; i++)
    311                         newNode->params[rParams[i]] = RndGen.Uni(-90, 90);
     307                        newNode->params[rParams[i]] = RndGen.Uni(-M_PI / 2, M_PI / 2);
    312308        }
    313309        else
    314310        {
    315311                string selectedParam = rParams[rndUint(3)];
    316                 newNode->params[selectedParam] = RndGen.Uni(-90, 90);
     312                newNode->params[selectedParam] = RndGen.Uni(-M_PI / 2, M_PI / 2);
    317313        }
    318314        // Assign part size to default value
     
    324320        double relativeVolume = volume / volumeMultiplier;    // Volume without applying modifiers
    325321
    326         double newRadius = Node::calculateRadiusFromVolume(newNode->partType, relativeVolume);
     322        double newRadius = std::cbrt(relativeVolume / volumeMultipliers.at(newNode->partType));
    327323        newNode->params[SIZE_X] = newRadius;
    328324        newNode->params[SIZE_Y] = newRadius;
     
    333329        {
    334330                geno.getState();
    335                 newNode->changeSizeParam(SIZE_X, fS_Genotype::randomParamMultiplier(), true);
    336                 newNode->changeSizeParam(SIZE_Y, fS_Genotype::randomParamMultiplier(), true);
    337                 newNode->changeSizeParam(SIZE_Z, fS_Genotype::randomParamMultiplier(), true);
     331                newNode->changeSizeParam(SIZE_X, true);
     332                newNode->changeSizeParam(SIZE_Y, true);
     333                newNode->changeSizeParam(SIZE_Z, true);
    338334        }
    339335        return true;
     
    374370                int index = rndUint(availTypesLength);
    375371                if (availTypes[index] == SHAPETYPE_TO_GENE.at(randomNode->partType))
    376                         index = (index + 1 + rndUint(availTypesLength)) % availTypesLength;
     372                        index = (index + 1 + rndUint(availTypesLength - 1)) % availTypesLength;
    377373                char newTypeChr = availTypes[index];
    378374
     
    385381#endif
    386382
    387                 if (ensureCircleSection)
    388                 {
    389                         geno.getState();
    390                         if (randomNode->partType == Part::Shape::SHAPE_CUBOID
    391                                 || (randomNode->partType == Part::Shape::SHAPE_CYLINDER && newType == Part::Shape::SHAPE_ELLIPSOID))
    392                         {
    393                                 double sizeMultiplier = randomNode->getParam(SIZE) * randomNode->state->s;
    394                                 double relativeVolume = randomNode->calculateVolume() / pow(sizeMultiplier, 3.0);
    395                                 double newRelativeRadius = Node::calculateRadiusFromVolume(newType, relativeVolume);
    396                                 randomNode->params[SIZE_X] = newRelativeRadius;
    397                                 randomNode->params[SIZE_Y] = newRelativeRadius;
    398                                 randomNode->params[SIZE_Z] = newRelativeRadius;
    399                         }
     383                geno.getState();
     384                double sizeMultiplier = randomNode->getParam(SIZE) * randomNode->state->s;
     385                double relativeVolume = randomNode->calculateVolume() / pow(sizeMultiplier, 3.0);
     386
     387                if(!ensureCircleSection || newType == Part::Shape::SHAPE_CUBOID || (randomNode->partType == Part::Shape::SHAPE_ELLIPSOID && newType == Part::Shape::SHAPE_CYLINDER))
     388                {
     389                        double radiusQuotient = std::cbrt(volumeMultipliers.at(randomNode->partType) / volumeMultipliers.at(newType));
     390                        randomNode->params[SIZE_X] = randomNode->getParam(SIZE_X) * radiusQuotient;
     391                        randomNode->params[SIZE_Y] = randomNode->getParam(SIZE_Y) * radiusQuotient;
     392                        randomNode->params[SIZE_Z] = randomNode->getParam(SIZE_Z) * radiusQuotient;
     393                }
     394                else if(randomNode->partType == Part::Shape::SHAPE_CUBOID && newType == Part::Shape::SHAPE_CYLINDER)
     395                {
     396                        double newRadius = 0.5 * (randomNode->getParam(SIZE_X) + randomNode->getParam(SIZE_Y));
     397                        randomNode->params[SIZE_X] = newRadius;
     398                        randomNode->params[SIZE_Y] = newRadius;
     399                        randomNode->params[SIZE_Z] = 0.5 * relativeVolume / (M_PI * newRadius * newRadius);
     400                }
     401                else if(newType == Part::Shape::SHAPE_ELLIPSOID)
     402                {
     403                        double newRelativeRadius = cbrt(relativeVolume / volumeMultipliers.at(newType));
     404                        randomNode->params[SIZE_X] = newRelativeRadius;
     405                        randomNode->params[SIZE_Y] = newRelativeRadius;
     406                        randomNode->params[SIZE_Z] = newRelativeRadius;
     407                }
     408                else
     409                {
     410                        throw fS_Exception("Invalid part type", 1);
    400411                }
    401412                randomNode->partType = newType;
     
    405416}
    406417
    407 bool GenoOper_fS::addJoint(fS_Genotype &geno)
     418bool GenoOper_fS::changeJoint(fS_Genotype &geno)
    408419{
    409420        if (geno.startNode->children.empty())
    410421                return false;
    411422
    412         Node *randomNode;
    413         for (int i = 0; i < mutationTries; i++)
    414         {
    415                 char randomJoint = JOINTS[rndUint(JOINT_COUNT)];
    416                 randomNode = geno.chooseNode(1);        // First part does not have joints
    417                 if (randomNode->joint == DEFAULT_JOINT)
    418                 {
    419                         randomNode->joint = randomJoint;
    420                         return true;
    421                 }
    422         }
    423         return false;
    424 }
    425 
    426 
    427 bool GenoOper_fS::removeJoint(fS_Genotype &geno)
    428 {
    429         // This operator may can lower success rate that others, as it does not work when there is only one node
    430         if (geno.startNode->children.size() < 1) // Only one node; there are no joints
    431                 return false;
    432 
    433         // Choose a node with joints
    434         for (int i = 0; i < mutationTries; i++)
    435         {
    436                 Node *randomNode = geno.chooseNode(1);    // First part does not have joints
    437                 if (randomNode->joint != DEFAULT_JOINT)
    438                 {
    439                         randomNode->joint = DEFAULT_JOINT;
    440                         return true;
    441                 }
    442         }
    443         return false;
     423        Node *randomNode = geno.chooseNode(1);        // First part does not have joints
     424        int jointLen  = ALL_JOINTS.length();
     425        int index = rndUint(jointLen);
     426        if (ALL_JOINTS[index] == randomNode->joint)
     427                index = (index + 1 + rndUint(jointLen - 1)) % jointLen;
     428
     429        randomNode->joint = ALL_JOINTS[index];
     430        return true;
    444431}
    445432
     
    450437        if (paramCount == int(PARAMS.size()))
    451438                return false;
    452         string selectedParam = PARAMS[rndUint(PARAMS.size())];
    453         // Not allow 'j' parameter when the cycle mode is not on
    454         if (selectedParam == JOINT_DISTANCE && !geno.startNode->cycleMode)
    455                 return false;
    456         if (randomNode->params.count(selectedParam) > 0)
     439        string key = PARAMS[rndUint(PARAMS.size())];
     440        if (randomNode->params.count(key) > 0)
    457441                return false;
    458442        // Do not allow invalid changes in part size
    459         bool isRadiusOfBase = selectedParam == SIZE_X || selectedParam == SIZE_Y;
    460         bool isRadius = isRadiusOfBase || selectedParam == SIZE_Z;
     443        bool isRadiusOfBase = key == SIZE_X || key == SIZE_Y;
     444        bool isRadius = isRadiusOfBase || key == SIZE_Z;
    461445        if (ensureCircleSection && isRadius)
    462446        {
     
    467451        }
    468452        // Add modified default value for param
    469         randomNode->params[selectedParam] = defaultParamValues.at(selectedParam);
     453        randomNode->params[key] = mutateCreep('f', defaultValues.at(key), minValues.at(key), maxValues.at(key), true);
    470454        return true;
    471455}
     
    501485                        advance(it, rndUint(paramCount));
    502486
    503                         double multiplier = fS_Genotype::randomParamMultiplier();
    504 
    505 
    506487                        // Do not allow invalid changes in part size
    507488                        if (it->first != SIZE_X && it->first != SIZE_Y && it->first != SIZE_Z)
    508489                        {
    509                                 it->second *= multiplier;
     490                                it->second = GenoOperators::mutateCreep('f', it->second, minValues.at(it->first), maxValues.at(it->first), true);
    510491                                return true;
    511492                        } else
    512                                 return randomNode->changeSizeParam(it->first, multiplier, ensureCircleSection);
     493                                return randomNode->changeSizeParam(it->first, ensureCircleSection);
    513494                }
    514495        }
     
    607588                        advance(it, rndUint(inputCount));
    608589
    609                         it->second = GenoOperators::getMutatedNeuroClassProperty(it->second, selectedNeuron, -1);
     590                        it->second = GenoOperators::getMutatedNeuronConnectionWeight(it->second);
    610591                        return true;
    611592                }
     
    673654
    674655        fS_Neuron *neu = neurons[rndUint(neurons.size())];
    675         SyntParam par = neu->classProperties();
    676 
    677         if (par.getPropCount() > 0)
    678         {
    679                 int i = rndUint(par.getPropCount());
    680                 if (*par.type(i) == 'f')
    681                 {
    682                         double change = GenoOperators::getMutatedNeuroClassProperty(par.getDouble(i), neu, GenoOperators::NEUROCLASS_PROP_OFFSET + i);
    683                         par.setDouble(i, change);
    684                 }
    685                 SString line;
    686                 int tmp = 0;
    687                 par.update(&line);
    688                 SString props;
    689                 line.getNextToken(tmp, props, '\n'); // removal of newline character
    690                 if (props != "")
    691                 {
    692                         SString det = neu->getClass()->name + ": " + props;
    693                         neu->setDetails(det);
    694                         return true;
    695                 }
    696         }
    697 
    698         return false;
    699 }
     656        return GenoOperators::mutateRandomNeuroClassProperty(neu);
     657}
Note: See TracChangeset for help on using the changeset viewer.